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