diff options
Diffstat (limited to 'logic')
| -rw-r--r-- | logic/CMakeLists.txt | 6 | ||||
| -rw-r--r-- | logic/lang/de_DE.ts | 64 | ||||
| -rw-r--r-- | logic/lang/nl_NL.ts | 36 | ||||
| -rw-r--r-- | logic/lang/ru_RU.ts | 36 | ||||
| -rw-r--r-- | logic/lang/stub.ts | 36 | ||||
| -rw-r--r-- | logic/lang/zh_CN.ts | 64 | ||||
| -rw-r--r-- | logic/main-settings.cpp | 85 | ||||
| -rw-r--r-- | logic/main-settings.hpp | 138 | ||||
| -rw-r--r-- | logic/mappings.cpp | 35 | ||||
| -rw-r--r-- | logic/mappings.hpp | 11 | ||||
| -rw-r--r-- | logic/pipeline.cpp | 690 | ||||
| -rw-r--r-- | logic/pipeline.hpp | 142 | ||||
| -rw-r--r-- | logic/runtime-libraries.cpp | 79 | ||||
| -rw-r--r-- | logic/runtime-libraries.hpp | 32 | ||||
| -rw-r--r-- | logic/selected-libraries.cpp | 46 | ||||
| -rw-r--r-- | logic/selected-libraries.hpp | 25 | ||||
| -rw-r--r-- | logic/shortcuts.cpp | 88 | ||||
| -rw-r--r-- | logic/shortcuts.h | 30 | ||||
| -rw-r--r-- | logic/state.cpp | 57 | ||||
| -rw-r--r-- | logic/state.hpp | 25 | ||||
| -rw-r--r-- | logic/tracker.cpp | 487 | ||||
| -rw-r--r-- | logic/tracker.h | 124 | ||||
| -rw-r--r-- | logic/tracklogger.cpp | 11 | ||||
| -rw-r--r-- | logic/tracklogger.hpp | 39 | ||||
| -rw-r--r-- | logic/win32-shortcuts.cpp | 276 | ||||
| -rw-r--r-- | logic/win32-shortcuts.h | 12 | ||||
| -rw-r--r-- | logic/work.cpp | 73 | ||||
| -rw-r--r-- | logic/work.hpp | 52 |
28 files changed, 1650 insertions, 1149 deletions
diff --git a/logic/CMakeLists.txt b/logic/CMakeLists.txt index 177dd045..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) + target_link_libraries(${self} opentrack-dinput winmm) endif() 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 c6ca1553..85b50bd8 100644 --- a/logic/lang/nl_NL.ts +++ b/logic/lang/nl_NL.ts @@ -4,24 +4,52 @@ <context> <name>Work</name> <message> - <location filename="../work.cpp" line="+20"/> <source>Select filename</source> <translation type="unfinished"></translation> </message> <message> - <location line="+2"/> <source>CSV File (*.csv)</source> <translation type="unfinished"></translation> </message> <message> - <location line="+26"/> <source>Logging error</source> <translation type="unfinished"></translation> </message> <message> - <location line="+1"/> <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 e9fcd993..7772438c 100644 --- a/logic/lang/ru_RU.ts +++ b/logic/lang/ru_RU.ts @@ -4,24 +4,52 @@ <context> <name>Work</name> <message> - <location filename="../work.cpp" line="+20"/> <source>Select filename</source> <translation type="unfinished"></translation> </message> <message> - <location line="+2"/> <source>CSV File (*.csv)</source> <translation type="unfinished"></translation> </message> <message> - <location line="+26"/> <source>Logging error</source> <translation type="unfinished"></translation> </message> <message> - <location line="+1"/> <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 5d1bc11a..cc15f98a 100644 --- a/logic/lang/stub.ts +++ b/logic/lang/stub.ts @@ -4,24 +4,52 @@ <context> <name>Work</name> <message> - <location filename="../work.cpp" line="+20"/> <source>Select filename</source> <translation type="unfinished"></translation> </message> <message> - <location line="+2"/> <source>CSV File (*.csv)</source> <translation type="unfinished"></translation> </message> <message> - <location line="+26"/> <source>Logging error</source> <translation type="unfinished"></translation> </message> <message> - <location line="+1"/> <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 new file mode 100644 index 00000000..000aff7c --- /dev/null +++ b/logic/lang/zh_CN.ts @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<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 987dd250..3865e602 100644 --- a/logic/main-settings.cpp +++ b/logic/main-settings.cpp @@ -1,62 +1,11 @@ #include "main-settings.hpp" -main_settings::main_settings() : - b(make_bundle("opentrack-ui")), - b_map(make_bundle("opentrack-mappings")), - a_x(b, b_map, "x", TX), - a_y(b, b_map, "y", TY), - a_z(b, b_map, "z", TZ), - a_yaw(b, b_map, "yaw", Yaw), - a_pitch(b, b_map, "pitch", Pitch), - a_roll(b, b_map, "roll", Roll), - tcomp_p(b, "compensate-translation", false), - tcomp_disable_tx(b, "compensate-translation-disable-x-axis", false), - tcomp_disable_ty(b, "compensate-translation-disable-y-axis", false), - tcomp_disable_tz(b, "compensate-translation-disable-z-axis", false), - tcomp_disable_src_yaw(b, "compensate-translation-disable-source-yaw", false), - tcomp_disable_src_pitch(b, "compensate-translation-disable-source-pitch", false), - tcomp_disable_src_roll(b, "compensate-translation-disable-source-roll", false), - tray_enabled(b, "use-system-tray", false), - tray_start(b, "start-in-tray", false), - camera_yaw(b, "camera-yaw", 0), - camera_pitch(b, "camera-pitch", 0), - camera_roll(b, "camera-roll", 0), - use_camera_offset_from_centering(b, "use-camera-offset-from-centering", false), - center_at_startup(b, "center-at-startup", true), - center_method(b, "centering-method", 1), - neck_y(b, "neck-height", 0), - 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()) -{ -} +namespace main_settings_impl { -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") -{ -} +using namespace options; + +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), ""), @@ -64,18 +13,16 @@ key_opts::key_opts(bundle b, const QString& name) : button(b, QString("button-%1").arg(name), -1) {} - -axis_opts::axis_opts(bundle b_settings_window, bundle b_mapping_window, QString pfx, Axis idx) : - b_settings_window(b_settings_window), - b_mapping_window(b_mapping_window), - zero(b_settings_window, n(pfx, "zero-pos"), 0), - src(b_settings_window, n(pfx, "source-index"), idx), - invert(b_settings_window, n(pfx, "invert-sign"), false), - altp(b_mapping_window, n(pfx, "alt-axis-sign"), false), - clamp(b_mapping_window, n(pfx, "max-value"), idx >= Yaw ? r180 : t30) -{} - -QString axis_opts::n(QString pfx, QString name) +key_opts& key_opts::operator=(const key_opts& x) { - return QString("%1-%2").arg(pfx, name); + 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 51b729e3..fcd5e745 100644 --- a/logic/main-settings.hpp +++ b/logic/main-settings.hpp @@ -11,87 +11,107 @@ #include <QString> #include "options/options.hpp" #include "api/plugin-api.hpp" - -using namespace options; +#include "spline/axis-opts.hpp" #include "export.hpp" -namespace axis_clamp_opts +enum reltrans_state : int { + reltrans_disabled = 0, + reltrans_enabled = 1, + reltrans_non_center = 2, +}; -} // ns axis-clamp-opts - -struct OTR_LOGIC_EXPORT axis_opts final +enum centering_state : int { - enum max_clamp - { - r180 = 180, - r90 = 90, - r60 = 60, - r45 = 45, - r30 = 30, - r25 = 25, - r20 = 20, - r15 = 15, - r10 = 10, - - t100 = 100, - t30 = 30, - t20 = 20, - t15 = 15, - t10 = 10, - }; - - // note, these two bundles can be the same value with no issues - bundle b_settings_window, b_mapping_window; - value<double> zero; - value<int> src; - value<bool> invert, altp; - value<max_clamp> clamp; - axis_opts(bundle b_settings_window, bundle b_mapping_window, QString pfx, Axis idx); -private: - static inline QString n(QString pfx, QString name); + center_disabled = 0, + center_point = 1, + center_vr360 = 2, + center_roll_compensated = 3, }; +namespace main_settings_impl { + +using namespace options; + struct OTR_LOGIC_EXPORT key_opts { value<QString> keycode, guid; 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; - value<bool> tcomp_p, tcomp_disable_tx, tcomp_disable_ty, tcomp_disable_tz; - value<bool> tcomp_disable_src_yaw, tcomp_disable_src_pitch, tcomp_disable_src_roll; - value<bool> tray_enabled, tray_start; - value<int> camera_yaw, camera_pitch, camera_roll; - value<bool> use_camera_offset_from_centering; - value<bool> center_at_startup; - value<int> center_method; - value<int> neck_y, 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; + 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 { 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 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.cpp b/logic/mappings.cpp index d7764375..57673540 100644 --- a/logic/mappings.cpp +++ b/logic/mappings.cpp @@ -1,20 +1,20 @@ #include "mappings.hpp" -Map::Map(QString primary, QString secondary, int max_x, int max_y, axis_opts& opts) : +#include <utility> + +Map::Map(const QString& spline_name, const QString& alt_spline_name, axis_opts& opts) : opts(opts), - name1(primary), - name2(secondary), - spline_main(max_x, max_y, primary), - spline_alt(max_x, max_y, secondary) + name(spline_name), + alt_name(alt_spline_name), + spline_main(spline_name, opts.prefix(), opts.axis()), + spline_alt(alt_spline_name, opts.prefix(), opts.axis()) { - spline_main.set_max_input(opts.clamp); - spline_alt.set_max_input(opts.clamp); } -void Map::save(QSettings& s) +void Map::save() { - spline_main.save(s); - spline_alt.save(s); + spline_main.save(); + spline_alt.save(); } void Map::load() @@ -23,13 +23,14 @@ void Map::load() spline_alt.reload(); } -Mappings::Mappings(std::vector<axis_opts*> opts) : + +Mappings::Mappings(axis_opts_impl::axis_opts** opts) : axes { - Map("spline-X", "alt-spline-X", 100, 75, *opts[TX]), - Map("spline-Y", "alt-spline-Y", 100, 75, *opts[TY]), - Map("spline-Z", "alt-spline-Z", 100, 75, *opts[TZ]), - Map("spline-yaw", "alt-spline-yaw", 180, 180, *opts[Yaw]), - Map("spline-pitch", "alt-spline-pitch", 180, 180, *opts[Pitch]), - Map("spline-roll", "alt-spline-roll", 180, 180, *opts[Roll]) + { "spline-X", "alt-spline-X", *opts[TX] }, + { "spline-Y", "alt-spline-Y", *opts[TY] }, + { "spline-Z", "alt-spline-Z", *opts[TZ] }, + { "spline-yaw", "alt-spline-yaw", *opts[Yaw] }, + { "spline-pitch", "alt-spline-pitch",*opts[Pitch] }, + { "spline-roll", "alt-spline-roll", *opts[Roll] } } {} diff --git a/logic/mappings.hpp b/logic/mappings.hpp index 4e0f7218..be7dd3a2 100644 --- a/logic/mappings.hpp +++ b/logic/mappings.hpp @@ -9,19 +9,18 @@ #include "export.hpp" #include "options/options.hpp" -using namespace options; #include "spline/spline.hpp" #include "main-settings.hpp" struct OTR_LOGIC_EXPORT Map final { - Map(QString primary, QString secondary, int max_x, int max_y, axis_opts& opts); + Map(const QString& spline_name, const QString& alt_spline_name, axis_opts& opts); - void save(QSettings& s); + void save(); void load(); axis_opts& opts; - QString name1, name2; + QString name, alt_name; spline spline_main, spline_alt; }; @@ -30,12 +29,10 @@ class OTR_LOGIC_EXPORT Mappings final private: Map axes[6]; public: - Mappings(std::vector<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 new file mode 100644 index 00000000..2e8efe55 --- /dev/null +++ b/logic/pipeline.cpp @@ -0,0 +1,690 @@ +/* Copyright (c) 2012-2018 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. + */ + +/* + * this file appeared originally in facetracknoir, was rewritten completely + * following opentrack fork. + * + * originally written by Wim Vriend. + */ + +#include "compat/sleep.hpp" +#include "compat/math.hpp" +#include "compat/meta.hpp" +#include "compat/macros.h" +#include "compat/thread-name.hpp" + +#include "pipeline.hpp" +#include "logic/shortcuts.h" + +#include <cmath> +#include <algorithm> +#include <cstdio> + +#ifdef _WIN32 +# include <windows.h> +# include <mmsystem.h> +#endif + +//#define DEBUG_TIMINGS +#ifdef DEBUG_TIMINGS +# include "compat/variance.hpp" +#endif + +namespace pipeline_impl { + +reltrans::reltrans() = default; + +void reltrans::on_center() +{ + interp_pos = { 0, 0, 0 }; + in_zone = false; + moving_to_reltans = false; +} + +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 Pose_ ret = R * Pose_(in(TZ), -in(TX), -in(TY)); + + Pose_ output; + + if (disable(TZ)) + output(TZ) = in(TZ); + else + output(TZ) = ret(tb_Z); + + if (disable(TY)) + output(TY) = in(TY); + else + output(TY) = -ret(tb_Y); + + if (disable(TX)) + output(TX) = in(TX); + else + output(TX) = -ret(tb_X); + + return output; +} + +Pose reltrans::apply_pipeline(reltrans_state state, const Pose& value, + const vec6_bool& disable, bool neck_enable, int neck_z) +{ + Pose_ rel((const double*)value); + + if (state != reltrans_disabled) + { + bool in_zone_ = true; + if (state == reltrans_non_center) + { + const bool looking_down = value(Pitch) < 20; + in_zone_ = looking_down ? std::fabs(value(Yaw)) > 35 : std::fabs(value(Yaw)) > 65; + } + + 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) + { + 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 && (state != reltrans_non_center || !in_zone)) + { + const Pose_ neck = apply_neck(R, -neck_z, disable(TZ)); + + for (unsigned k = 0; k < 3; k++) + rel(k) += neck(k); + } + } + + if (moving_to_reltans) + { + 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_stage + 1 < std::size(RC_stages) && + interp_phase_timer.elapsed_seconds() > RC_time_deltas[RC_stage]) + { + RC_stage++; + interp_phase_timer.start(); + } + + const double RC = RC_stages[RC_stage]; + const double alpha = dt/(dt+RC); + + constexpr double eps = .01; + + interp_pos = interp_pos * (1-alpha) + rel * alpha; + + const Pose_ tmp = rel - interp_pos; + rel = interp_pos; + const double delta = std::fabs(tmp(0)) + std::fabs(tmp(1)) + std::fabs(tmp(2)); + + //qDebug() << "reltrans-interp: delta" << delta << "phase" << RC_phase; + + if (delta < eps) + { + //qDebug() << "reltrans-interp: STOP"; + moving_to_reltans = false; + } + } + else + interp_pos = rel; + } + else + { + moving_to_reltans = false; + in_zone = false; + } + + return { + rel(TX), rel(TY), rel(TZ), + value(Yaw), value(Pitch), value(Roll), + }; +} + +Pose_ reltrans::apply_neck(const rmat& R, int nz, bool disable_tz) const +{ + Pose_ neck; + + neck = rotate(R, { 0, 0, nz }, {}); + neck(TZ) = neck(TZ) - nz; + + if (disable_tz) + neck(TZ) = 0; + + return neck; +} + +pipeline::pipeline(const Mappings& m, const runtime_libraries& libs, TrackLogger& logger) : + m(m), libs(libs), logger(logger) +{ +} + +pipeline::~pipeline() +{ + requestInterruption(); + wait(); +} + +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); + auto& fc = altp ? axis.spline_alt : axis.spline_main; + return fc.get_value(pos); +} + +template<int u, int w> +static inline bool is_nan(const dmat<u,w>& r) +{ + 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) + return true; + } + + return false; +} + +static never_inline +void emit_nan_check_msg(const char* text, const char* fun, int line) +{ + eval_once( + qDebug() << "nan check failed" + << "for:" << text + << "function:" << fun + << "line:" << line + ); +} + +template<typename... xs> +static never_inline +bool maybe_nan(const char* text, const char* fun, int line, const xs&... vals) +{ + bool ret = (is_nan(vals) || ... || false); + + if (ret) + emit_nan_check_msg(text, fun, line); + + return ret; +} + +#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() +{ + if (!tracking_started) + { + for (int i = 0; i < 6; i++) + if (std::fabs(newpose(i)) != 0) + { + tracking_started = true; + break; + } + + if (tracking_started && s.center_at_startup) + { + set_center(true); + return true; + } + } + + return false; +} + +void pipeline::maybe_set_center_pose(const centering_state mode, const Pose& value, bool own_center_logic) +{ + if (b.get(f_center | f_held_center)) + { + set_center(false); + + if (libs.pFilter) + libs.pFilter->center(); + + if (own_center_logic) + { + center.P = {}; + center.QC = QQuaternion(1,0,0,0); + center.QR = QQuaternion(1,0,0,0); + } + else + { + 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::apply_center(const centering_state mode, Pose value) const +{ + if (mode != center_disabled) + { + for (unsigned k = TX; k <= TZ; k++) + value(k) -= center.P(k); + + QQuaternion q; + QVector3D v; + + 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; + } + } + + for (int i = 0; i < 6; i++) + // don't invert after reltrans + // inverting here doesn't break centering + if (m(i).opts.invert_pre) + value(i) = -value(i); + + return value; +} + +std::tuple<Pose, Pose, vec6_bool> +pipeline::get_selected_axis_values(const Pose& newpose) const +{ + Pose value; + vec6_bool disabled; + + for (int i = 0; i < 6; i++) + { + const Map& axis = m(i); + const int k = axis.opts.src; + + disabled(i) = k == 6; + + if (k < 0 || k >= 6) + value(i) = 0; + else + value(i) = newpose(k); + } + + return { newpose, value, disabled }; +} + +Pose pipeline::maybe_apply_filter(const Pose& value) const +{ + Pose tmp(value); + + // nan/inf values will corrupt filter internal state + if (libs.pFilter) + libs.pFilter->filter(value, tmp); + + return tmp; +} + +Pose pipeline::apply_zero_pos(Pose value) const +{ + for (int i = 0; i < 6; i++) + value(i) += m(i).opts.zero * (m(i).opts.invert_pre ? -1 : 1); + + return value; +} + +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_tx, + !!s.reltrans_disable_ty, + !!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); + + // reltrans will move it + for (unsigned k = 0; k < 6; k++) + if (disabled(k)) + value(k) = 0; + + return value; +} + +void pipeline::logic() +{ + using namespace euler; + + logger.write_dt(); + logger.reset_dt(); + + // we must center prior to getting data from the tracker + const bool center_ordered = b.get(f_center | f_held_center) && tracking_started; + const bool own_center_logic = center_ordered && libs.pTracker->center(); + const bool hold_ordered = b.get(f_enabled_p) ^ b.get(f_enabled_h); + + { + Pose tmp; + libs.pTracker->data(tmp); + newpose = tmp; + } + + auto [raw, value, disabled] = get_selected_axis_values(newpose); + logger.write_pose(raw); // raw + + nan_check(newpose, raw, value); + + { + maybe_enable_center_on_tracking_started(); + 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); + } + + { + // 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" + } + + { + // 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, center_ordered); + + { + // CAVEAT translation only, due to tcomp + for (int i = 0; i < 3; i++) + value(i) = map(value(i), m(i)); + nan_check(value); + } + + goto ok; + +error: + { + QMutexLocker foo(&mtx); + + value = last_value; + raw = raw_6dof; + + // for widget last value display + for (int i = 0; i < 6; i++) + (void)map(raw_6dof(i), m(i)); + } + +ok: + + set_center(false); + + 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); + + 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; + raw_6dof = raw; + + logger.write_pose(value); // "mapped" + + logger.reset_dt(); + 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[16]; + for (unsigned j = 1; j < 5; ++j) // NOLINT(modernize-loop-convert) + { + for (unsigned i = 0; i < 6; ++i) // NOLINT(modernize-loop-convert) + { + std::sprintf(buffer, "%s%s", datachannels[j], posechannels[i]); + logger.write(buffer); + } + } + logger.next_line(); + } + + logger.reset_dt(); + + t.start(); + + while (!isInterruptionRequested()) + { + logic(); + + constexpr ms interval{4}; + backlog_time += ms{t.elapsed_ms()} - interval; + t.start(); + + if (std::chrono::abs(backlog_time) > secs(3)) + { + qDebug() << "tracker: backlog interval overflow" + << ms{backlog_time}.count() << "ms"; + backlog_time = {}; + } + + const int sleep_ms = (int)std::clamp(interval - backlog_time, ms{0}, ms{10}).count(); + +#ifdef DEBUG_TIMINGS + debug_timings(backlog_time.count(), sleep_ms); +#endif + portable::sleep(sleep_ms); + } + + // filter may inhibit exact origin + Pose p; + libs.pProtocol->pose(p, p); + + for (int i = 0; i < 6; i++) + { + m(i).spline_main.set_tracking_active(false); + m(i).spline_alt.set_tracking_active(false); + } + +#if defined _WIN32 + if (mmres == 0) + (void) timeEndPeriod(1); +#endif +} + +void pipeline::raw_and_mapped_pose(double* mapped, double* raw) const +{ + QMutexLocker foo(&mtx); + + for (int i = 0; i < 6; i++) + { + raw[i] = raw_6dof(i); + mapped[i] = output_pose(i); + } +} + +void pipeline::set_center(bool x) { b.set(f_center, x); } + +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::set_enabled(bool value) { b.set(f_enabled_h, value); } +void pipeline::set_zero(bool value) { b.set(f_zero, value); } + +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) +{ + QMutexLocker l(&lock); + + flags &= ~flag; + if (val) + flags |= flag; +} + +void bits::negate(bit_flags flag) +{ + QMutexLocker l(&lock); + + flags ^= flag; +} + +bool bits::get(bit_flags flag) +{ + QMutexLocker l(&lock); + + return !!(flags & flag); +} + +bits::bits() +{ + 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 new file mode 100644 index 00000000..a539525d --- /dev/null +++ b/logic/pipeline.hpp @@ -0,0 +1,142 @@ +#pragma once + +#include <vector> + +#include "compat/timer.hpp" +#include "api/plugin-support.hpp" +#include "mappings.hpp" +#include "compat/euler.hpp" +#include "compat/enum-operators.hpp" +#include "runtime-libraries.hpp" + +#include "spline/spline.hpp" +#include "main-settings.hpp" +#include "options/options.hpp" +#include "tracklogger.hpp" + +#include <QMutex> +#include <QThread> + +#include <atomic> +#include <cmath> +#include <QQuaternion> + +#include "export.hpp" + +namespace pipeline_impl { + +using namespace euler; +using namespace time_units; + +using vec6_bool = Mat<bool, 6, 1>; +using vec3_bool = Mat<bool, 6, 1>; + +class reltrans +{ + 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_stage = 0; + + bool moving_to_reltans = false; + bool in_zone = false; + +public: + reltrans(); + + void on_center(); + + 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); +}; + +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 +{ + bit_flags flags{0}; + QMutex lock; + + void set(bit_flags flag, bool val); + void negate(bit_flags flag); + bool get(bit_flags flag); + bits(); +}; + +DEFINE_ENUM_OPERATORS(bit_flags); + +class OTR_LOGIC_EXPORT pipeline : private QThread +{ + Q_OBJECT + + mutable QMutex mtx; + main_settings s; + const Mappings& m; + + Timer t; + Pose output_pose, raw_6dof, last_value; + + Pose newpose; + runtime_libraries const& libs; + // The owner of the reference is the main window. + // This design might be useful if we decide later on to swap out + // the logger while the tracker is running. + TrackLogger& logger; + + reltrans rel; + + struct { + Pose P; + QQuaternion QC = QQuaternion(1,0,0,0); + QQuaternion QR = QQuaternion(1,0,0,0); + } center; + + time_units::ms backlog_time {}; + + bool tracking_started = false; + + 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 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, bool centerp); + Pose apply_zero_pos(Pose value) const; + + void set_center(bool x); + + bits b; + +public: + 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); } + + void toggle_zero(); + void toggle_enabled(); + + void set_held_center(bool value); + void set_enabled(bool value); + void set_zero(bool value); +}; + +} // ns pipeline_impl + +using pipeline = pipeline_impl::pipeline; diff --git a/logic/runtime-libraries.cpp b/logic/runtime-libraries.cpp new file mode 100644 index 00000000..754f52cd --- /dev/null +++ b/logic/runtime-libraries.cpp @@ -0,0 +1,79 @@ +#include "runtime-libraries.hpp" +#include "options/scoped.hpp" +#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 = + error(tr("Library load failure")); + + using namespace options; + + with_tracker_teardown sentinel; + + pProtocol = make_dylib_instance<IProtocol>(p); + + if (!pProtocol) + { + qDebug() << "protocol dylib load failure"; + goto end; + } + + if(status = pProtocol->initialize(), !status.is_ok()) + { + status = error(tr("Error occurred while loading protocol %1\n\n%2\n") + .arg(p->name, status.error)); + goto end; + } + + pTracker = make_dylib_instance<ITracker>(t); + pFilter = make_dylib_instance<IFilter>(f); + + if (!pTracker) + { + qDebug() << "tracker dylib load failure"; + goto end; + } + + if (f && f->Constructor && !pFilter) + { + qDebug() << "filter load failure"; + goto end; + } + + if (pFilter) + if(status = pFilter->initialize(), !status.is_ok()) + { + 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(tr("Error occurred while loading tracker %1\n\n%2\n") + .arg(t->name, status.error)); + goto end; + } + + correct = true; + return; + +end: + pTracker = nullptr; + pFilter = nullptr; + pProtocol = nullptr; + + if (!status.is_ok()) + QMessageBox::critical(nullptr, + tr("Startup failure"), status.error, + QMessageBox::Cancel, QMessageBox::NoButton); +} + diff --git a/logic/runtime-libraries.hpp b/logic/runtime-libraries.hpp new file mode 100644 index 00000000..8c7fedd1 --- /dev/null +++ b/logic/runtime-libraries.hpp @@ -0,0 +1,32 @@ +/* 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 "api/plugin-support.hpp" +#include "compat/tr.hpp" +#include "export.hpp" + +class QFrame; + +class OTR_LOGIC_EXPORT runtime_libraries final : public TR +{ + Q_OBJECT + +public: + using dylibptr = std::shared_ptr<dylib>; + + std::shared_ptr<ITracker> pTracker; + std::shared_ptr<IFilter> pFilter; + std::shared_ptr<IProtocol> pProtocol; + + runtime_libraries(QFrame* frame, dylibptr t, dylibptr p, dylibptr f); + runtime_libraries() = default; + + bool correct = false; +}; diff --git a/logic/selected-libraries.cpp b/logic/selected-libraries.cpp deleted file mode 100644 index ffa3e496..00000000 --- a/logic/selected-libraries.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "selected-libraries.hpp" -#include "options/scoped.hpp" -#include <QDebug> - -SelectedLibraries::SelectedLibraries(QFrame* frame, dylibptr t, dylibptr p, dylibptr f) : - pTracker(nullptr), - pFilter(nullptr), - pProtocol(nullptr), - correct(false) -{ - using namespace options; - - const bool prev_teardown_flag = opts::is_tracker_teardown(); - - opts::set_teardown_flag(true); - - pProtocol = make_dylib_instance<IProtocol>(p); - - if (!pProtocol) - { - qDebug() << "protocol dylib load failure"; - goto end; - } - - if(!pProtocol->correct()) - { - qDebug() << "protocol load failure"; - pProtocol = nullptr; - goto end; - } - - pTracker = make_dylib_instance<ITracker>(t); - pFilter = make_dylib_instance<IFilter>(f); - - if (!pTracker) - { - qDebug() << "tracker dylib load failure"; - goto end; - } - - pTracker->start_tracker(frame); - - correct = true; -end: - opts::set_teardown_flag(prev_teardown_flag); -} diff --git a/logic/selected-libraries.hpp b/logic/selected-libraries.hpp deleted file mode 100644 index 689cbec3..00000000 --- a/logic/selected-libraries.hpp +++ /dev/null @@ -1,25 +0,0 @@ -/* 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 "api/plugin-support.hpp" -#include <QFrame> - -#include "export.hpp" - -struct OTR_LOGIC_EXPORT SelectedLibraries -{ - using dylibptr = mem<dylib>; - mem<ITracker> pTracker; - mem<IFilter> pFilter; - mem<IProtocol> pProtocol; - SelectedLibraries(QFrame* frame, dylibptr t, dylibptr p, dylibptr f); - SelectedLibraries() : pTracker(nullptr), pFilter(nullptr), pProtocol(nullptr), correct(false) {} - bool correct; -}; diff --git a/logic/shortcuts.cpp b/logic/shortcuts.cpp index 6d77c3e0..df21f7d2 100644 --- a/logic/shortcuts.cpp +++ b/logic/shortcuts.cpp @@ -29,9 +29,10 @@ void Shortcuts::free_binding(K& key) #endif } -void Shortcuts::bind_shortcut(K &key, const key_opts& k, unused_on_unix(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) { @@ -45,13 +46,18 @@ void Shortcuts::bind_shortcut(K &key, const key_opts& k, unused_on_unix(bool, he 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; @@ -62,48 +68,51 @@ void Shortcuts::bind_shortcut(K &key, const key_opts& k, unused_on_unix(bool, he } 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 = QStringLiteral(""); - 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() @@ -126,23 +135,24 @@ 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(true); }); + auto fn = std::get<1>(kk_); + 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 5f23d2e7..87926f66 100644 --- a/logic/shortcuts.h +++ b/logic/shortcuts.h @@ -11,7 +11,6 @@ #include "options/options.hpp" #include "main-settings.hpp" -#include "compat/util.hpp" #ifdef _WIN32 # include "dinput/keybinding-worker.hpp" @@ -25,12 +24,22 @@ #include <vector> #include <functional> +#if !defined __APPLE__ +# define OTR_HAS_KEY_UP_SUPPORT +#endif + +namespace shortcuts_impl { + using namespace options; -struct OTR_LOGIC_EXPORT Shortcuts final : public QObject +class OTR_LOGIC_EXPORT Shortcuts final : public QObject { Q_OBJECT +#ifdef _WIN32 + void receiver(const Key& k); +#endif + public: using K = #ifndef _WIN32 @@ -46,21 +55,18 @@ public: using t_keys = std::vector<t_key>; std::vector<tt> keys; #ifdef _WIN32 - KeybindingWorker::Token key_token; + KeybindingWorker::Token key_token {[this](const Key& k) { receiver(k); }}; #endif - Shortcuts() -#ifdef _WIN32 - : key_token([&](const Key& k) { receiver(k); }) -#endif - {} - ~Shortcuts(); + Shortcuts() = default; + ~Shortcuts() override; void reload(const t_keys& keys_); private: void free_binding(K& key); void bind_shortcut(K &key, const key_opts& k, bool held); -#ifdef _WIN32 - void receiver(const Key& k); -#endif }; + +} // ns shortcuts_impl + +using shortcuts_impl::Shortcuts; 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 f5892557..7fc06a5c 100644 --- a/logic/state.hpp +++ b/logic/state.hpp @@ -9,22 +9,31 @@ #pragma once #include "options/options.hpp" -using namespace options; #include "api/plugin-support.hpp" #include "main-settings.hpp" #include "mappings.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), - pose(std::vector<axis_opts*>{&s.a_x, &s.a_y, &s.a_z, &s.a_yaw, &s.a_pitch, &s.a_roll}) - {} + 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; main_settings s; + module_settings m; Mappings pose; - mem<Work> work; + std::shared_ptr<Work> work; + QString library_path; }; diff --git a/logic/tracker.cpp b/logic/tracker.cpp deleted file mode 100644 index 320053b9..00000000 --- a/logic/tracker.cpp +++ /dev/null @@ -1,487 +0,0 @@ -/* Copyright (c) 2012-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. - */ - -/* - * this file appeared originally in facetracknoir, was rewritten completely - * following opentrack fork. - * - * originally written by Wim Vriend. - */ - -#include "compat/sleep.hpp" -#include "compat/util.hpp" - -#include "tracker.h" - -#include <cmath> -#include <algorithm> -#include <cstdio> - -using namespace euler; -using namespace gui_tracker_impl; - -constexpr double Tracker::r2d; -constexpr double Tracker::d2r; - -Tracker::Tracker(Mappings& m, SelectedLibraries& libs, TrackLogger& logger) : - m(m), - libs(libs), - logger(logger), - backlog_time(0), - tracking_started(false) -{ -} - -Tracker::~Tracker() -{ - set(f_should_quit, true); - wait(); -} - -Tracker::rmat Tracker::get_camera_offset_matrix(double c) -{ - const double off[] = - { - d2r * c * (double)-s.camera_yaw, - d2r * c * (double)-s.camera_pitch, - d2r * c * (double)-s.camera_roll - }; - - return euler::euler_to_rmat(off); -} - -double Tracker::map(double pos, Map& axis) -{ - bool altp = (pos < 0) && axis.opts.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)); -} - -void Tracker::t_compensate(const rmat& rmat, const euler_t& xyz, euler_t& output, - bool disable_tx, bool disable_ty, bool disable_tz) -{ - 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 = rmat * euler_t(xyz(TZ), -xyz(TX), -xyz(TY)); - - if (disable_tz) - output(TZ) = xyz(TZ); - else - output(TZ) = ret(tb_Z); - - if (disable_ty) - output(TY) = xyz(TY); - else - output(TY) = -ret(tb_Y); - - if (disable_tx) - output(TX) = xyz(TX); - else - output(TX) = -ret(tb_X); -} - -#include "compat/nan.hpp" - -static inline double elide_nan(double value, double def) -{ - if (nanp(value)) - { - if (nanp(def)) - return 0; - return def; - } - return value; -} - -template<int u, int w> -static bool is_nan(const dmat<u,w>& r) -{ - for (int i = 0; i < u; i++) - for (int j = 0; j < w; j++) - if (nanp(r(i, j))) - return true; - - return false; -} - -constexpr double Tracker::c_mult; -constexpr double Tracker::c_div; - -void Tracker::logic() -{ - using namespace euler; - - logger.write_dt(); - logger.reset_dt(); - - const bool center_ordered = get(f_center) && tracking_started; - set(f_center, false); - const bool own_center_logic = center_ordered && libs.pTracker->center(); - - { - Pose tmp; - libs.pTracker->data(tmp); - - if (get(f_enabled)) - for (int i = 0; i < 6; i++) - newpose[i] = elide_nan(tmp(i), newpose(i)); - } - - Pose value, raw; - - for (int i = 0; i < 6; i++) - { - auto& axis = m(i); - int k = axis.opts.src; - if (k < 0 || k >= 6) - value(i) = 0; - else - value(i) = newpose(k); - raw(i) = newpose(i); - } - - // 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; - - 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); - } - - logger.write_pose(raw); // raw - - bool nanp = is_nan(raw) | is_nan(value); - - // TODO split this function, it's too big - - { - euler_t tmp = d2r * euler_t(&value[Yaw]); - scaled_rotation.rotation = euler_to_rmat(c_div * tmp); - real_rotation.rotation = euler_to_rmat(tmp); - } - - scaled_rotation.camera = get_camera_offset_matrix(c_div); - real_rotation.camera = get_camera_offset_matrix(1); - - nanp |= is_nan(value) || is_nan(scaled_rotation.rotation) || is_nan(real_rotation.rotation); - - if (!tracking_started) - { - using std::fabs; - - for (int i = 0; i < 6; i++) - if (fabs(newpose(i)) != 0) - { - tracking_started = true; - break; - } - - tracking_started &= !nanp; - - if (tracking_started && s.center_at_startup) - { - set(f_center, true); - } - } - - if (center_ordered) - { - if (libs.pFilter) - libs.pFilter->center(); - - if (own_center_logic) - { - scaled_rotation.rotation = rmat::eye(); - real_rotation.rotation = rmat::eye(); - } - else - { - real_rotation.rot_center = real_rotation.rotation.t(); - scaled_rotation.rot_center = scaled_rotation.rotation.t(); - } - - t_center = euler_t(&value(TX)); - } - - { - rmat rotation; - - switch (s.center_method) - { - // inertial - case 0: - default: - //scaled_rotation.rotation = scaled_rotation - rotation = scaled_rotation.rot_center * scaled_rotation.rotation; - break; - // camera - case 1: - rotation = scaled_rotation.rotation * scaled_rotation.rot_center; - break; - } - - euler_t rot = r2d * c_mult * rmat_to_euler(rotation); - euler_t pos = euler_t(&value[TX]) - t_center; - - for (int i = 0; i < 3; i++) - { - // don't invert after t_compensate - // inverting here doesn't break centering - - if (m(i+3).opts.invert) - rot(i) = -rot(i); - if (m(i).opts.invert) - pos(i) = -pos(i); - } - - t_compensate(real_rotation.camera.t(), pos, pos, false, false, false); - - for (int i = 0; i < 3; i++) - { - value(i) = pos(i); - value(i+3) = rot(i); - } - } - - logger.write_pose(value); // "corrected" - after various transformations to account for camera position - - nanp |= is_nan(value); - - { - { - Pose tmp(value); - - // nan/inf values will corrupt filter internal state - if (!nanp && libs.pFilter) - libs.pFilter->filter(tmp, value); - - logger.write_pose(value); // "filtered" - } - } - - nanp |= is_nan(value); - - { - euler_t neck, rel; - - if (s.neck_enable) - { - double ny = s.neck_y, nz = -s.neck_z; - - if (ny != 0 || nz != 0) - { - const rmat R = euler_to_rmat( - euler_t(value(Yaw) * d2r, - value(Pitch) * d2r, - value(Roll) * d2r)); - euler_t xyz(0, ny, nz); - t_compensate(R, xyz, xyz, false, false, false); - neck(TX) = xyz(TX); - neck(TY) = xyz(TY) - ny; - neck(TZ) = xyz(TZ) - nz; - } - } - - // CAVEAT rotation only, due to tcomp - for (int i = 3; i < 6; i++) - value(i) = map(value(i), m(i)); - - const bool reltrans = !get(f_tcomp_disabled); - - if (s.tcomp_p && reltrans) - { - const double tcomp_c[] = - { - double(!s.tcomp_disable_src_yaw), - double(!s.tcomp_disable_src_pitch), - double(!s.tcomp_disable_src_roll), - }; - const rmat R = euler_to_rmat( - euler_t(value(Yaw) * d2r * tcomp_c[0], - value(Pitch) * d2r * tcomp_c[1], - value(Roll) * d2r * tcomp_c[2])); - euler_t ret; - t_compensate(R, - euler_t(value(TX), value(TY), value(TZ)), - ret, - s.tcomp_disable_tx, - s.tcomp_disable_ty, - s.tcomp_disable_tz); - - for (int i = 0; i < 3; i++) - rel(i) = ret(i) - value(i); - } - - // don't t_compensate existing compensated values - for (int i = 0; i < 3; i++) - value(i) += neck(i) + rel(i); - - nanp |= is_nan(neck) | is_nan(rel) | is_nan(value); - } - - // CAVEAT translation only, due to tcomp - for (int i = 0; i < 3; i++) - value(i) = map(value(i), m(i)); - - if (nanp) - { - QMutexLocker foo(&mtx); - - value = output_pose; - raw = raw_6dof; - - // for widget last value display - for (int i = 0; i < 6; i++) - (void) map(raw_6dof(i), m(i)); - } - - if (get(f_zero)) - for (int i = 0; i < 6; i++) - value(i) = 0; - - // custom zero position - for (int i = 0; i < 6; i++) - value(i) += m(i).opts.zero * (m(i).opts.invert ? -1 : 1); - - if (!nanp) - libs.pProtocol->pose(value); - - QMutexLocker foo(&mtx); - output_pose = value; - raw_6dof = raw; - - logger.write_pose(value); // "mapped" - - logger.reset_dt(); - logger.next_line(); -} - -void Tracker::run() -{ - setPriority(QThread::HighPriority); - - { - static constexpr const char* posechannels[6] = { "TX", "TY", "TZ", "Yaw", "Pitch", "Roll" }; - static constexpr const char* datachannels[5] = { "dt", "raw", "corrected", "filtered", "mapped" }; - logger.write(datachannels[0]); - char buffer[128]; - for (unsigned j = 1; j < 5; ++j) - { - for (unsigned i = 0; i < 6; ++i) - { - std::sprintf(buffer, "%s%s", datachannels[j], posechannels[i]); - logger.write(buffer); - } - } - logger.next_line(); - } - - logger.reset_dt(); - - t.start(); - - while (!get(f_should_quit)) - { - logic(); - - static constexpr long const_sleep_us = 4000; - const long elapsed_usecs = t.elapsed_usecs(); - t.start(); - - backlog_time += elapsed_usecs - const_sleep_us; - - if (std::fabs(backlog_time) > 3000 * 1000) - { - qDebug() << "tracker: backlog interval overflow" << backlog_time; - backlog_time = 0; - } - - const unsigned sleep_time = unsigned(std::round(clamp((const_sleep_us - backlog_time)/1000., 0, const_sleep_us*2.5/1000))); - - portable::sleep(sleep_time); - } - - { - // filter may inhibit exact origin - Pose p; - libs.pProtocol->pose(p); - } - - for (int i = 0; i < 6; i++) - { - m(i).spline_main.set_tracking_active(false); - m(i).spline_alt.set_tracking_active(false); - } -} - -void Tracker::get_raw_and_mapped_poses(double* mapped, double* raw) const -{ - QMutexLocker foo(&const_cast<Tracker&>(*this).mtx); - - for (int i = 0; i < 6; i++) - { - raw[i] = raw_6dof(i); - mapped[i] = output_pose(i); - } -} - - -void bits::set(bits::flags flag_, bool val_) -{ - const unsigned flag = unsigned(flag_); - const unsigned val = unsigned(val_); - - 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; - } -} - -void bits::negate(bits::flags flag_) -{ - const unsigned flag = unsigned(flag_); - - for (;;) - { - unsigned b_(b); - - if (b.compare_exchange_weak(b_, - b_ ^ flag, - std::memory_order_seq_cst, - std::memory_order_seq_cst)) - break; - } -} - -bool bits::get(bits::flags flag) -{ - return !!(b & flag); -} - -bits::bits() : b(0u) -{ - set(f_center, true); - set(f_enabled, true); - set(f_zero, false); - set(f_tcomp_disabled, false); - set(f_should_quit, false); -} diff --git a/logic/tracker.h b/logic/tracker.h deleted file mode 100644 index 754a836c..00000000 --- a/logic/tracker.h +++ /dev/null @@ -1,124 +0,0 @@ -/* 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> - -#include "compat/timer.hpp" -#include "api/plugin-support.hpp" -#include "mappings.hpp" -#include "compat/euler.hpp" -#include "selected-libraries.hpp" - -#include "spline/spline.hpp" -#include "main-settings.hpp" -#include "options/options.hpp" -#include "tracklogger.hpp" - -#include <QMutex> -#include <QThread> - -#include <atomic> -#include <cmath> - -#include "export.hpp" - -namespace gui_tracker_impl { - -using Pose = Mat<double, 6, 1>; - -struct bits -{ - enum flags { - f_center = 1 << 0, - f_enabled = 1 << 1, - f_zero = 1 << 2, - f_tcomp_disabled = 1 << 3, - f_should_quit = 1 << 4, - }; - - std::atomic<unsigned> b; - - void set(flags flag_, bool val_); - void negate(flags flag_); - bool get(flags flag); - bits(); -}; - -class OTR_LOGIC_EXPORT Tracker : private QThread, private bits -{ - Q_OBJECT -private: - using rmat = euler::rmat; - using euler_t = euler::euler_t; - - QMutex mtx; - main_settings s; - Mappings& m; - - Timer t; - Pose output_pose, raw_6dof, last_mapped, last_raw; - - Pose newpose; - SelectedLibraries const& libs; - // The owner of the reference is the main window. - // This design might be usefull if we decide later on to swap out - // the logger while the tracker is running. - TrackLogger& logger; - - struct state - { - rmat rot_center; - rmat camera; - rmat rotation; - - state() : rot_center(rmat::eye()) - {} - }; - - state real_rotation, scaled_rotation; - euler_t t_center; - - long backlog_time; - - bool tracking_started; - - double map(double pos, Map& axis); - void logic(); - void t_compensate(const rmat& rmat, const euler_t& ypr, euler_t& output, - bool disable_tx, bool disable_ty, bool disable_tz); - void run() override; - - static constexpr double r2d = 180. / M_PI; - static constexpr double d2r = M_PI / 180.; - - // note: float exponent base is 2 - static constexpr double c_mult = 16; - static constexpr double c_div = 1./c_mult; -public: - Tracker(Mappings& m, SelectedLibraries& libs, TrackLogger& logger); - ~Tracker(); - - rmat get_camera_offset_matrix(double c); - void get_raw_and_mapped_poses(double* mapped, double* raw) const; - void start() { QThread::start(); } - - void center() { set(f_center, true); } - - void set_toggle(bool value) { set(f_enabled, value); } - void set_zero(bool value) { set(f_zero, value); } - void set_tcomp_disabled(bool x) { set(f_tcomp_disabled, x); } - - void zero() { negate(f_zero); } - void toggle_enabled() { negate(f_enabled); } -}; - -} // ns impl - -using gui_tracker_impl::Tracker; diff --git a/logic/tracklogger.cpp b/logic/tracklogger.cpp index 64dda579..758c2478 100644 --- a/logic/tracklogger.cpp +++ b/logic/tracklogger.cpp @@ -1,7 +1,14 @@ #include "tracklogger.hpp" -#include "tracker.h" +#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 114bb46d..cb4f99b3 100644 --- a/logic/win32-shortcuts.cpp +++ b/logic/win32-shortcuts.cpp @@ -7,141 +7,132 @@ */ #if defined(_WIN32) -# ifndef DIRECTINPUT_VERSION -# define DIRECTINPUT_VERSION 0x800 -# endif +# undef DIRECTINPUT_VERSION +# define DIRECTINPUT_VERSION 0x800 # include <dinput.h> #include "win32-shortcuts.h" -#include <QList> #include <QVariant> #include <QDebug> -QList<win_key> windows_key_mods = - QList<win_key>({ - win_key(DIK_LCONTROL, Qt::Key::Key_Control), - win_key(DIK_RCONTROL, Qt::Key::Key_Control), - win_key(DIK_LALT, Qt::Key::Key_Alt), - win_key(DIK_RALT, Qt::Key::Key_Alt), - win_key(DIK_LSHIFT, Qt::Key::Key_Shift), - win_key(DIK_RSHIFT, Qt::Key::Key_Shift), - win_key(DIK_LWIN, Qt::Key::Key_unknown), - win_key(DIK_RWIN, Qt::Key::Key_unknown) - }); +#if 0 +win_key const windows_key_mods[] { + {DIK_LCONTROL, Qt::Key_Control}, + {DIK_RCONTROL, Qt::Key_Control}, + {DIK_LALT, Qt::Key_Alt}, + {DIK_RALT, Qt::Key_Alt}, + {DIK_LSHIFT, Qt::Key_Shift}, + {DIK_RSHIFT, Qt::Key_Shift}, + {DIK_LWIN, Qt::Key_Super_L}, + {DIK_RWIN, Qt::Key_Super_R}, +}; +#endif -QList<win_key> windows_key_sequences = - QList<win_key>({ - win_key(DIK_F1, Qt::Key::Key_F1 ), - win_key(DIK_F2, Qt::Key::Key_F2 ), - win_key(DIK_F3, Qt::Key::Key_F3 ), - win_key(DIK_F4, Qt::Key::Key_F4 ), - win_key(DIK_F5, Qt::Key::Key_F5 ), - win_key(DIK_F6, Qt::Key::Key_F6 ), - win_key(DIK_F7, Qt::Key::Key_F7 ), - win_key(DIK_F8, Qt::Key::Key_F8 ), - win_key(DIK_F9, Qt::Key::Key_F9 ), - win_key(DIK_F10, Qt::Key::Key_F10 ), - win_key(DIK_F11, Qt::Key::Key_F11 ), - win_key(DIK_F12, Qt::Key::Key_F12 ), - win_key(DIK_LEFT, Qt::Key::Key_Left ), - win_key(DIK_RIGHT, Qt::Key::Key_Right ), - win_key(DIK_UP, Qt::Key::Key_Up ), - win_key(DIK_DOWN, Qt::Key::Key_Down ), - win_key(DIK_PRIOR, Qt::Key::Key_PageUp ), - win_key(DIK_NEXT, Qt::Key::Key_PageDown ), - win_key(DIK_HOME, Qt::Key::Key_Home ), - win_key(DIK_END, Qt::Key::Key_End ), - win_key(DIK_BACK, Qt::Key::Key_Backspace ), - win_key(DIK_COMMA, Qt::Key::Key_Comma ), - win_key(DIK_PERIOD, Qt::Key::Key_Period ), - win_key(DIK_LBRACKET, Qt::Key::Key_BracketLeft ), - win_key(DIK_RBRACKET, Qt::Key::Key_BracketRight ), - win_key(DIK_SEMICOLON, Qt::Key::Key_Semicolon ), - win_key(DIK_SLASH, Qt::Key::Key_Slash ), - win_key(DIK_BACKSLASH, Qt::Key::Key_Backslash ), - win_key(DIK_BACKSPACE, Qt::Key::Key_Backspace ), - win_key(DIK_APOSTROPHE, Qt::Key::Key_Apostrophe ), - win_key(DIK_GRAVE, Qt::Key::Key_QuoteLeft ), - win_key(DIK_MINUS, Qt::Key::Key_Minus ), - win_key(DIK_EQUALS, Qt::Key::Key_Equal ), - win_key(DIK_PERIOD, Qt::Key::Key_Period ), - win_key(DIK_F1, Qt::Key::Key_F1 ), - win_key(DIK_F2, Qt::Key::Key_F2 ), - win_key(DIK_F3, Qt::Key::Key_F3 ), - win_key(DIK_F4, Qt::Key::Key_F4 ), - win_key(DIK_F5, Qt::Key::Key_F5 ), - win_key(DIK_F6, Qt::Key::Key_F6 ), - win_key(DIK_F7, Qt::Key::Key_F7 ), - win_key(DIK_F8, Qt::Key::Key_F8 ), - win_key(DIK_F9, Qt::Key::Key_F9 ), - win_key(DIK_F10, Qt::Key::Key_F10 ), - win_key(DIK_F11, Qt::Key::Key_F11 ), - win_key(DIK_F12, Qt::Key::Key_F12 ), - win_key(DIK_0, Qt::Key::Key_0 ), - win_key(DIK_1, Qt::Key::Key_1 ), - win_key(DIK_2, Qt::Key::Key_2 ), - win_key(DIK_3, Qt::Key::Key_3 ), - win_key(DIK_4, Qt::Key::Key_4 ), - win_key(DIK_5, Qt::Key::Key_5 ), - win_key(DIK_6, Qt::Key::Key_6 ), - win_key(DIK_7, Qt::Key::Key_7 ), - win_key(DIK_8, Qt::Key::Key_8 ), - win_key(DIK_9, Qt::Key::Key_9 ), - win_key(DIK_A, Qt::Key::Key_A ), - win_key(DIK_B, Qt::Key::Key_B ), - win_key(DIK_C, Qt::Key::Key_C ), - win_key(DIK_D, Qt::Key::Key_D ), - win_key(DIK_E, Qt::Key::Key_E ), - win_key(DIK_F, Qt::Key::Key_F ), - win_key(DIK_G, Qt::Key::Key_G ), - win_key(DIK_H, Qt::Key::Key_H ), - win_key(DIK_I, Qt::Key::Key_I ), - win_key(DIK_J, Qt::Key::Key_J ), - win_key(DIK_K, Qt::Key::Key_K ), - win_key(DIK_L, Qt::Key::Key_L ), - win_key(DIK_M, Qt::Key::Key_M ), - win_key(DIK_N, Qt::Key::Key_N ), - win_key(DIK_O, Qt::Key::Key_O ), - win_key(DIK_P, Qt::Key::Key_P ), - win_key(DIK_Q, Qt::Key::Key_Q ), - win_key(DIK_R, Qt::Key::Key_R ), - win_key(DIK_S, Qt::Key::Key_S ), - win_key(DIK_T, Qt::Key::Key_T ), - win_key(DIK_U, Qt::Key::Key_U ), - win_key(DIK_V, Qt::Key::Key_V ), - win_key(DIK_W, Qt::Key::Key_W ), - win_key(DIK_X, Qt::Key::Key_X ), - win_key(DIK_Y, Qt::Key::Key_Y ), - win_key(DIK_Z, Qt::Key::Key_Z ), - win_key(DIK_RETURN, Qt::Key::Key_Return), - win_key(DIK_INSERT, Qt::Key::Key_Insert), - win_key(DIK_DELETE, Qt::Key::Key_Delete), - win_key(DIK_SPACE, Qt::Key::Key_Space), - win_key(DIK_SYSRQ, Qt::Key::Key_Print), - win_key(DIK_SCROLL, Qt::Key::Key_ScrollLock), - win_key(DIK_PAUSE, Qt::Key::Key_Pause), - win_key(DIK_NUMLOCK, Qt::Key::Key_NumLock), -#define mod(x, y) static_cast<Qt::Key>(x | y) - win_key(DIK_NUMPAD0, mod(Qt::Key::Key_0, Qt::KeypadModifier)), - win_key(DIK_NUMPAD0, mod(Qt::Key::Key_0, Qt::KeypadModifier)), - win_key(DIK_NUMPAD1, mod(Qt::Key::Key_1, Qt::KeypadModifier)), - win_key(DIK_NUMPAD2, mod(Qt::Key::Key_2, Qt::KeypadModifier)), - win_key(DIK_NUMPAD3, mod(Qt::Key::Key_3, Qt::KeypadModifier)), - win_key(DIK_NUMPAD4, mod(Qt::Key::Key_4, Qt::KeypadModifier)), - win_key(DIK_NUMPAD5, mod(Qt::Key::Key_5, Qt::KeypadModifier)), - win_key(DIK_NUMPAD6, mod(Qt::Key::Key_6, Qt::KeypadModifier)), - win_key(DIK_NUMPAD7, mod(Qt::Key::Key_7, Qt::KeypadModifier)), - win_key(DIK_NUMPAD8, mod(Qt::Key::Key_8, Qt::KeypadModifier)), - win_key(DIK_NUMPAD9, mod(Qt::Key::Key_9, Qt::KeypadModifier)), - win_key(DIK_NUMPADCOMMA, mod(Qt::Key::Key_Comma, Qt::KeypadModifier)), - win_key(DIK_NUMPADENTER, mod(Qt::Key::Key_Enter, Qt::KeypadModifier)), - win_key(DIK_NUMPADEQUALS, mod(Qt::Key::Key_Equal, Qt::KeypadModifier)), - win_key(DIK_NUMPADMINUS, mod(Qt::Key::Key_Minus, Qt::KeypadModifier)), - win_key(DIK_NUMPADPERIOD, mod(Qt::Key::Key_Period, Qt::KeypadModifier)), - win_key(DIK_NUMPADPLUS, mod(Qt::Key::Key_Plus, Qt::KeypadModifier)), - win_key(DIK_NUMPADSLASH, mod(Qt::Key::Key_Slash, Qt::KeypadModifier)), - win_key(DIK_NUMPADSTAR, mod(Qt::Key::Key_multiply, Qt::KeypadModifier)), - }); +static const win_key windows_key_sequences[] { + { 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_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 }, + { DIK_DOWN, Qt::Key_Down }, + { DIK_PRIOR, Qt::Key_PageUp }, + { DIK_NEXT, Qt::Key_PageDown }, + { DIK_HOME, Qt::Key_Home }, + { DIK_END, Qt::Key_End }, + { DIK_BACK, Qt::Key_Backspace }, + { DIK_COMMA, Qt::Key_Comma }, + { DIK_PERIOD, Qt::Key_Period }, + { DIK_LBRACKET, Qt::Key_BracketLeft }, + { DIK_RBRACKET, Qt::Key_BracketRight }, + { DIK_SEMICOLON, Qt::Key_Semicolon }, + { DIK_SLASH, Qt::Key_Slash }, + { DIK_BACKSLASH, Qt::Key_Backslash }, + { DIK_BACKSPACE, Qt::Key_Backspace }, + { DIK_APOSTROPHE, Qt::Key_Apostrophe }, + { DIK_GRAVE, Qt::Key_QuoteLeft }, + { DIK_MINUS, Qt::Key_Minus }, + { DIK_EQUALS, Qt::Key_Equal }, + { DIK_PERIOD, Qt::Key_Period }, + { DIK_0, Qt::Key_0 }, + { DIK_1, Qt::Key_1 }, + { DIK_2, Qt::Key_2 }, + { DIK_3, Qt::Key_3 }, + { DIK_4, Qt::Key_4 }, + { DIK_5, Qt::Key_5 }, + { DIK_6, Qt::Key_6 }, + { DIK_7, Qt::Key_7 }, + { DIK_8, Qt::Key_8 }, + { DIK_9, Qt::Key_9 }, + { DIK_A, Qt::Key_A }, + { DIK_B, Qt::Key_B }, + { DIK_C, Qt::Key_C }, + { DIK_D, Qt::Key_D }, + { DIK_E, Qt::Key_E }, + { DIK_F, Qt::Key_F }, + { DIK_G, Qt::Key_G }, + { DIK_H, Qt::Key_H }, + { DIK_I, Qt::Key_I }, + { DIK_J, Qt::Key_J }, + { DIK_K, Qt::Key_K }, + { DIK_L, Qt::Key_L }, + { DIK_M, Qt::Key_M }, + { DIK_N, Qt::Key_N }, + { DIK_O, Qt::Key_O }, + { DIK_P, Qt::Key_P }, + { DIK_Q, Qt::Key_Q }, + { DIK_R, Qt::Key_R }, + { DIK_S, Qt::Key_S }, + { DIK_T, Qt::Key_T }, + { DIK_U, Qt::Key_U }, + { DIK_V, Qt::Key_V }, + { DIK_W, Qt::Key_W }, + { DIK_X, Qt::Key_X }, + { DIK_Y, Qt::Key_Y }, + { DIK_Z, Qt::Key_Z }, + { DIK_TAB, Qt::Key_Tab }, + { DIK_RETURN, Qt::Key_Return}, + { DIK_INSERT, Qt::Key_Insert}, + { DIK_DELETE, Qt::Key_Delete}, + { DIK_SPACE, Qt::Key_Space}, + { DIK_SYSRQ, Qt::Key_Print}, + { DIK_SCROLL, Qt::Key_ScrollLock}, + { DIK_PAUSE, Qt::Key_Pause}, + { DIK_NUMLOCK, Qt::Key_NumLock}, + { DIK_CAPSLOCK, Qt::Key_CapsLock}, +#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) { @@ -160,32 +151,33 @@ 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) { - const auto key_ = qt; - for (auto& wk : windows_key_sequences) + if (unsigned(wk.qt) == qt) { - if (wk.qt == key_) - { - dik = wk.win; - mods = Qt::NoModifier; - return true; - } + dik = wk.win; + mods = Qt::NoModifier; + return true; } } + { const unsigned key = qt & ~Qt::KeyboardModifierMask; - for (auto& wk : windows_key_sequences) + for (const win_key& wk : windows_key_sequences) { - if (wk.qt == key) + 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 4e32c9ea..afc909ed 100644 --- a/logic/win32-shortcuts.h +++ b/logic/win32-shortcuts.h @@ -2,23 +2,19 @@ #ifdef _WIN32 +#include <Qt> #include <QKeySequence> #include "shortcuts.h" -struct win_key; - -extern QList<win_key> windows_key_mods; -extern QList<win_key> windows_key_sequences; - #include "export.hpp" 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 7b9e550e..8c6a3a62 100644 --- a/logic/work.cpp +++ b/logic/work.cpp @@ -1,11 +1,12 @@ #include "work.hpp" -#include "opentrack-library-path.h" +#include "compat/library-path.hpp" + +#include <utility> #include <QObject> #include <QMessageBox> #include <QFileDialog> - QString Work::browse_datalogging_file(main_settings &s) { QString filename = s.tracklogging_filename; @@ -17,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, - QCoreApplication::translate("Work", "Select filename"), + tr("Select filename"), filename, - QCoreApplication::translate("Work", "CSV File (*.csv)"), + tr("CSV File (*.csv)"), nullptr); if (!newfilename.isEmpty()) { @@ -30,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, QCoreApplication::translate("Work", "Logging error"), - QCoreApplication::translate("Work", "Unable to open file '%1'. Proceeding without logging.").arg(s.tracklogging_filename), - QMessageBox::Ok, - QMessageBox::NoButton); + QMessageBox::warning(nullptr, + 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, QFrame* frame, mem<dylib> tracker_, mem<dylib> filter_, mem<dylib> proto_) : - libs(frame, tracker_, filter_, proto_), - logger(make_logger(s)), - tracker(std::make_shared<Tracker>(m, libs, *logger)), - sc(std::make_shared<Shortcuts>()), - keys { - key_tuple(s.key_center1, [&](bool) -> void { tracker->center(); }, true), - key_tuple(s.key_center2, [&](bool) -> void { tracker->center(); }, true), - key_tuple(s.key_toggle1, [&](bool) -> void { tracker->toggle_enabled(); }, true), - key_tuple(s.key_toggle2, [&](bool) -> void { tracker->toggle_enabled(); }, true), - - key_tuple(s.key_zero1, [&](bool) -> void { tracker->zero(); }, true), - key_tuple(s.key_zero2, [&](bool) -> void { tracker->zero(); }, true), + return std::make_unique<TrackLogger>(); +} - key_tuple(s.key_toggle_press1, [&](bool x) -> void { tracker->set_toggle(!x); }, false), - key_tuple(s.key_toggle_press2, [&](bool x) -> void { tracker->set_toggle(!x); }, false), - key_tuple(s.key_zero_press1, [&](bool x) -> void { tracker->set_zero(x); }, false), - key_tuple(s.key_zero_press2, [&](bool x) -> void { 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 @@ -98,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 = SelectedLibraries(); + //sc = nullptr; + //pipeline = nullptr; + //libs = runtime_libraries(); } +#endif diff --git a/logic/work.hpp b/logic/work.hpp index f1d5e401..ef839257 100644 --- a/logic/work.hpp +++ b/logic/work.hpp @@ -10,12 +10,13 @@ #include "main-settings.hpp" #include "api/plugin-support.hpp" -#include "tracker.h" +#include "pipeline.hpp" #include "shortcuts.h" #include "export.hpp" #include "tracklogger.hpp" -#include "logic/selected-libraries.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 - SelectedLibraries libs; // idem - std::shared_ptr<TrackLogger> logger; // must come before tracker, since tracker depends on it - std::shared_ptr<Tracker> tracker; - std::shared_ptr<Shortcuts> sc; - std::vector<key_tuple> keys; - - Work(Mappings& m, QFrame* frame, mem<dylib> tracker, mem<dylib> filter, mem<dylib> proto); - ~Work(); + main_settings s; // pipeline needs settings, so settings must come before it + runtime_libraries libs; // idem + 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), + + 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); }; |
