diff options
Diffstat (limited to 'logic')
| -rw-r--r-- | logic/CMakeLists.txt | 6 | ||||
| -rw-r--r-- | logic/extensions.cpp | 71 | ||||
| -rw-r--r-- | logic/extensions.hpp | 44 | ||||
| -rw-r--r-- | logic/lang/de_DE.ts | 64 | ||||
| -rw-r--r-- | logic/lang/nl_NL.ts | 51 | ||||
| -rw-r--r-- | logic/lang/ru_RU.ts | 51 | ||||
| -rw-r--r-- | logic/lang/stub.ts | 51 | ||||
| -rw-r--r-- | logic/lang/zh_CN.ts | 62 | ||||
| -rw-r--r-- | logic/main-settings.cpp | 70 | ||||
| -rw-r--r-- | logic/main-settings.hpp | 96 | ||||
| -rw-r--r-- | logic/mappings.hpp | 4 | ||||
| -rw-r--r-- | logic/pipeline.cpp | 519 | ||||
| -rw-r--r-- | logic/pipeline.hpp | 118 | ||||
| -rw-r--r-- | logic/runtime-libraries.cpp | 33 | ||||
| -rw-r--r-- | logic/runtime-libraries.hpp | 10 | ||||
| -rw-r--r-- | logic/shortcuts.cpp | 84 | ||||
| -rw-r--r-- | logic/shortcuts.h | 8 | ||||
| -rw-r--r-- | logic/state.cpp | 57 | ||||
| -rw-r--r-- | logic/state.hpp | 25 | ||||
| -rw-r--r-- | logic/tracklogger.cpp | 9 | ||||
| -rw-r--r-- | logic/tracklogger.hpp | 39 | ||||
| -rw-r--r-- | logic/win32-shortcuts.cpp | 81 | ||||
| -rw-r--r-- | logic/win32-shortcuts.h | 6 | ||||
| -rw-r--r-- | logic/work.cpp | 66 | ||||
| -rw-r--r-- | logic/work.hpp | 44 |
25 files changed, 965 insertions, 704 deletions
diff --git a/logic/CMakeLists.txt b/logic/CMakeLists.txt index f3f128af..f3344798 100644 --- a/logic/CMakeLists.txt +++ b/logic/CMakeLists.txt @@ -1,7 +1,7 @@ otr_module(logic BIN) -target_link_libraries(opentrack-logic opentrack-spline) +target_link_libraries(${self} opentrack-spline) if(NOT WIN32) - target_link_libraries(opentrack-logic opentrack-qxt-mini) + target_link_libraries(${self} opentrack-qxt-mini) else() - target_link_libraries(opentrack-logic opentrack-dinput winmm) + target_link_libraries(${self} opentrack-dinput winmm) endif() diff --git a/logic/extensions.cpp b/logic/extensions.cpp deleted file mode 100644 index 22eef6df..00000000 --- a/logic/extensions.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "extensions.hpp" - -#include <functional> - -using namespace options; - -using ext_fun_type = void(IExtension::*)(Pose&); -using ext_mask = IExtension::event_mask; -using ext_ord = IExtension::event_ordinal; - -static constexpr struct event_type_mapping -{ - ext_fun_type ptr; - ext_mask mask; - ext_ord idx; -} ordinal_to_function[] = { - { &IExtension::process_raw, ext_mask::on_raw, ext_ord::ev_raw, }, - { &IExtension::process_before_filter, ext_mask::on_before_filter, ext_ord::ev_before_filter, }, - { &IExtension::process_before_mapping, ext_mask::on_before_mapping, ext_ord::ev_before_mapping, }, - { &IExtension::process_finished, ext_mask::on_finished, ext_ord::ev_finished, }, -}; - -bool event_handler::is_enabled(const QString& name) -{ - (void)name; -#if 1 - return true; -#else - if (!ext_bundle->contains(name)) - return false; - - return ext_bundle->get<bool>(name); -#endif -} - -event_handler::event_handler(Modules::dylib_list const& extensions) : ext_bundle(make_bundle("extensions")) -{ - for (std::shared_ptr<dylib> const& lib : extensions) - { - std::shared_ptr<IExtension> ext(reinterpret_cast<IExtension*>(lib->Constructor())); - std::shared_ptr<IExtensionDialog> dlg(reinterpret_cast<IExtensionDialog*>(lib->Dialog())); - std::shared_ptr<Metadata> m(reinterpret_cast<Metadata*>(lib->Meta())); - - const ext_mask mask = ext->hook_types(); - - if (!is_enabled(lib->module_name)) - continue; - -#if 0 - qDebug() << "extension" << lib->module_name << "mask" << (void*)mask; -#endif - - for (event_type_mapping const& mapping : ordinal_to_function) - { - const unsigned i = mapping.idx; - const ext_mask mask_ = mapping.mask; - - if (mask & mask_) - extensions_for_event[i].push_back({ ext, dlg, m }); - } - } -} - -void event_handler::run_events(event_ordinal k, Pose& pose) -{ - auto fun = std::mem_fn(ordinal_to_function[k].ptr); - - for (extension& x : extensions_for_event[k]) - fun(*x.logic, pose); -} - diff --git a/logic/extensions.hpp b/logic/extensions.hpp deleted file mode 100644 index 4d6763b2..00000000 --- a/logic/extensions.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -/* Copyright (c) 2017 Stanislaw Halik - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - */ - -#include "api/plugin-support.hpp" -#include "options/options.hpp" - -#include <vector> -#include <array> - -#include "export.hpp" - -struct OTR_LOGIC_EXPORT event_handler final -{ - using event_ordinal = IExtension::event_ordinal; - - struct extension - { - using ext = std::shared_ptr<IExtension>; - using dlg = std::shared_ptr<IExtensionDialog>; - using m = std::shared_ptr<Metadata>; - - ext logic; - dlg dialog; - m metadata; - }; - - void run_events(event_ordinal k, Pose& pose); - event_handler(Modules::dylib_list const& extensions); - -private: - using ext_list = std::vector<extension>; - std::array<ext_list, IExtension::event_count> extensions_for_event; - - options::bundle ext_bundle; - - bool is_enabled(const QString& name); -}; - diff --git a/logic/lang/de_DE.ts b/logic/lang/de_DE.ts new file mode 100644 index 00000000..eca10616 --- /dev/null +++ b/logic/lang/de_DE.ts @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1" language="de_DE"> +<context> + <name>Work</name> + <message> + <source>Select filename</source> + <translation>Dateiname wählen</translation> + </message> + <message> + <source>CSV File (*.csv)</source> + <translation>CSV-Datei (*.csv)</translation> + </message> + <message> + <source>Logging error</source> + <translation>Protokollierungsfehler</translation> + </message> + <message> + <source>Unable to open file '%1'. Proceeding without logging.</source> + <translation>Datei '%1' kann nicht geöffnet werden. Es wird ohne Protokollierung fortgefahren.</translation> + </message> +</context> +<context> + <name>runtime_libraries</name> + <message> + <source>Library load failure</source> + <translation>Fehler beim Laden der Bibliothek</translation> + </message> + <message> + <source>Error occurred while loading protocol %1 + +%2 +</source> + <translation>Ein Fehler trat auf beim Laden des Protokolls %1 + +%2 +</translation> + </message> + <message> + <source>Error occurred while loading filter %1 + +%2 +</source> + <translation>Fehler beim Laden des Filters %1 + +%2 +</translation> + </message> + <message> + <source>Error occurred while loading tracker %1 + +%2 +</source> + <translation>Fehler beim Laden des Trackers %1 + +%2 +</translation> + </message> + <message> + <source>Startup failure</source> + <translation>Ausführungsfehler</translation> + </message> +</context> +</TS> diff --git a/logic/lang/nl_NL.ts b/logic/lang/nl_NL.ts index 9e739505..85b50bd8 100644 --- a/logic/lang/nl_NL.ts +++ b/logic/lang/nl_NL.ts @@ -1,4 +1,55 @@ <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> <TS version="2.1" language="nl_NL"> +<context> + <name>Work</name> + <message> + <source>Select filename</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>CSV File (*.csv)</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Logging error</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unable to open file '%1'. Proceeding without logging.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>runtime_libraries</name> + <message> + <source>Library load failure</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Error occurred while loading protocol %1 + +%2 +</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Error occurred while loading filter %1 + +%2 +</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Error occurred while loading tracker %1 + +%2 +</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Startup failure</source> + <translation type="unfinished"></translation> + </message> +</context> </TS> diff --git a/logic/lang/ru_RU.ts b/logic/lang/ru_RU.ts index f62cf2e1..7772438c 100644 --- a/logic/lang/ru_RU.ts +++ b/logic/lang/ru_RU.ts @@ -1,4 +1,55 @@ <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> <TS version="2.1" language="ru_RU"> +<context> + <name>Work</name> + <message> + <source>Select filename</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>CSV File (*.csv)</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Logging error</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unable to open file '%1'. Proceeding without logging.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>runtime_libraries</name> + <message> + <source>Library load failure</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Error occurred while loading protocol %1 + +%2 +</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Error occurred while loading filter %1 + +%2 +</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Error occurred while loading tracker %1 + +%2 +</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Startup failure</source> + <translation type="unfinished"></translation> + </message> +</context> </TS> diff --git a/logic/lang/stub.ts b/logic/lang/stub.ts index 6401616d..cc15f98a 100644 --- a/logic/lang/stub.ts +++ b/logic/lang/stub.ts @@ -1,4 +1,55 @@ <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> <TS version="2.1"> +<context> + <name>Work</name> + <message> + <source>Select filename</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>CSV File (*.csv)</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Logging error</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unable to open file '%1'. Proceeding without logging.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>runtime_libraries</name> + <message> + <source>Library load failure</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Error occurred while loading protocol %1 + +%2 +</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Error occurred while loading filter %1 + +%2 +</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Error occurred while loading tracker %1 + +%2 +</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Startup failure</source> + <translation type="unfinished"></translation> + </message> +</context> </TS> diff --git a/logic/lang/zh_CN.ts b/logic/lang/zh_CN.ts index 6401616d..000aff7c 100644 --- a/logic/lang/zh_CN.ts +++ b/logic/lang/zh_CN.ts @@ -1,4 +1,64 @@ <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> -<TS version="2.1"> +<TS version="2.1" language="zh_CN"> +<context> + <name>Work</name> + <message> + <source>Select filename</source> + <translation>选择文件名</translation> + </message> + <message> + <source>CSV File (*.csv)</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Logging error</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unable to open file '%1'. Proceeding without logging.</source> + <translation type="unfinished">未能打开文件 '%1'. Proceeding without logging.</translation> + </message> +</context> +<context> + <name>runtime_libraries</name> + <message> + <source>Library load failure</source> + <translation>库加载失败</translation> + </message> + <message> + <source>Error occurred while loading protocol %1 + +%2 +</source> + <translation type="unfinished">加载协议 %1 时发生错误 + +%2 +</translation> + </message> + <message> + <source>Error occurred while loading filter %1 + +%2 +</source> + <translation type="unfinished">加载滤波器 %1 时发生错误 + +%2 +</translation> + </message> + <message> + <source>Error occurred while loading tracker %1 + +%2 +</source> + <translation type="unfinished">加载跟踪器 %1 时发生错误 + +%2 +</translation> + </message> + <message> + <source>Startup failure</source> + <translation type="unfinished"></translation> + </message> +</context> </TS> diff --git a/logic/main-settings.cpp b/logic/main-settings.cpp index c735ac6e..3865e602 100644 --- a/logic/main-settings.cpp +++ b/logic/main-settings.cpp @@ -1,62 +1,28 @@ #include "main-settings.hpp" -using namespace options; +namespace main_settings_impl { -main_settings::main_settings() : - b(make_bundle("opentrack-ui")), - b_map(make_bundle("opentrack-mappings")), - a_x("x", TX), - a_y("y", TY), - a_z("z", TZ), - a_yaw("yaw", Yaw), - a_pitch("pitch", Pitch), - a_roll("roll", Roll), - all_axis_opts { &a_x, &a_y, &a_z, &a_yaw, &a_pitch, &a_roll }, - reltrans_disable_tx(b, "compensate-translation-disable-x-axis", false), - reltrans_disable_ty(b, "compensate-translation-disable-y-axis", false), - reltrans_disable_tz(b, "compensate-translation-disable-z-axis", false), - reltrans_disable_src_yaw(b, "compensate-translation-disable-source-yaw", false), - reltrans_disable_src_pitch(b, "compensate-translation-disable-source-pitch", false), - reltrans_disable_src_roll(b, "compensate-translation-disable-source-roll", false), - tray_enabled(b, "use-system-tray", false), - tray_start(b, "start-in-tray", false), - center_at_startup(b, "center-at-startup", true), - //center_method(b, "centering-method", 1), - neck_z(b, "neck-depth", 0), - neck_enable(b, "neck-enable", false), - key_start_tracking1(b, "start-tracking"), - key_start_tracking2(b, "start-tracking-alt"), - key_stop_tracking1(b, "stop-tracking"), - key_stop_tracking2(b, "stop-tracking-alt"), - key_toggle_tracking1(b, "toggle-tracking"), - key_toggle_tracking2(b, "toggle-tracking-alt"), - key_restart_tracking1(b, "restart-tracking"), - key_restart_tracking2(b, "restart-tracking-alt"), - key_center1(b, "center"), - key_center2(b, "center-alt"), - key_toggle1(b, "toggle"), - key_toggle2(b, "toggle-alt"), - key_zero1(b, "zero"), - key_zero2(b, "zero-alt"), - key_toggle_press1(b, "toggle-press"), - key_toggle_press2(b, "toggle-press-alt"), - key_zero_press1(b, "zero-press"), - key_zero_press2(b, "zero-press-alt"), - tracklogging_enabled(b, "tracklogging-enabled", false), - tracklogging_filename(b, "tracklogging-filename", QString()) -{ -} +using namespace options; -module_settings::module_settings() : - b(make_bundle("modules")), - tracker_dll(b, "tracker-dll", "PointTracker 1.1"), - filter_dll(b, "filter-dll", "Accela"), - protocol_dll(b, "protocol-dll", "freetrack 2.0 Enhanced") -{ -} +main_settings::main_settings() = default; +module_settings::module_settings() = default; key_opts::key_opts(bundle b, const QString& name) : keycode(b, QString("keycode-%1").arg(name), ""), guid(b, QString("guid-%1").arg(name), ""), button(b, QString("button-%1").arg(name), -1) {} + +key_opts& key_opts::operator=(const key_opts& x) +{ + if (&x != this) + { + keycode = x.keycode; + guid = x.guid; + button = x.button; + } + + return *this; +} + +} // ns main_settings_impl diff --git a/logic/main-settings.hpp b/logic/main-settings.hpp index df86f856..fcd5e745 100644 --- a/logic/main-settings.hpp +++ b/logic/main-settings.hpp @@ -15,13 +15,21 @@ #include "export.hpp" -enum reltrans_state +enum reltrans_state : int { reltrans_disabled = 0, reltrans_enabled = 1, reltrans_non_center = 2, }; +enum centering_state : int +{ + center_disabled = 0, + center_point = 1, + center_vr360 = 2, + center_roll_compensated = 3, +}; + namespace main_settings_impl { using namespace options; @@ -32,46 +40,78 @@ struct OTR_LOGIC_EXPORT key_opts value<int> button; key_opts(bundle b, const QString& name); + key_opts& operator=(const key_opts& x); }; struct OTR_LOGIC_EXPORT module_settings { - bundle b; - value<QString> tracker_dll, filter_dll, protocol_dll; + bundle b { make_bundle("modules") }; + value<QString> tracker_dll { b, "tracker-dll", "pt" }; + value<QString> filter_dll { b, "filter-dll", "accela" }; + value<QString> protocol_dll { b, "protocol-dll", "freetrack" }; module_settings(); }; struct OTR_LOGIC_EXPORT main_settings final { - bundle b, b_map; - axis_opts a_x, a_y, a_z; - axis_opts a_yaw, a_pitch, a_roll; - axis_opts* all_axis_opts[6]; + bundle b { make_bundle("opentrack-ui") }; + bundle b_map { make_bundle("opentrack-mappings") }; + axis_opts a_x{ "x", TX }, a_y { "y", TY }, a_z { "z", TZ }; + axis_opts a_yaw{ "yaw", Yaw }, a_pitch { "pitch", Pitch }, a_roll { "roll", Roll }; + axis_opts* all_axis_opts[6] { &a_x, &a_y, &a_z, &a_yaw, &a_pitch, &a_roll }; value<reltrans_state> reltrans_mode { b, "relative-translation-mode", reltrans_disabled }; - value<bool> reltrans_disable_tx, reltrans_disable_ty, reltrans_disable_tz; - value<bool> reltrans_disable_src_yaw, reltrans_disable_src_pitch, reltrans_disable_src_roll; - value<bool> tray_enabled, tray_start; - value<bool> center_at_startup; - //value<int> center_method; - value<int> neck_z; - value<bool> neck_enable; - key_opts key_start_tracking1, key_start_tracking2; - key_opts key_stop_tracking1, key_stop_tracking2; - key_opts key_toggle_tracking1, key_toggle_tracking2; - key_opts key_restart_tracking1, key_restart_tracking2; - key_opts key_center1, key_center2; - key_opts key_toggle1, key_toggle2; - key_opts key_zero1, key_zero2; - key_opts key_toggle_press1, key_toggle_press2; - key_opts key_zero_press1, key_zero_press2; - value<bool> tracklogging_enabled; - value<QString> tracklogging_filename; + + value<bool> reltrans_disable_tx { b, "compensate-translation-disable-x-axis", false }; + value<bool> reltrans_disable_ty { b, "compensate-translation-disable-y-axis", false }; + value<bool> reltrans_disable_tz { b, "compensate-translation-disable-z-axis", false }; + + value<bool> reltrans_disable_src_yaw { b, "compensate-translation-disable-source-yaw", false }; + value<bool> reltrans_disable_src_pitch { b, "compensate-translation-disable-source-pitch", false }; + value<bool> reltrans_disable_src_roll { b, "compensate-translation-disable-source-roll", false }; + + value<bool> tray_enabled { b, "use-system-tray", false }; + value<bool> tray_start { b, "start-in-tray", false }; + + value<bool> center_at_startup { b, "center-at-startup", true }; + value<centering_state> centering_mode { b, "centering-mode", center_roll_compensated }; + value<int> neck_z { b, "neck-depth", 0 }; + value<bool> neck_enable { b, "neck-enable", false }; + + key_opts key_start_tracking1 { b, "start-tracking" }; + key_opts key_start_tracking2 { b, "start-tracking-alt" }; + + key_opts key_stop_tracking1 { b, "stop-tracking" }; + key_opts key_stop_tracking2 { b, "stop-tracking-alt" }; + + key_opts key_toggle_tracking1 { b, "toggle-tracking" }; + key_opts key_toggle_tracking2 { b, "toggle-tracking-alt" }; + + key_opts key_restart_tracking1 { b, "restart-tracking" }; + key_opts key_restart_tracking2 { b, "restart-tracking-alt" }; + + key_opts key_center1 { b, "center" }; + key_opts key_center2 { b, "center-alt" }; + + key_opts key_toggle1 { b, "toggle" }; + key_opts key_toggle2 { b, "toggle-alt" }; + + key_opts key_zero1 { b, "zero" }; + key_opts key_zero2 { b, "zero-alt" }; + + key_opts key_toggle_press1 { b, "toggle-press" }; + key_opts key_toggle_press2 { b, "toggle-press-alt" }; + + key_opts key_zero_press1 { b, "zero-press" }; + key_opts key_zero_press2 { b, "zero-press-alt" }; + + value<bool> tracklogging_enabled { b, "tracklogging-enabled", false }; + value<QString> tracklogging_filename { b, "tracklogging-filename", {} }; main_settings(); }; } // ns main_settings_impl -using main_settings_impl::key_opts; -using main_settings_impl::module_settings; -using main_settings_impl::main_settings; +using key_opts = main_settings_impl::key_opts; +using module_settings = main_settings_impl::module_settings; +using main_settings = main_settings_impl::main_settings; diff --git a/logic/mappings.hpp b/logic/mappings.hpp index f88e6820..be7dd3a2 100644 --- a/logic/mappings.hpp +++ b/logic/mappings.hpp @@ -29,12 +29,10 @@ class OTR_LOGIC_EXPORT Mappings final private: Map axes[6]; public: - Mappings(axis_opts** opts); + explicit Mappings(axis_opts** opts); Map& operator()(int i) { return axes[i]; } const Map& operator()(int i) const { return axes[i]; } - Map& operator()(unsigned i) { return axes[i]; } - const Map& operator()(unsigned i) const { return axes[i]; } template<typename f> void forall(f&& fun) { diff --git a/logic/pipeline.cpp b/logic/pipeline.cpp index 7774b02e..2e8efe55 100644 --- a/logic/pipeline.cpp +++ b/logic/pipeline.cpp @@ -15,7 +15,8 @@ #include "compat/sleep.hpp" #include "compat/math.hpp" #include "compat/meta.hpp" -#include "compat/macros.hpp" +#include "compat/macros.h" +#include "compat/thread-name.hpp" #include "pipeline.hpp" #include "logic/shortcuts.h" @@ -26,26 +27,34 @@ #ifdef _WIN32 # include <windows.h> +# include <mmsystem.h> #endif -using namespace euler; -using namespace time_units; -using namespace gui_tracker_impl; +//#define DEBUG_TIMINGS +#ifdef DEBUG_TIMINGS +# include "compat/variance.hpp" +#endif + +namespace pipeline_impl { -static constexpr inline double r2d = 180. / M_PI; -static constexpr inline double d2r = M_PI / 180.; +reltrans::reltrans() = default; -reltrans::reltrans() {} +void reltrans::on_center() +{ + interp_pos = { 0, 0, 0 }; + in_zone = false; + moving_to_reltans = false; +} -euler_t reltrans::rotate(const rmat& R, const euler_t& in, vec3_bool disable) const +Pose_ reltrans::rotate(const rmat& R, const Pose_& in, vec3_bool disable) const { enum { tb_Z, tb_X, tb_Y }; // TY is really yaw axis. need swapping accordingly. // sign changes are due to right-vs-left handedness of coordinate system used - const euler_t ret = R * euler_t(in(TZ), -in(TX), -in(TY)); + const Pose_ ret = R * Pose_(in(TZ), -in(TX), -in(TY)); - euler_t output; + Pose_ output; if (disable(TZ)) output(TZ) = in(TZ); @@ -68,104 +77,92 @@ euler_t reltrans::rotate(const rmat& R, const euler_t& in, vec3_bool disable) co Pose reltrans::apply_pipeline(reltrans_state state, const Pose& value, const vec6_bool& disable, bool neck_enable, int neck_z) { - euler_t rel(static_cast<const double*>(value)); + Pose_ rel((const double*)value); if (state != reltrans_disabled) { + bool in_zone_ = true; + if (state == reltrans_non_center) { - bool tcomp_in_zone_ = progn( - if (state == reltrans_non_center) - { - const bool look_up = value(Pitch) < 15; - return look_up ? std::fabs(value(Yaw)) > 85 : std::fabs(value(Yaw)) < 50; - } - else - return true; - ); - - if (!cur && in_zone != tcomp_in_zone_) - { - //qDebug() << "reltrans-interp: START" << tcomp_in_zone_; - cur = true; - interp_timer.start(); - interp_phase_timer.start(); - RC_phase = 0; - } + const bool looking_down = value(Pitch) < 20; + in_zone_ = looking_down ? std::fabs(value(Yaw)) > 35 : std::fabs(value(Yaw)) > 65; + } - in_zone = tcomp_in_zone_; + if (!moving_to_reltans && in_zone != in_zone_) + { + //qDebug() << "reltrans-interp: START" << tcomp_in_zone_; + moving_to_reltans = true; + interp_timer.start(); + interp_phase_timer.start(); + RC_stage = 0; } + in_zone = in_zone_; + // only when looking behind or downward if (in_zone) { - const rmat R = euler_to_rmat(euler_t(value(Yaw) * d2r * !disable(Yaw), - value(Pitch) * d2r * !disable(Pitch), - value(Roll) * d2r * !disable(Roll))); + constexpr double d2r = M_PI / 180; + + const rmat R = euler_to_rmat( + Pose_(value(Yaw) * d2r * !disable(Yaw), + value(Pitch) * d2r * !disable(Pitch), + value(Roll) * d2r * !disable(Roll))); rel = rotate(R, rel, &disable[TX]); // dynamic neck - if (neck_enable) + if (neck_enable && (state != reltrans_non_center || !in_zone)) { - const euler_t neck = apply_neck(value, -neck_z); + const Pose_ neck = apply_neck(R, -neck_z, disable(TZ)); for (unsigned k = 0; k < 3; k++) rel(k) += neck(k); } } - if (cur) + if (moving_to_reltans) { - static constexpr double RC_phases[] = { 2, 1, .5, .1, }; - static constexpr double RC_time_deltas[] = { 1, .25, 25., }; - const double dt = interp_timer.elapsed_seconds(); + + static constexpr double RC_stages[] = { 2, 1, .5, .1, .05 }; + static constexpr double RC_time_deltas[] = { 1, .25, .25, 2 }; + interp_timer.start(); - if (RC_phase + 1 != std::size(RC_phases) && - interp_phase_timer.elapsed_seconds() > RC_time_deltas[RC_phase]) + if (RC_stage + 1 < std::size(RC_stages) && + interp_phase_timer.elapsed_seconds() > RC_time_deltas[RC_stage]) { - RC_phase++; + RC_stage++; interp_phase_timer.start(); } - const double RC = RC_phases[RC_phase]; + const double RC = RC_stages[RC_stage]; const double alpha = dt/(dt+RC); - constexpr double eps = .05; + constexpr double eps = .01; interp_pos = interp_pos * (1-alpha) + rel * alpha; - const euler_t tmp = rel - interp_pos; + const Pose_ tmp = rel - interp_pos; rel = interp_pos; - const double delta = std::fabs(tmp(0)) + std::fabs(tmp(0)) + std::fabs(tmp(0)); + const double delta = std::fabs(tmp(0)) + std::fabs(tmp(1)) + std::fabs(tmp(2)); - //qDebug() << "reltrans-interp: delta" << delta; + //qDebug() << "reltrans-interp: delta" << delta << "phase" << RC_phase; if (delta < eps) { //qDebug() << "reltrans-interp: STOP"; - cur = false; + moving_to_reltans = false; } } else - { interp_pos = rel; - } } else { - cur = false; + moving_to_reltans = false; in_zone = false; - - // dynamic neck - if (neck_enable) - { - const euler_t neck = apply_neck(value, -neck_z); - - for (unsigned k = 0; k < 3; k++) - rel(k) += neck(k); - } } return { @@ -174,22 +171,21 @@ Pose reltrans::apply_pipeline(reltrans_state state, const Pose& value, }; } -euler_t reltrans::apply_neck(const Pose& value, int nz) const +Pose_ reltrans::apply_neck(const rmat& R, int nz, bool disable_tz) const { - euler_t neck; + Pose_ neck; - const rmat R = euler_to_rmat(euler_t(&value[Yaw]) * d2r); - neck = rotate(R, { 0, 0, nz }, vec3_bool()); + neck = rotate(R, { 0, 0, nz }, {}); neck(TZ) = neck(TZ) - nz; + if (disable_tz) + neck(TZ) = 0; + return neck; } -pipeline::pipeline(Mappings& m, runtime_libraries& libs, event_handler& ev, TrackLogger& logger) : - m(m), - ev(ev), - libs(libs), - logger(logger) +pipeline::pipeline(const Mappings& m, const runtime_libraries& libs, TrackLogger& logger) : + m(m), libs(libs), logger(logger) { } @@ -199,20 +195,20 @@ pipeline::~pipeline() wait(); } -double pipeline::map(double pos, Map& axis) +double pipeline::map(double pos, const Map& axis) { bool altp = (pos < 0) && axis.opts.altp; - axis.spline_main.set_tracking_active( !altp ); - axis.spline_alt.set_tracking_active( altp ); + axis.spline_main.set_tracking_active(!altp); + axis.spline_alt.set_tracking_active(altp); auto& fc = altp ? axis.spline_alt : axis.spline_main; - return double(fc.get_value(pos)); + return fc.get_value(pos); } template<int u, int w> -static bool is_nan(const dmat<u,w>& r) +static inline bool is_nan(const dmat<u,w>& r) { - for (int i = 0; i < u; i++) - for (int j = 0; j < w; j++) + for (unsigned i = 0; i < u; i++) + for (unsigned j = 0; j < w; j++) { int val = std::fpclassify(r(i, j)); if (val == FP_NAN || val == FP_INFINITE) @@ -222,29 +218,14 @@ static bool is_nan(const dmat<u,w>& r) return false; } -template<typename x, typename y, typename... xs> -static force_inline bool nan_check_(const x& datum, const y& next, const xs&... rest) -{ - return is_nan(datum) || nan_check_(next, rest...); -} - -template<typename x> -static force_inline bool nan_check_(const x& datum) -{ - return is_nan(datum); -} - -template<typename> -static bool nan_check_() = delete; - static never_inline void emit_nan_check_msg(const char* text, const char* fun, int line) { - once_only( + eval_once( qDebug() << "nan check failed" << "for:" << text << "function:" << fun - << "line:" << line; + << "line:" << line ); } @@ -252,24 +233,23 @@ template<typename... xs> static never_inline bool maybe_nan(const char* text, const char* fun, int line, const xs&... vals) { - if (nan_check_(vals...)) - { + bool ret = (is_nan(vals) || ... || false); + + if (ret) emit_nan_check_msg(text, fun, line); - return true; - } - return false; -} -// for MSVC `else' is like `unlikely' for GNU + return ret; +} -#define nan_check(...) \ - do \ - { \ - if (likely(!maybe_nan(#__VA_ARGS__, OTR_FUNNAME, __LINE__, __VA_ARGS__))) \ - (void)0; \ - else \ - goto error; \ - } while (false) +#define nan_check(...) \ + do \ + { \ + if (likely(!maybe_nan(#__VA_ARGS__, function_name, __LINE__, __VA_ARGS__))) \ + (void)0; \ + else \ + goto error; \ + } \ + while (false) bool pipeline::maybe_enable_center_on_tracking_started() { @@ -284,7 +264,7 @@ bool pipeline::maybe_enable_center_on_tracking_started() if (tracking_started && s.center_at_startup) { - set(f_center, true); + set_center(true); return true; } } @@ -292,84 +272,91 @@ bool pipeline::maybe_enable_center_on_tracking_started() return false; } -void pipeline::maybe_set_center_pose(const Pose& value, bool own_center_logic) +void pipeline::maybe_set_center_pose(const centering_state mode, const Pose& value, bool own_center_logic) { - euler_t tmp = d2r * euler_t(&value[Yaw]); - //scaled_rotation.rotation = euler_to_rmat(c_div * tmp); - rotation.rotation = euler_to_rmat(tmp); - - if (get(f_center)) + if (b.get(f_center | f_held_center)) { + set_center(false); + if (libs.pFilter) libs.pFilter->center(); if (own_center_logic) { - //scaled_rotation.rot_center = rmat::eye(); - rotation.inv_rot_center = rmat::eye(); - - t_center = euler_t(); + center.P = {}; + center.QC = QQuaternion(1,0,0,0); + center.QR = QQuaternion(1,0,0,0); } else { - rotation.inv_rot_center = rotation.rotation.t(); - //scaled_rotation.rot_center = scaled_rotation.rotation.t(); - - t_center = euler_t(static_cast<const double*>(value)); + if (mode) + { + center.P = value; + center.QC = QQuaternion::fromEulerAngles(value[Pitch], value[Yaw], -value[Roll]).conjugated(); + center.QR = QQuaternion::fromEulerAngles(value[Pitch], value[Yaw], 0).conjugated(); + } + else + { + // To reset the centering coordinates + // just select "Centering method [Disabled]" and then press [Center] button + center.P = {}; + center.QC = QQuaternion(1,0,0,0); + center.QR = QQuaternion(1,0,0,0); + } } } } -Pose pipeline::clamp_value(Pose value) const +Pose pipeline::apply_center(const centering_state mode, Pose value) const { - // hatire, udp, and freepie trackers can mess up here - for (unsigned i = 3; i < 6; i++) - { - using std::fmod; - using std::copysign; - using std::fabs; + if (mode != center_disabled) + { + for (unsigned k = TX; k <= TZ; k++) + value(k) -= center.P(k); - value(i) = fmod(value(i), 360); + QQuaternion q; + QVector3D v; - const double x = value(i); - if (fabs(x) - 1e-2 > 180) - value(i) = fmod(x + copysign(180, x), 360) - copysign(180, x); - else - value(i) = clamp(x, -180, 180); + switch (mode) + { + case center_point: + for (unsigned k = Yaw; k <= Roll; k++) + { + value(k) -= center.P(k); + if (fabs(value[k]) > 180) value[k] -= copysign(360, value[k]); + } + break; + case center_vr360: + q = QQuaternion::fromEulerAngles(value[Pitch], value[Yaw], -value[Roll]); + q = center.QC * q; + v = q.toEulerAngles(); + value[Pitch] = v.x(); + value[Yaw] = v.y(); + value[Roll] = -v.z(); + break; + case center_roll_compensated: + q = QQuaternion::fromEulerAngles(value[Pitch], value[Yaw], center.P[Roll] - value[Roll]); + q = center.QR * q; + v = q.toEulerAngles(); + value[Pitch] = v.x(); + value[Yaw] = v.y(); + value[Roll] = -v.z(); + break; + case center_disabled: break; + } } - return value; -} - -Pose pipeline::apply_center(Pose value) const -{ - euler_t T = euler_t(value) - t_center; - euler_t R = r2d * rmat_to_euler(rotation.rotation * rotation.inv_rot_center); - - T = rel.rotate(rotation.inv_rot_center, T, vec3_bool()); - - for (int i = 0; i < 3; i++) - { + for (int i = 0; i < 6; i++) // don't invert after reltrans // inverting here doesn't break centering - - if (m(i+3).opts.invert) - R(i) = -R(i); - if (m(i).opts.invert) - T(i) = -T(i); - } - - for (int i = 0; i < 3; i++) - { - value(i) = T(i); - value(i+3) = R(i); - } + if (m(i).opts.invert_pre) + value(i) = -value(i); return value; } std::tuple<Pose, Pose, vec6_bool> -pipeline::get_selected_axis_value(const Pose& newpose) const +pipeline::get_selected_axis_values(const Pose& newpose) const { Pose value; vec6_bool disabled; @@ -403,22 +390,24 @@ Pose pipeline::maybe_apply_filter(const Pose& value) const Pose pipeline::apply_zero_pos(Pose value) const { - // custom zero position for (int i = 0; i < 6; i++) - value(i) += m(i).opts.zero * (m(i).opts.invert ? -1 : 1); + value(i) += m(i).opts.zero * (m(i).opts.invert_pre ? -1 : 1); return value; } -Pose pipeline::apply_reltrans(Pose value, vec6_bool disabled) +Pose pipeline::apply_reltrans(Pose value, vec6_bool disabled, bool centerp) { + if (centerp) + rel.on_center(); + value = rel.apply_pipeline(s.reltrans_mode, value, - { !!s.reltrans_disable_src_yaw, - !!s.reltrans_disable_src_pitch, - !!s.reltrans_disable_src_roll, - !!s.reltrans_disable_tx, + { !!s.reltrans_disable_tx, !!s.reltrans_disable_ty, - !!s.reltrans_disable_tz }, + !!s.reltrans_disable_tz, + !!s.reltrans_disable_src_yaw, + !!s.reltrans_disable_src_pitch, + !!s.reltrans_disable_src_roll, }, s.neck_enable, s.neck_z); @@ -433,57 +422,53 @@ Pose pipeline::apply_reltrans(Pose value, vec6_bool disabled) void pipeline::logic() { using namespace euler; - using EV = event_handler::event_ordinal; logger.write_dt(); logger.reset_dt(); // we must center prior to getting data from the tracker - const bool center_ordered = get(f_center) && tracking_started; + const bool center_ordered = b.get(f_center | f_held_center) && tracking_started; const bool own_center_logic = center_ordered && libs.pTracker->center(); - - Pose value, raw; - vec6_bool disabled; + const bool hold_ordered = b.get(f_enabled_p) ^ b.get(f_enabled_h); { Pose tmp; libs.pTracker->data(tmp); - nan_check(tmp); - ev.run_events(EV::ev_raw, tmp); - - if (get(f_enabled_p) ^ !get(f_enabled_h)) - for (int i = 0; i < 6; i++) - newpose(i) = tmp(i); + newpose = tmp; } - std::tie(raw, value, disabled) = get_selected_axis_value(newpose); + auto [raw, value, disabled] = get_selected_axis_values(newpose); logger.write_pose(raw); // raw - value = clamp_value(value); + nan_check(newpose, raw, value); { maybe_enable_center_on_tracking_started(); - maybe_set_center_pose(value, own_center_logic); - value = apply_center(value); + maybe_set_center_pose(s.centering_mode, value, own_center_logic); + value = apply_center(s.centering_mode, value); + // "corrected" - after various transformations to account for camera position logger.write_pose(value); } { - ev.run_events(EV::ev_before_filter, value); - value = maybe_apply_filter(value); + // we must proceed with all the filtering since the filter + // needs fresh values to prevent deconvergence + if (center_ordered) + (void)maybe_apply_filter(value); + else + value = maybe_apply_filter(value); nan_check(value); logger.write_pose(value); // "filtered" } { - ev.run_events(EV::ev_before_mapping, value); - // CAVEAT rotation only, due to tcomp + // CAVEAT rotation only, due to reltrans for (int i = 3; i < 6; i++) value(i) = map(value(i), m(i)); } - value = apply_reltrans(value, disabled); + value = apply_reltrans(value, disabled, center_ordered); { // CAVEAT translation only, due to tcomp @@ -498,7 +483,7 @@ error: { QMutexLocker foo(&mtx); - value = output_pose; + value = last_value; raw = raw_6dof; // for widget last value display @@ -508,16 +493,22 @@ error: ok: - set(f_center, false); + set_center(false); - if (get(f_zero)) + if (b.get(f_zero)) for (int i = 0; i < 6; i++) value(i) = 0; + if (hold_ordered) + value = last_value; + last_value = value; value = apply_zero_pos(value); - ev.run_events(EV::ev_finished, value); - libs.pProtocol->pose(value); + for (int i = 0; i < 6; i++) + if (m(i).opts.invert_post) + value(i) = -value(i); + + libs.pProtocol->pose(value, raw); QMutexLocker foo(&mtx); output_pose = value; @@ -529,21 +520,63 @@ ok: logger.next_line(); } +#ifdef DEBUG_TIMINGS +static void debug_timings(float backlog_time, int sleep_time) +{ + static variance v, v2; + static Timer t, t2; + static unsigned cnt, k; + + if (k > 1000) + { + v.input((double)backlog_time); + v2.input(sleep_time); + + if (t.elapsed_ms() >= 1000) + { + t.start(); + qDebug() << cnt << "Hz:" + << "backlog" + << "avg" << v.avg() + << "dev" << v.stddev() + << "| sleep" << v2.avg() + << "dev" << v2.stddev(); + + cnt = 0; + } + + cnt++; + } + else + { + k++; + t.start(); + } + + t2.start(); +} +#endif + void pipeline::run() { + portable::set_curthread_name("tracking pipeline"); + #if defined _WIN32 const MMRESULT mmres = timeBeginPeriod(1); #endif + setPriority(QThread::HighPriority); + setPriority(QThread::HighestPriority); + { static const char* const posechannels[6] = { "TX", "TY", "TZ", "Yaw", "Pitch", "Roll" }; static const char* const datachannels[5] = { "dt", "raw", "corrected", "filtered", "mapped" }; logger.write(datachannels[0]); - char buffer[128]; - for (unsigned j = 1; j < 5; ++j) + char buffer[16]; + for (unsigned j = 1; j < 5; ++j) // NOLINT(modernize-loop-convert) { - for (unsigned i = 0; i < 6; ++i) + for (unsigned i = 0; i < 6; ++i) // NOLINT(modernize-loop-convert) { std::sprintf(buffer, "%s%s", datachannels[j], posechannels[i]); logger.write(buffer); @@ -560,33 +593,28 @@ void pipeline::run() { logic(); - constexpr ns const_sleep_ms(time_cast<ns>(ms(4))); - const ns elapsed_nsecs = prog1(t.elapsed<ns>(), t.start()); + constexpr ms interval{4}; + backlog_time += ms{t.elapsed_ms()} - interval; + t.start(); - if (backlog_time > secs_(3) || backlog_time < secs_(-3)) + if (std::chrono::abs(backlog_time) > secs(3)) { qDebug() << "tracker: backlog interval overflow" - << time_cast<ms>(backlog_time).count() << "ms"; - backlog_time = backlog_time.zero(); + << ms{backlog_time}.count() << "ms"; + backlog_time = {}; } - backlog_time += ns(elapsed_nsecs - const_sleep_ms); - - const int sleep_time_ms = time_cast<ms>(clamp(const_sleep_ms - backlog_time, - ms::zero(), ms(10))).count(); + const int sleep_ms = (int)std::clamp(interval - backlog_time, ms{0}, ms{10}).count(); -#if 0 - qDebug() << "sleepy time" << sleep_time_ms - << "elapsed" << time_cast<ms>(elapsed_nsecs).count() - << "backlog" << time_cast<ms>(backlog_time).count(); +#ifdef DEBUG_TIMINGS + debug_timings(backlog_time.count(), sleep_ms); #endif - - portable::sleep(sleep_time_ms); + portable::sleep(sleep_ms); } // filter may inhibit exact origin Pose p; - libs.pProtocol->pose(p); + libs.pProtocol->pose(p, p); for (int i = 0; i < 6; i++) { @@ -602,7 +630,7 @@ void pipeline::run() void pipeline::raw_and_mapped_pose(double* mapped, double* raw) const { - QMutexLocker foo(&const_cast<pipeline&>(*this).mtx); + QMutexLocker foo(&mtx); for (int i = 0; i < 6; i++) { @@ -611,55 +639,52 @@ void pipeline::raw_and_mapped_pose(double* mapped, double* raw) const } } -void pipeline::set_center() { set(f_center, true); } +void pipeline::set_center(bool x) { b.set(f_center, x); } -void pipeline::set_enabled(bool value) { set(f_enabled_h, value); } -void pipeline::set_zero(bool value) { set(f_zero, value); } +void pipeline::set_held_center(bool value) +{ + if (value) + b.set(f_held_center | f_center, true); + else + b.set(f_held_center, false); +} -void pipeline::toggle_zero() { negate(f_zero); } -void pipeline::toggle_enabled() { negate(f_enabled_p); } +void pipeline::set_enabled(bool value) { b.set(f_enabled_h, value); } +void pipeline::set_zero(bool value) { b.set(f_zero, value); } -void bits::set(flags flag_, bool val_) +void pipeline::toggle_zero() { b.negate(f_zero); } +void pipeline::toggle_enabled() { b.negate(f_enabled_p); } + +void bits::set(bit_flags flag, bool val) { - const unsigned flag = unsigned(flag_); - const unsigned val = unsigned(val_); + QMutexLocker l(&lock); - for (;;) - { - unsigned b_(b); - if (b.compare_exchange_weak(b_, - unsigned((b_ & ~flag) | (flag * val)), - std::memory_order_seq_cst, - std::memory_order_seq_cst)) - break; - } + flags &= ~flag; + if (val) + flags |= flag; } -void bits::negate(flags flag_) +void bits::negate(bit_flags flag) { - const unsigned flag = unsigned(flag_); + QMutexLocker l(&lock); - for (;;) - { - unsigned b_(b); - - if (b.compare_exchange_weak(b_, - b_ ^ flag, - std::memory_order_seq_cst, - std::memory_order_seq_cst)) - break; - } + flags ^= flag; } -bool bits::get(flags flag) +bool bits::get(bit_flags flag) { - return !!(b & flag); + QMutexLocker l(&lock); + + return !!(flags & flag); } -bits::bits() : b(0u) +bits::bits() { - set(f_center, true); + set(f_center, false); + set(f_held_center, false); set(f_enabled_p, true); set(f_enabled_h, true); set(f_zero, false); } + +} // ns pipeline_impl diff --git a/logic/pipeline.hpp b/logic/pipeline.hpp index 82a339a3..a539525d 100644 --- a/logic/pipeline.hpp +++ b/logic/pipeline.hpp @@ -1,11 +1,3 @@ -/* Copyright (c) 2014-2015, Stanislaw Halik <sthalik@misaki.pl> - - * Permission to use, copy, modify, and/or distribute this - * software for any purpose with or without fee is hereby granted, - * provided that the above copyright notice and this permission - * notice appear in all copies. - */ - #pragma once #include <vector> @@ -14,8 +6,8 @@ #include "api/plugin-support.hpp" #include "mappings.hpp" #include "compat/euler.hpp" +#include "compat/enum-operators.hpp" #include "runtime-libraries.hpp" -#include "extensions.hpp" #include "spline/spline.hpp" #include "main-settings.hpp" @@ -27,74 +19,74 @@ #include <atomic> #include <cmath> +#include <QQuaternion> #include "export.hpp" -namespace gui_tracker_impl { +namespace pipeline_impl { -using rmat = euler::rmat; -using euler_t = euler::euler_t; +using namespace euler; +using namespace time_units; using vec6_bool = Mat<bool, 6, 1>; using vec3_bool = Mat<bool, 6, 1>; class reltrans { - euler_t interp_pos, last_value; + Pose_ interp_pos; Timer interp_timer; // this implements smooth transition into reltrans mode // once not aiming anymore. see `apply_pipeline()'. Timer interp_phase_timer; - unsigned RC_phase; + unsigned RC_stage = 0; - bool cur = false; + bool moving_to_reltans = false; bool in_zone = false; public: reltrans(); - warn_result_unused - euler_t rotate(const rmat& rmat, const euler_t& in, vec3_bool disable) const; + void on_center(); - warn_result_unused + Pose_ rotate(const rmat& rmat, const Pose_& in, vec3_bool disable) const; + Pose_ apply_neck(const rmat& R, int nz, bool disable_tz) const; Pose apply_pipeline(reltrans_state state, const Pose& value, const vec6_bool& disable, bool neck_enable, int neck_z); - - warn_result_unused - euler_t apply_neck(const Pose& value, int nz) const; }; -using namespace time_units; +enum bit_flags : unsigned { + f_none = 0, + f_center = 1 << 0, + f_held_center = 1 << 1, + f_enabled_h = 1 << 2, + f_enabled_p = 1 << 3, + f_zero = 1 << 4, +}; struct OTR_LOGIC_EXPORT bits { - enum flags : unsigned { - f_center = 1 << 0, - f_enabled_h = 1 << 1, - f_enabled_p = 1 << 2, - f_zero = 1 << 3, - }; - - std::atomic<unsigned> b; - - void set(flags flag_, bool val_); - void negate(flags flag_); - bool get(flags flag); + bit_flags flags{0}; + QMutex lock; + + void set(bit_flags flag, bool val); + void negate(bit_flags flag); + bool get(bit_flags flag); bits(); }; -class OTR_LOGIC_EXPORT pipeline : private QThread, private bits +DEFINE_ENUM_OPERATORS(bit_flags); + +class OTR_LOGIC_EXPORT pipeline : private QThread { Q_OBJECT -private: - QMutex mtx; + + mutable QMutex mtx; main_settings s; - Mappings& m; - event_handler& ev; + const Mappings& m; Timer t; - Pose output_pose, raw_6dof, last_mapped, last_raw; + Pose output_pose, raw_6dof, last_value; Pose newpose; runtime_libraries const& libs; @@ -103,42 +95,36 @@ private: // the logger while the tracker is running. TrackLogger& logger; - struct state - { - rmat inv_rot_center; - rmat rotation; - - state() : inv_rot_center(rmat::eye()) - {} - }; - reltrans rel; - state rotation; - euler_t t_center; + struct { + Pose P; + QQuaternion QC = QQuaternion(1,0,0,0); + QQuaternion QR = QQuaternion(1,0,0,0); + } center; - ns backlog_time = ns(0); + time_units::ms backlog_time {}; bool tracking_started = false; - double map(double pos, Map& axis); + static double map(double pos, const Map& axis); void logic(); void run() override; bool maybe_enable_center_on_tracking_started(); - void maybe_set_center_pose(const Pose& value, bool own_center_logic); - Pose clamp_value(Pose value) const; - Pose apply_center(Pose value) const; - std::tuple<Pose, Pose, vec6_bool> get_selected_axis_value(const Pose& newpose) const; + void maybe_set_center_pose(const centering_state mode, const Pose& value, bool own_center_logic); + Pose apply_center(const centering_state mode, Pose value) const; + std::tuple<Pose, Pose, vec6_bool> get_selected_axis_values(const Pose& newpose) const; Pose maybe_apply_filter(const Pose& value) const; - Pose apply_reltrans(Pose value, vec6_bool disabled); + Pose apply_reltrans(Pose value, vec6_bool disabled, bool centerp); Pose apply_zero_pos(Pose value) const; - // reminder: float exponent base is 2 - //static constexpr inline double c_mult = 16; - //static constexpr inline double c_div = 1./c_mult; + void set_center(bool x); + + bits b; + public: - pipeline(Mappings& m, runtime_libraries& libs, event_handler& ev, TrackLogger& logger); - ~pipeline(); + pipeline(const Mappings& m, const runtime_libraries& libs, TrackLogger& logger); + ~pipeline() override; void raw_and_mapped_pose(double* mapped, double* raw) const; void start() { QThread::start(QThread::HighPriority); } @@ -146,11 +132,11 @@ public: void toggle_zero(); void toggle_enabled(); - void set_center(); + void set_held_center(bool value); void set_enabled(bool value); void set_zero(bool value); }; -} // ns impl +} // ns pipeline_impl -using gui_tracker_impl::pipeline; +using pipeline = pipeline_impl::pipeline; diff --git a/logic/runtime-libraries.cpp b/logic/runtime-libraries.cpp index d05e90c2..754f52cd 100644 --- a/logic/runtime-libraries.cpp +++ b/logic/runtime-libraries.cpp @@ -3,10 +3,16 @@ #include <QMessageBox> #include <QDebug> +#ifdef __clang__ +# pragma clang diagnostic ignored "-Wcomma" +#endif + runtime_libraries::runtime_libraries(QFrame* frame, dylibptr t, dylibptr p, dylibptr f) { + auto error = [](const QString& msg) { return module_status_mixin::error(msg); }; + module_status status = - module_status_mixin::error(otr_tr("Library load failure")); + error(tr("Library load failure")); using namespace options; @@ -15,12 +21,15 @@ runtime_libraries::runtime_libraries(QFrame* frame, dylibptr t, dylibptr p, dyli pProtocol = make_dylib_instance<IProtocol>(p); if (!pProtocol) + { + qDebug() << "protocol dylib load failure"; goto end; + } if(status = pProtocol->initialize(), !status.is_ok()) { - status = _("Error occurred while loading protocol %1\n\n%2\n") - .arg(p->name).arg(status.error); + status = error(tr("Error occurred while loading protocol %1\n\n%2\n") + .arg(p->name, status.error)); goto end; } @@ -33,18 +42,24 @@ runtime_libraries::runtime_libraries(QFrame* frame, dylibptr t, dylibptr p, dyli goto end; } + if (f && f->Constructor && !pFilter) + { + qDebug() << "filter load failure"; + goto end; + } + if (pFilter) if(status = pFilter->initialize(), !status.is_ok()) { - status = _("Error occurred while loading filter %1\n\n%2\n") - .arg(f->name).arg(status.error); + status = error(tr("Error occurred while loading filter %1\n\n%2\n") + .arg(f->name, status.error)); goto end; } if (status = pTracker->start_tracker(frame), !status.is_ok()) { - status = _("Error occurred while loading tracker %1\n\n%2\n") - .arg(t->name).arg(status.error); + status = error(tr("Error occurred while loading tracker %1\n\n%2\n") + .arg(t->name, status.error)); goto end; } @@ -57,6 +72,8 @@ end: pProtocol = nullptr; if (!status.is_ok()) - QMessageBox::critical(nullptr, "Startup failure", status.error, QMessageBox::Cancel, QMessageBox::NoButton); + QMessageBox::critical(nullptr, + tr("Startup failure"), status.error, + QMessageBox::Cancel, QMessageBox::NoButton); } diff --git a/logic/runtime-libraries.hpp b/logic/runtime-libraries.hpp index 1105c179..8c7fedd1 100644 --- a/logic/runtime-libraries.hpp +++ b/logic/runtime-libraries.hpp @@ -9,12 +9,16 @@ #pragma once #include "api/plugin-support.hpp" +#include "compat/tr.hpp" #include "export.hpp" -#include <QFrame> +class QFrame; -struct OTR_LOGIC_EXPORT runtime_libraries final +class OTR_LOGIC_EXPORT runtime_libraries final : public TR { + Q_OBJECT + +public: using dylibptr = std::shared_ptr<dylib>; std::shared_ptr<ITracker> pTracker; @@ -22,7 +26,7 @@ struct OTR_LOGIC_EXPORT runtime_libraries final std::shared_ptr<IProtocol> pProtocol; runtime_libraries(QFrame* frame, dylibptr t, dylibptr p, dylibptr f); - runtime_libraries() : pTracker(nullptr), pFilter(nullptr), pProtocol(nullptr), correct(false) {} + runtime_libraries() = default; bool correct = false; }; diff --git a/logic/shortcuts.cpp b/logic/shortcuts.cpp index 5ddefc1f..df21f7d2 100644 --- a/logic/shortcuts.cpp +++ b/logic/shortcuts.cpp @@ -29,9 +29,9 @@ void Shortcuts::free_binding(K& key) #endif } -void Shortcuts::bind_shortcut(K &key, const key_opts& k, bool held) +void Shortcuts::bind_shortcut(K& key, const key_opts& k, bool held) { -#if !defined(_WIN32) +#if !defined _WIN32 (void)held; using sh = QxtGlobalShortcut; if (key) @@ -46,13 +46,18 @@ void Shortcuts::bind_shortcut(K &key, const key_opts& k, bool held) key->setShortcut(QKeySequence::fromString(k.keycode, QKeySequence::PortableText)); key->setEnabled(); } -} #else - key = K(); + key = {}; int idx = 0; - QKeySequence code; + QKeySequence code(QKeySequence::UnknownKey); - if (k.guid != "") + if (k.guid == QStringLiteral("mouse")) + { + key.guid = k.guid; + key.keycode = k.button; + key.held = held; + } + if (!k.guid->isEmpty()) { key.guid = k.guid; key.keycode = k.button & ~Qt::KeyboardModifierMask; @@ -63,48 +68,51 @@ void Shortcuts::bind_shortcut(K &key, const key_opts& k, bool held) } else { - if (k.keycode == "") - code = QKeySequence(Qt::Key_unknown); - else + if (!k.keycode->isEmpty()) code = QKeySequence::fromString(k.keycode, QKeySequence::PortableText); Qt::KeyboardModifiers mods = Qt::NoModifier; - if (code != Qt::Key_unknown) - win_key::from_qt(code, idx, mods); - - key.guid = ""; - key.keycode = idx; - key.held = held; - key.ctrl = !!(mods & Qt::ControlModifier); - key.alt = !!(mods & Qt::AltModifier); - key.shift = !!(mods & Qt::ShiftModifier); + if (!code.isEmpty() && + code != QKeySequence{ QKeySequence::UnknownKey } && + win_key::from_qt(code, idx, mods)) + { + key.guid = QString{}; + key.keycode = idx; + key.held = held; + key.ctrl = !!(mods & Qt::ControlModifier); + key.alt = !!(mods & Qt::AltModifier); + key.shift = !!(mods & Qt::ShiftModifier); + } } -} #endif +} #ifdef _WIN32 -void Shortcuts::receiver(const Key& k) + +void Shortcuts::receiver(const Key& key) { const unsigned sz = keys.size(); for (unsigned i = 0; i < sz; i++) { - K& k_ = std::get<0>(keys[i]); - if (k.guid != k_.guid) + auto& [k, f, held] = keys[i]; + if (key.guid != k.guid) continue; - if (k.keycode != k_.keycode) + if (key.keycode != k.keycode) continue; - if (k_.held && !k.held) continue; - if (k_.alt != k.alt) continue; - if (k_.ctrl != k.ctrl) continue; - if (k_.shift != k.shift) continue; - if (!k_.should_process()) - continue; - - fun& f = std::get<1>(keys[i]); - f(k.held); + if (k.held && !key.held) continue; + if (key.held) + { + if (k.alt != key.alt) continue; + if (k.ctrl != key.ctrl) continue; + if (k.shift != key.shift) continue; + if (!k.should_process()) + continue; + } + f(key.held); } } + #endif Shortcuts::~Shortcuts() @@ -127,24 +135,22 @@ void Shortcuts::reload(const t_keys& keys_) for (unsigned i = 0; i < sz; i++) { - const auto& kk = keys_[i]; - const key_opts& opts = std::get<0>(kk); - const bool held = std::get<2>(kk); - auto fun = std::get<1>(kk); + auto const&[opts, fun, held] = keys_[i]; #ifdef _WIN32 K k; #else K k(nullptr); #endif bind_shortcut(k, opts, held); - keys.push_back(tt(k, [=](bool flag) { fun(flag); }, held)); + keys.emplace_back(k, fun, held); #ifndef _WIN32 const int idx = keys.size() - 1; tt& kk_ = keys[idx]; auto fn = std::get<1>(kk_); - connect(k, &QxtGlobalShortcut::activated, [fn, held](bool keydown) { - if (keydown || !held) + bool held_ = held; + connect(k, &QxtGlobalShortcut::activated, [fn, held_](bool keydown) { + if (keydown || !held_) fn(keydown); }); #endif diff --git a/logic/shortcuts.h b/logic/shortcuts.h index 046e68de..87926f66 100644 --- a/logic/shortcuts.h +++ b/logic/shortcuts.h @@ -24,6 +24,10 @@ #include <vector> #include <functional> +#if !defined __APPLE__ +# define OTR_HAS_KEY_UP_SUPPORT +#endif + namespace shortcuts_impl { using namespace options; @@ -54,8 +58,8 @@ public: KeybindingWorker::Token key_token {[this](const Key& k) { receiver(k); }}; #endif - Shortcuts() {} - ~Shortcuts(); + Shortcuts() = default; + ~Shortcuts() override; void reload(const t_keys& keys_); private: diff --git a/logic/state.cpp b/logic/state.cpp new file mode 100644 index 00000000..dc5e5a36 --- /dev/null +++ b/logic/state.cpp @@ -0,0 +1,57 @@ +#include "state.hpp" +#include "opentrack/defs.hpp" +#include <iterator> + +using dylib_ptr = Modules::dylib_ptr; +using dylib_list = Modules::dylib_list; + +std::tuple<dylib_ptr, int> State::module_by_name(const QString& name, dylib_list& list) +{ + auto it = std::find_if(list.cbegin(), list.cend(), [&name](const dylib_ptr& lib) { + if (!lib) + return name.isEmpty(); + else + return name == lib->module_name; + }); + + if (it == list.cend()) + return { nullptr, -1 }; + else + return { *it, int(std::distance(list.cbegin(), it)) }; +} + +State::State(const QString& library_path) : + modules(library_path), + pose(s.all_axis_opts), + library_path{library_path} +{} + +dylib_ptr State::current_tracker() +{ + const QString& module = +#ifdef UI_FORCED_TRACKER + UI_FORCED_TRACKER; +#else + m.tracker_dll; +#endif + auto [ptr, idx] = module_by_name(module, modules.trackers()); + return ptr; +} + +dylib_ptr State::current_protocol() +{ + auto [ptr, idx] = module_by_name(m.protocol_dll, modules.protocols()); + return ptr; +} + +dylib_ptr State::current_filter() +{ + const QString& module = +#ifdef UI_FORCED_FILTER + UI_FORCED_FILTER; +#else + m.filter_dll; +#endif + auto [ptr, idx] = module_by_name(module, modules.filters()); + return ptr; +} diff --git a/logic/state.hpp b/logic/state.hpp index 25205524..7fc06a5c 100644 --- a/logic/state.hpp +++ b/logic/state.hpp @@ -12,21 +12,28 @@ #include "api/plugin-support.hpp" #include "main-settings.hpp" #include "mappings.hpp" -#include "extensions.hpp" #include "work.hpp" -#include <vector> +#include "export.hpp" + +#include <memory> #include <QString> -struct State +struct OTR_LOGIC_EXPORT State { - State(const QString& library_path) : - modules(library_path), - ev(modules.extensions()), - pose(s.all_axis_opts) - {} + using dylib_ptr = Modules::dylib_ptr; + using dylib_list = Modules::dylib_list; + + explicit State(const QString& library_path); + static std::tuple<dylib_ptr, int> module_by_name(const QString& name, dylib_list& list); + + dylib_ptr current_tracker(); + dylib_ptr current_protocol(); + dylib_ptr current_filter(); + Modules modules; - event_handler ev; main_settings s; + module_settings m; Mappings pose; std::shared_ptr<Work> work; + QString library_path; }; diff --git a/logic/tracklogger.cpp b/logic/tracklogger.cpp index 35510cb3..758c2478 100644 --- a/logic/tracklogger.cpp +++ b/logic/tracklogger.cpp @@ -1,7 +1,14 @@ #include "tracklogger.hpp" #include "pipeline.hpp" -TrackLogger::~TrackLogger() {} +#include <QMessageBox> + +TrackLogger::~TrackLogger() = default; + +void TrackLogger::write_pose(const double* p) +{ + write(p, 6); +} void TrackLogger::reset_dt() { diff --git a/logic/tracklogger.hpp b/logic/tracklogger.hpp index 0a8d5410..84cded28 100644 --- a/logic/tracklogger.hpp +++ b/logic/tracklogger.hpp @@ -5,41 +5,21 @@ #include <fstream> #include <QString> -#include <QMessageBox> -#include <QWidget> +#include <QDebug> class OTR_LOGIC_EXPORT TrackLogger { - TrackLogger(TrackLogger&&) = delete; - TrackLogger(const TrackLogger&) = delete; - TrackLogger& operator=(const TrackLogger&) = delete; - TrackLogger& operator=(TrackLogger&&) = delete; - Timer t; public: - TrackLogger() - { - } - + TrackLogger() = default; virtual ~TrackLogger(); - virtual void write(const char *) - { - } + virtual void write(const char *) {} + virtual void write(const double *, int) {} + virtual void next_line() {} - virtual void write(const double *, int) - { - } - - virtual void next_line() - { - } - - void write_pose(const double *p) - { - write(p, 6); - } + void write_pose(const double *p); void reset_dt(); void write_dt(); @@ -49,10 +29,10 @@ public: class OTR_LOGIC_EXPORT TrackLoggerCSV : public TrackLogger { std::ofstream out; - bool first_col; + bool first_col = true; inline void handle_first_col_sep(); public: - TrackLoggerCSV(const QString &filename) : first_col(true) + explicit TrackLoggerCSV(const QString &filename) { out.open(filename.toStdString()); } @@ -61,5 +41,8 @@ public: void write(const char *s) override; void write(const double *p, int n) override; void next_line() override; + + TrackLoggerCSV(const TrackLoggerCSV&) = delete; + TrackLoggerCSV& operator=(const TrackLoggerCSV&) = delete; }; diff --git a/logic/win32-shortcuts.cpp b/logic/win32-shortcuts.cpp index 2099ce09..cb4f99b3 100644 --- a/logic/win32-shortcuts.cpp +++ b/logic/win32-shortcuts.cpp @@ -15,6 +15,7 @@ #include <QVariant> #include <QDebug> +#if 0 win_key const windows_key_mods[] { {DIK_LCONTROL, Qt::Key_Control}, {DIK_RCONTROL, Qt::Key_Control}, @@ -25,6 +26,7 @@ win_key const windows_key_mods[] { {DIK_LWIN, Qt::Key_Super_L}, {DIK_RWIN, Qt::Key_Super_R}, }; +#endif static const win_key windows_key_sequences[] { { DIK_F1, Qt::Key_F1 }, @@ -39,6 +41,9 @@ static const win_key windows_key_sequences[] { { DIK_F10, Qt::Key_F10 }, { DIK_F11, Qt::Key_F11 }, { DIK_F12, Qt::Key_F12 }, + { DIK_F13, Qt::Key_F13 }, + { DIK_F14, Qt::Key_F14 }, + { DIK_F15, Qt::Key_F15 }, { DIK_LEFT, Qt::Key_Left }, { DIK_RIGHT, Qt::Key_Right }, { DIK_UP, Qt::Key_Up }, @@ -61,18 +66,6 @@ static const win_key windows_key_sequences[] { { DIK_MINUS, Qt::Key_Minus }, { DIK_EQUALS, Qt::Key_Equal }, { DIK_PERIOD, Qt::Key_Period }, - { DIK_F1, Qt::Key_F1 }, - { DIK_F2, Qt::Key_F2 }, - { DIK_F3, Qt::Key_F3 }, - { DIK_F4, Qt::Key_F4 }, - { DIK_F5, Qt::Key_F5 }, - { DIK_F6, Qt::Key_F6 }, - { DIK_F7, Qt::Key_F7 }, - { DIK_F8, Qt::Key_F8 }, - { DIK_F9, Qt::Key_F9 }, - { DIK_F10, Qt::Key_F10 }, - { DIK_F11, Qt::Key_F11 }, - { DIK_F12, Qt::Key_F12 }, { DIK_0, Qt::Key_0 }, { DIK_1, Qt::Key_1 }, { DIK_2, Qt::Key_2 }, @@ -119,26 +112,26 @@ static const win_key windows_key_sequences[] { { DIK_PAUSE, Qt::Key_Pause}, { DIK_NUMLOCK, Qt::Key_NumLock}, { DIK_CAPSLOCK, Qt::Key_CapsLock}, -#define mod(x, y) static_cast<Qt::Key>(x | y) - { DIK_NUMPAD0, mod(Qt::Key_0, Qt::KeypadModifier)}, - { DIK_NUMPAD0, mod(Qt::Key_0, Qt::KeypadModifier)}, - { DIK_NUMPAD1, mod(Qt::Key_1, Qt::KeypadModifier)}, - { DIK_NUMPAD2, mod(Qt::Key_2, Qt::KeypadModifier)}, - { DIK_NUMPAD3, mod(Qt::Key_3, Qt::KeypadModifier)}, - { DIK_NUMPAD4, mod(Qt::Key_4, Qt::KeypadModifier)}, - { DIK_NUMPAD5, mod(Qt::Key_5, Qt::KeypadModifier)}, - { DIK_NUMPAD6, mod(Qt::Key_6, Qt::KeypadModifier)}, - { DIK_NUMPAD7, mod(Qt::Key_7, Qt::KeypadModifier)}, - { DIK_NUMPAD8, mod(Qt::Key_8, Qt::KeypadModifier)}, - { DIK_NUMPAD9, mod(Qt::Key_9, Qt::KeypadModifier)}, - { DIK_NUMPADCOMMA, mod(Qt::Key_Comma, Qt::KeypadModifier)}, - { DIK_NUMPADENTER, mod(Qt::Key_Enter, Qt::KeypadModifier)}, - { DIK_NUMPADEQUALS, mod(Qt::Key_Equal, Qt::KeypadModifier)}, - { DIK_NUMPADMINUS, mod(Qt::Key_Minus, Qt::KeypadModifier)}, - { DIK_NUMPADPERIOD, mod(Qt::Key_Period, Qt::KeypadModifier)}, - { DIK_NUMPADPLUS, mod(Qt::Key_Plus, Qt::KeypadModifier)}, - { DIK_NUMPADSLASH, mod(Qt::Key_Slash, Qt::KeypadModifier)}, - { DIK_NUMPADSTAR, mod(Qt::Key_multiply, Qt::KeypadModifier)}, +#define key_mod(x, y) Qt::Key(int((x)) | int((y))) + { DIK_NUMPAD0, key_mod(Qt::Key_0, Qt::KeypadModifier)}, + { DIK_NUMPAD0, key_mod(Qt::Key_0, Qt::KeypadModifier)}, + { DIK_NUMPAD1, key_mod(Qt::Key_1, Qt::KeypadModifier)}, + { DIK_NUMPAD2, key_mod(Qt::Key_2, Qt::KeypadModifier)}, + { DIK_NUMPAD3, key_mod(Qt::Key_3, Qt::KeypadModifier)}, + { DIK_NUMPAD4, key_mod(Qt::Key_4, Qt::KeypadModifier)}, + { DIK_NUMPAD5, key_mod(Qt::Key_5, Qt::KeypadModifier)}, + { DIK_NUMPAD6, key_mod(Qt::Key_6, Qt::KeypadModifier)}, + { DIK_NUMPAD7, key_mod(Qt::Key_7, Qt::KeypadModifier)}, + { DIK_NUMPAD8, key_mod(Qt::Key_8, Qt::KeypadModifier)}, + { DIK_NUMPAD9, key_mod(Qt::Key_9, Qt::KeypadModifier)}, + { DIK_NUMPADCOMMA, key_mod(Qt::Key_Comma, Qt::KeypadModifier)}, + { DIK_NUMPADENTER, key_mod(Qt::Key_Enter, Qt::KeypadModifier)}, + { DIK_NUMPADEQUALS, key_mod(Qt::Key_Equal, Qt::KeypadModifier)}, + { DIK_NUMPADMINUS, key_mod(Qt::Key_Minus, Qt::KeypadModifier)}, + { DIK_NUMPADPERIOD, key_mod(Qt::Key_Period, Qt::KeypadModifier)}, + { DIK_NUMPADPLUS, key_mod(Qt::Key_Plus, Qt::KeypadModifier)}, + { DIK_NUMPADSLASH, key_mod(Qt::Key_Slash, Qt::KeypadModifier)}, + { DIK_NUMPADSTAR, key_mod(Qt::Key_multiply, Qt::KeypadModifier)}, }; bool win_key::to_qt(const Key& k, QKeySequence& qt_, Qt::KeyboardModifiers &mods) @@ -158,23 +151,25 @@ bool win_key::to_qt(const Key& k, QKeySequence& qt_, Qt::KeyboardModifiers &mods return false; } -bool win_key::from_qt(QKeySequence qt_, int& dik, Qt::KeyboardModifiers& mods) +bool win_key::from_qt(const QKeySequence& qt_, int& dik, Qt::KeyboardModifiers& mods) { // CAVEAT don't use QVariant::toUInt() or conversion fails - const unsigned qt = static_cast<unsigned>(QVariant(qt_).toInt()); - const unsigned our_mods = unsigned(qt & Qt::KeyboardModifierMask); + const unsigned qt = (unsigned)QVariant(qt_).toInt(); + const unsigned our_mods = qt & (unsigned)Qt::KeyboardModifierMask; + + if (qt == 0) + return false; + for (const win_key& wk : windows_key_sequences) { - for (const win_key& wk : windows_key_sequences) + if (unsigned(wk.qt) == qt) { - if (unsigned(wk.qt) == qt) - { - dik = wk.win; - mods = Qt::NoModifier; - return true; - } + dik = wk.win; + mods = Qt::NoModifier; + return true; } } + { const unsigned key = qt & ~Qt::KeyboardModifierMask; for (const win_key& wk : windows_key_sequences) @@ -182,7 +177,7 @@ bool win_key::from_qt(QKeySequence qt_, int& dik, Qt::KeyboardModifiers& mods) if (unsigned(wk.qt) == key) { dik = wk.win; - mods = static_cast<Qt::KeyboardModifiers>(our_mods); + mods = { (Qt::KeyboardModifier)our_mods }; return true; } } diff --git a/logic/win32-shortcuts.h b/logic/win32-shortcuts.h index 8cd6bdc9..afc909ed 100644 --- a/logic/win32-shortcuts.h +++ b/logic/win32-shortcuts.h @@ -10,11 +10,11 @@ struct OTR_LOGIC_EXPORT win_key { - win_key(int win, Qt::Key qt) : win(win), qt(qt) {} + //win_key(int win, Qt::Key qt) : win(win), qt(qt) {} int win; Qt::Key qt; - static bool from_qt(QKeySequence qt_, int& dik, Qt::KeyboardModifiers &mods); - static bool to_qt(const Key& k, QKeySequence& qt_, Qt::KeyboardModifiers &mods); + [[nodiscard]] static bool from_qt(const QKeySequence& qt_, int& dik, Qt::KeyboardModifiers &mods); + [[nodiscard]] static bool to_qt(const Key& k, QKeySequence& qt_, Qt::KeyboardModifiers &mods); }; #endif diff --git a/logic/work.cpp b/logic/work.cpp index 11ec9912..8c6a3a62 100644 --- a/logic/work.cpp +++ b/logic/work.cpp @@ -1,6 +1,8 @@ #include "work.hpp" #include "compat/library-path.hpp" +#include <utility> + #include <QObject> #include <QMessageBox> #include <QFileDialog> @@ -16,9 +18,9 @@ QString Work::browse_datalogging_file(main_settings &s) Since the freeze is apparently random, I'm not sure it helped. */ QString newfilename = QFileDialog::getSaveFileName(nullptr, - otr_tr("Select filename"), + tr("Select filename"), filename, - otr_tr("CSV File (*.csv)"), + tr("CSV File (*.csv)"), nullptr); if (!newfilename.isEmpty()) { @@ -29,67 +31,46 @@ QString Work::browse_datalogging_file(main_settings &s) return newfilename; } -std::shared_ptr<TrackLogger> Work::make_logger(main_settings &s) +std::unique_ptr<TrackLogger> Work::make_logger(main_settings &s) { if (s.tracklogging_enabled) { QString filename = browse_datalogging_file(s); - if (filename.isEmpty()) - { - // The user probably canceled the file dialog. In this case we don't want to do anything. - } - else + + if (!filename.isEmpty()) { - auto logger = std::make_shared<TrackLoggerCSV>(s.tracklogging_filename); + auto logger = std::make_unique<TrackLoggerCSV>(*s.tracklogging_filename); + if (!logger->is_open()) { - logger = nullptr; QMessageBox::warning(nullptr, - otr_tr("Logging error"), - otr_tr("Unable to open file '%1'. Proceeding without logging.").arg(s.tracklogging_filename), + tr("Logging error"), + tr("Unable to open file '%1'. Proceeding without logging.").arg(s.tracklogging_filename), QMessageBox::Ok, QMessageBox::NoButton); } else - { return logger; - } } } - return std::make_shared<TrackLogger>(); -} - - -Work::Work(Mappings& m, event_handler& ev, QFrame* frame, std::shared_ptr<dylib> tracker_, std::shared_ptr<dylib> filter_, std::shared_ptr<dylib> proto_) : - libs(frame, tracker_, filter_, proto_), - logger(make_logger(s)), - tracker(std::make_shared<pipeline>(m, libs, ev, *logger)), - sc(std::make_shared<Shortcuts>()), - keys { - key_tuple(s.key_center1, [&](bool) { tracker->set_center(); }, true), - key_tuple(s.key_center2, [&](bool) { tracker->set_center(); }, true), - key_tuple(s.key_toggle1, [&](bool) { tracker->toggle_enabled(); }, true), - key_tuple(s.key_toggle2, [&](bool) { tracker->toggle_enabled(); }, true), - - key_tuple(s.key_zero1, [&](bool) { tracker->toggle_zero(); }, true), - key_tuple(s.key_zero2, [&](bool) { tracker->toggle_zero(); }, true), + return std::make_unique<TrackLogger>(); +} - key_tuple(s.key_toggle_press1, [&](bool x) { tracker->set_enabled(!x); }, false), - key_tuple(s.key_toggle_press2, [&](bool x) { tracker->set_enabled(!x); }, false), - key_tuple(s.key_zero_press1, [&](bool x) { tracker->set_zero(x); }, false), - key_tuple(s.key_zero_press2, [&](bool x) { tracker->set_zero(x); }, false), - } +Work::Work(const Mappings& m, QFrame* frame, + const dylibptr& tracker, const dylibptr& filter, const dylibptr& proto) : + libs(frame, tracker, filter, proto), + pipeline_{ m, libs, *logger } { if (!is_ok()) return; reload_shortcuts(); - tracker->start(); + pipeline_.start(); } void Work::reload_shortcuts() { - sc->reload(keys); + sc.reload(keys); } bool Work::is_ok() const @@ -97,10 +78,13 @@ bool Work::is_ok() const return libs.correct; } +// TODO member dtor order looks fine, check valgrind -sh 20180706 +#if 0 Work::~Work() { // order matters, otherwise use-after-free -sh - sc = nullptr; - tracker = nullptr; - libs = runtime_libraries(); + //sc = nullptr; + //pipeline = nullptr; + //libs = runtime_libraries(); } +#endif diff --git a/logic/work.hpp b/logic/work.hpp index 7f6cb450..ef839257 100644 --- a/logic/work.hpp +++ b/logic/work.hpp @@ -16,6 +16,7 @@ #include "tracklogger.hpp" #include "logic/runtime-libraries.hpp" #include "api/plugin-support.hpp" +#include "compat/tr.hpp" #include <QObject> #include <QFrame> @@ -24,23 +25,42 @@ #include <tuple> #include <functional> -struct OTR_LOGIC_EXPORT Work +class OTR_LOGIC_EXPORT Work final : public QObject { + Q_OBJECT + + using dylibptr = std::shared_ptr<dylib>; + + static std::unique_ptr<TrackLogger> make_logger(main_settings &s); + static QString browse_datalogging_file(main_settings &s); + +public: using fn_t = std::function<void(bool)>; using key_tuple = std::tuple<key_opts&, fn_t, bool>; - main_settings s; // tracker needs settings, so settings must come before it + main_settings s; // pipeline needs settings, so settings must come before it runtime_libraries libs; // idem - std::shared_ptr<TrackLogger> logger; // must come before tracker, since tracker depends on it - std::shared_ptr<pipeline> tracker; - std::shared_ptr<Shortcuts> sc; - std::vector<key_tuple> keys; + std::unique_ptr<TrackLogger> logger { make_logger(s) }; // must come before pipeline, since pipeline depends on it + pipeline pipeline_; + Shortcuts sc; + + std::vector<key_tuple> keys { + // third argument means "keydown only" + key_tuple(s.key_center1, [this](bool x) { pipeline_.set_held_center(x); }, false), + key_tuple(s.key_center2, [this](bool x) { pipeline_.set_held_center(x); }, false), - Work(Mappings& m, event_handler& ev, QFrame* frame, std::shared_ptr<dylib> tracker, std::shared_ptr<dylib> filter, std::shared_ptr<dylib> proto); - ~Work(); + key_tuple(s.key_toggle1, [this](bool) { pipeline_.toggle_enabled(); }, true), + key_tuple(s.key_toggle2, [this](bool) { pipeline_.toggle_enabled(); }, true), + key_tuple(s.key_toggle_press1, [this](bool x) { pipeline_.set_enabled(!x); }, false), + key_tuple(s.key_toggle_press2, [this](bool x) { pipeline_.set_enabled(!x); }, false), + + key_tuple(s.key_zero1, [this](bool) { pipeline_.toggle_zero(); }, true), + key_tuple(s.key_zero2, [this](bool) { pipeline_.toggle_zero(); }, true), + key_tuple(s.key_zero_press1, [this](bool x) { pipeline_.set_zero(x); }, false), + key_tuple(s.key_zero_press2, [this](bool x) { pipeline_.set_zero(x); }, false), + }; + + Work(const Mappings& m, QFrame* frame, + const dylibptr& tracker, const dylibptr& filter, const dylibptr& proto); void reload_shortcuts(); bool is_ok() const; - -private: - static std::shared_ptr<TrackLogger> make_logger(main_settings &s); - static QString browse_datalogging_file(main_settings &s); }; |
