summaryrefslogtreecommitdiffhomepage
path: root/logic
diff options
context:
space:
mode:
Diffstat (limited to 'logic')
-rw-r--r--logic/CMakeLists.txt6
-rw-r--r--logic/lang/de_DE.ts64
-rw-r--r--logic/lang/nl_NL.ts36
-rw-r--r--logic/lang/ru_RU.ts36
-rw-r--r--logic/lang/stub.ts36
-rw-r--r--logic/lang/zh_CN.ts64
-rw-r--r--logic/main-settings.cpp85
-rw-r--r--logic/main-settings.hpp138
-rw-r--r--logic/mappings.cpp35
-rw-r--r--logic/mappings.hpp11
-rw-r--r--logic/pipeline.cpp690
-rw-r--r--logic/pipeline.hpp142
-rw-r--r--logic/runtime-libraries.cpp79
-rw-r--r--logic/runtime-libraries.hpp32
-rw-r--r--logic/selected-libraries.cpp46
-rw-r--r--logic/selected-libraries.hpp25
-rw-r--r--logic/shortcuts.cpp88
-rw-r--r--logic/shortcuts.h30
-rw-r--r--logic/state.cpp57
-rw-r--r--logic/state.hpp25
-rw-r--r--logic/tracker.cpp487
-rw-r--r--logic/tracker.h124
-rw-r--r--logic/tracklogger.cpp11
-rw-r--r--logic/tracklogger.hpp39
-rw-r--r--logic/win32-shortcuts.cpp276
-rw-r--r--logic/win32-shortcuts.h12
-rw-r--r--logic/work.cpp73
-rw-r--r--logic/work.hpp52
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 &apos;%1&apos;. Proceeding without logging.</source>
+ <translation>Datei &apos;%1&apos; 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 &apos;%1&apos;. 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 &apos;%1&apos;. 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 &apos;%1&apos;. 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 &apos;%1&apos;. Proceeding without logging.</source>
+ <translation type="unfinished">未能打开文件 &apos;%1&apos;. 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);
};