diff options
Diffstat (limited to 'opentrack')
-rw-r--r-- | opentrack/ftnoir_keyboardshortcuts.ui | 210 | ||||
-rw-r--r-- | opentrack/global-shortcuts.cpp | 68 | ||||
-rw-r--r-- | opentrack/main-settings.hpp | 15 | ||||
-rw-r--r-- | opentrack/mappings.hpp | 49 | ||||
-rw-r--r-- | opentrack/mingw-version-script.txt | 8 | ||||
-rw-r--r-- | opentrack/options.hpp | 123 | ||||
-rw-r--r-- | opentrack/plugin-support.cpp | 71 | ||||
-rw-r--r-- | opentrack/plugin-support.h | 17 | ||||
-rw-r--r-- | opentrack/pose.hpp | 24 | ||||
-rw-r--r-- | opentrack/posix-version-script.txt | 8 | ||||
-rw-r--r-- | opentrack/quat.hpp | 66 | ||||
-rw-r--r-- | opentrack/shortcuts.cpp | 117 | ||||
-rw-r--r-- | opentrack/shortcuts.h | 97 | ||||
-rw-r--r-- | opentrack/simple-mat.hpp | 155 | ||||
-rw-r--r-- | opentrack/state.hpp | 23 | ||||
-rw-r--r-- | opentrack/timer.hpp | 11 | ||||
-rw-r--r-- | opentrack/tracker.cpp | 216 | ||||
-rw-r--r-- | opentrack/tracker.h | 41 | ||||
-rw-r--r-- | opentrack/work.hpp | 18 |
19 files changed, 684 insertions, 653 deletions
diff --git a/opentrack/ftnoir_keyboardshortcuts.ui b/opentrack/ftnoir_keyboardshortcuts.ui deleted file mode 100644 index f576d8fb..00000000 --- a/opentrack/ftnoir_keyboardshortcuts.ui +++ /dev/null @@ -1,210 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>UICKeyboardShortcutDialog</class> - <widget class="QWidget" name="UICKeyboardShortcutDialog"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>415</width> - <height>143</height> - </rect> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="windowTitle"> - <string>Keyboard shortcuts</string> - </property> - <property name="windowIcon"> - <iconset> - <normaloff>images/facetracknoir.png</normaloff>images/facetracknoir.png</iconset> - </property> - <property name="layoutDirection"> - <enum>Qt::LeftToRight</enum> - </property> - <property name="autoFillBackground"> - <bool>false</bool> - </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="2" column="0"> - <widget class="QLabel" name="textLabel2_5"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Toggle</string> - </property> - <property name="wordWrap"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="textLabel2_3"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Center</string> - </property> - <property name="wordWrap"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="QCheckBox" name="chkToggleShift"> - <property name="maximumSize"> - <size> - <width>50</width> - <height>16777215</height> - </size> - </property> - <property name="text"> - <string>Shift</string> - </property> - </widget> - </item> - <item row="2" column="4"> - <widget class="QComboBox" name="cbxToggleKey"> - <property name="minimumSize"> - <size> - <width>90</width> - <height>0</height> - </size> - </property> - <property name="toolTip"> - <string>Select Number</string> - </property> - <property name="insertPolicy"> - <enum>QComboBox::InsertAlphabetically</enum> - </property> - </widget> - </item> - <item row="1" column="3"> - <widget class="QCheckBox" name="chkCenterAlt"> - <property name="maximumSize"> - <size> - <width>50</width> - <height>16777215</height> - </size> - </property> - <property name="text"> - <string>Alt</string> - </property> - </widget> - </item> - <item row="2" column="2"> - <widget class="QCheckBox" name="chkToggleCtrl"> - <property name="maximumSize"> - <size> - <width>50</width> - <height>16777215</height> - </size> - </property> - <property name="text"> - <string>Ctrl</string> - </property> - </widget> - </item> - <item row="0" column="4"> - <widget class="QLabel" name="textLabel2_4"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Keyboard</string> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - <property name="wordWrap"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="2" column="3"> - <widget class="QCheckBox" name="chkToggleAlt"> - <property name="maximumSize"> - <size> - <width>50</width> - <height>16777215</height> - </size> - </property> - <property name="text"> - <string>Alt</string> - </property> - </widget> - </item> - <item row="3" column="3" colspan="2"> - <widget class="QDialogButtonBox" name="buttonBox"> - <property name="standardButtons"> - <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> - </property> - </widget> - </item> - <item row="1" column="2"> - <widget class="QCheckBox" name="chkCenterCtrl"> - <property name="maximumSize"> - <size> - <width>50</width> - <height>16777215</height> - </size> - </property> - <property name="text"> - <string>Ctrl</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QCheckBox" name="chkCenterShift"> - <property name="maximumSize"> - <size> - <width>50</width> - <height>16777215</height> - </size> - </property> - <property name="text"> - <string>Shift</string> - </property> - </widget> - </item> - <item row="1" column="4"> - <widget class="QComboBox" name="cbxCenterKey"> - <property name="minimumSize"> - <size> - <width>90</width> - <height>0</height> - </size> - </property> - <property name="toolTip"> - <string>Select Number</string> - </property> - <property name="insertPolicy"> - <enum>QComboBox::InsertAlphabetically</enum> - </property> - </widget> - </item> - </layout> - </widget> - <resources/> - <connections/> - <slots> - <slot>startEngineClicked()</slot> - <slot>stopEngineClicked()</slot> - <slot>cameraSettingsClicked()</slot> - </slots> -</ui> diff --git a/opentrack/global-shortcuts.cpp b/opentrack/global-shortcuts.cpp new file mode 100644 index 00000000..7569fd9a --- /dev/null +++ b/opentrack/global-shortcuts.cpp @@ -0,0 +1,68 @@ +#include <QList> +#include <QString> + +extern QList<QString> global_key_sequences; +extern QList<int> global_windows_key_sequences; + +#if defined(_WIN32) +# ifndef DIRECTINPUT_VERSION +# define DIRECTINPUT_VERSION 0x800 +# endif +# include <windows.h> +# include <dinput.h> + +QList<int> global_windows_key_sequences = + QList<int>() + << 0 + << DIK_F1 + << DIK_F2 + << DIK_F3 + << DIK_F4 + << DIK_F5 + << DIK_F6 + << DIK_F7 + << DIK_F8 + << DIK_F9 + << DIK_F10 + << DIK_F11 + << DIK_F12 + << DIK_LEFT + << DIK_RIGHT + << DIK_UP + << DIK_DOWN + << DIK_PGUP + << DIK_PGDN + << DIK_HOME + << DIK_END + << DIK_BACK + << DIK_DELETE + << DIK_RETURN; +#endif + +QList<QString> global_key_sequences = + QList<QString>() + << "" + << "F1" + << "F2" + << "F3" + << "F4" + << "F5" + << "F6" + << "F7" + << "F8" + << "F9" + << "F10" + << "F11" + << "F12" + << "Left" + << "Right" + << "Up" + << "Down" + << "PgUp" + << "PgDown" + << "Home" + << "End" + << "Del" +; + + diff --git a/opentrack/main-settings.hpp b/opentrack/main-settings.hpp index e41a23c9..0468aeb1 100644 --- a/opentrack/main-settings.hpp +++ b/opentrack/main-settings.hpp @@ -12,7 +12,7 @@ struct axis_opts { value<int> src; axis_opts(pbundle b, QString pfx, int idx) : zero(b, n(pfx, "zero-pos"), 0), - invert(b, n(pfx, "invert-axis"), false), + invert(b, n(pfx, "invert-sign"), false), altp(b, n(pfx, "alt-axis-sign"), false), src(b, n(pfx, "source-index"), idx) {} @@ -27,8 +27,11 @@ struct main_settings { value<QString> tracker_dll, tracker2_dll, filter_dll, protocol_dll; axis_opts a_x, a_y, a_z, a_yaw, a_pitch, a_roll; value<bool> tcomp_p, tcomp_tz; - main_settings(pbundle b) : - b(b), + value<bool> tray_enabled; + value<int> camera_yaw, camera_pitch; + value<bool> center_at_startup; + main_settings() : + b(bundle("opentrack-ui")), tracker_dll(b, "tracker-dll", ""), tracker2_dll(b, "tracker2-dll", ""), filter_dll(b, "filter-dll", ""), @@ -40,6 +43,10 @@ struct main_settings { a_pitch(b, "pitch", Pitch), a_roll(b, "roll", Roll), tcomp_p(b, "compensate-translation", true), - tcomp_tz(b, "compensate-translation-disable-z-axis", false) + tcomp_tz(b, "compensate-translation-disable-z-axis", false), + tray_enabled(b, "use-system-tray", false), + camera_yaw(b, "camera-yaw", 0), + camera_pitch(b, "camera-pitch", 0), + center_at_startup(b, "center-at-startup", true) {} }; diff --git a/opentrack/mappings.hpp b/opentrack/mappings.hpp index 86126db9..3336dcd8 100644 --- a/opentrack/mappings.hpp +++ b/opentrack/mappings.hpp @@ -10,23 +10,18 @@ class Mapping { public: Mapping(QString primary, QString secondary, - int maxInput1, - int maxOutput1, - int maxInput2, - int maxOutput2, + int max_x, + int max_y, axis_opts& opts) : - curve(maxInput1, maxOutput1), - curveAlt(maxInput2, maxOutput2), + curve(max_x, max_y), + curveAlt(max_x, max_y), opts(opts), name1(primary), name2(secondary) { - // XXX TODO move all this qsettings boilerplate into a single header -sh 20141004 - QSettings settings("opentrack"); - QString currentFile = settings.value ( "SettingsFile", QCoreApplication::applicationDirPath() + "/settings/default.ini" ).toString(); - QSettings iniFile(currentFile, QSettings::IniFormat); - curve.loadSettings(iniFile, primary); - curveAlt.loadSettings(iniFile, secondary); + mem<QSettings> iniFile = group::ini_file(); + curve.loadSettings(*iniFile, primary); + curveAlt.loadSettings(*iniFile, secondary); } Map curve; Map curveAlt; @@ -40,12 +35,12 @@ private: public: Mappings(std::vector<axis_opts*> opts) : axes { - Mapping("tx","tx_alt", 100, 100, 100, 100, *opts[TX]), - Mapping("ty","ty_alt", 100, 100, 100, 100, *opts[TY]), - Mapping("tz","tz_alt", 100, 100, 100, 100, *opts[TZ]), - Mapping("rx", "rx_alt", 180, 180, 180, 180, *opts[Yaw]), - Mapping("ry", "ry_alt", 180, 180, 180, 180, *opts[Pitch]), - Mapping("rz", "rz_alt", 180, 180, 180, 180, *opts[Roll]) + Mapping("tx","tx_alt", 100, 100, *opts[TX]), + Mapping("ty","ty_alt", 100, 100, *opts[TY]), + Mapping("tz","tz_alt", 100, 100, *opts[TZ]), + Mapping("rx", "rx_alt", 180, 180, *opts[Yaw]), + Mapping("ry", "ry_alt", 180, 180, *opts[Pitch]), + Mapping("rz", "rz_alt", 180, 180, *opts[Roll]) } {} @@ -54,29 +49,25 @@ public: void load_mappings() { - QSettings settings("opentrack"); - QString currentFile = settings.value ( "SettingsFile", QCoreApplication::applicationDirPath() + "/settings/default.ini" ).toString(); - QSettings iniFile( currentFile, QSettings::IniFormat ); + mem<QSettings> iniFile = group::ini_file(); for (int i = 0; i < 6; i++) { - axes[i].curve.loadSettings(iniFile, axes[i].name1); - axes[i].curveAlt.loadSettings(iniFile, axes[i].name2); + axes[i].curve.loadSettings(*iniFile, axes[i].name1); + axes[i].curveAlt.loadSettings(*iniFile, axes[i].name2); } } void save_mappings() { - QSettings settings("opentrack"); - QString currentFile = settings.value("SettingsFile", QCoreApplication::applicationDirPath() + "/settings/default.ini").toString(); - QSettings iniFile(currentFile, QSettings::IniFormat); + mem<QSettings> iniFile = group::ini_file(); for (int i = 0; i < 6; i++) { - axes[i].curve.saveSettings(iniFile, axes[i].name1); - axes[i].curveAlt.saveSettings(iniFile, axes[i].name2); + axes[i].curve.saveSettings(*iniFile, axes[i].name1); + axes[i].curveAlt.saveSettings(*iniFile, axes[i].name2); } } - + void invalidate_unsaved() { for (int i = 0; i < 6; i++) diff --git a/opentrack/mingw-version-script.txt b/opentrack/mingw-version-script.txt new file mode 100644 index 00000000..fe20ad37 --- /dev/null +++ b/opentrack/mingw-version-script.txt @@ -0,0 +1,8 @@ +{ + global: + GetDialog?0; + GetConstructor?0; + GetMetadata?0; + local: + *; +}; diff --git a/opentrack/options.hpp b/opentrack/options.hpp index 6c15d729..5eae754f 100644 --- a/opentrack/options.hpp +++ b/opentrack/options.hpp @@ -26,17 +26,21 @@ #include <QSlider> #include <QLineEdit> #include <QLabel> +#include <QTabWidget> #include <QCoreApplication> #include <cinttypes> #include <QDebug> +#include <memory> +template<typename t> using mem = std::shared_ptr<t>; + namespace options { template<typename k, typename v> using map = std::map<k, v>; using std::string; - + template<typename t> // don't elide usages of the function, qvariant default implicit // conversion results in nonsensical runtime behavior -sh @@ -77,12 +81,6 @@ namespace options { private: map<string, QVariant> kvs; string name; - static const QString ini_pathname() - { - QSettings settings(group::org); - return settings.value("SettingsFile", - QCoreApplication::applicationDirPath() + "/settings/default.ini" ).toString(); - } public: group(const string& name) : name(name) { @@ -97,8 +95,8 @@ namespace options { } conf.endGroup(); } - static constexpr const char* org = "opentrack"; - + static constexpr const char* org = "opentrack-2.3"; + void save() { QSettings s(ini_pathname(), QSettings::IniFormat); @@ -110,26 +108,41 @@ namespace options { s.setValue(k, i.second); } s.endGroup(); + s.sync(); } - + template<typename t> t get(const string& k) { return qcruft_to_t<t>(kvs[k]); } - + void put(const string& s, const QVariant& d) { kvs[s] = d; } - + bool contains(const string& s) { return kvs.count(s) != 0; } + + static constexpr const char* filename_key = "settings-file"; + static constexpr const char* default_path = "/settings/default.ini"; + + static const QString ini_pathname() + { + QSettings settings(group::org); + return settings.value(filename_key, QCoreApplication::applicationDirPath() + default_path).toString(); + } + static const mem<QSettings> ini_file() + { + return std::make_shared<QSettings>(ini_pathname(), QSettings::IniFormat); + } }; class impl_bundle : public QObject { + Q_OBJECT protected: QMutex mtx; const string group_name; @@ -138,6 +151,9 @@ namespace options { bool modified; impl_bundle(const impl_bundle&) = delete; impl_bundle& operator=(const impl_bundle&) = delete; + signals: + void reloading(); + void saving(); public: impl_bundle(const string& group_name) : mtx(QMutex::Recursive), @@ -147,28 +163,29 @@ namespace options { modified(false) { } - + string name() { return group_name; } - + void reload() { - QMutexLocker l(&mtx); - saved = group(group_name); - transient = saved; - modified = false; + { + QMutexLocker l(&mtx); + saved = group(group_name); + transient = saved; + modified = false; + } + emit reloading(); } - - bool store_kv(const string& name, const QVariant& datum) + + void store_kv(const string& name, const QVariant& datum) { QMutexLocker l(&mtx); - + auto old = transient.get<QVariant>(name); if (!transient.contains(name) || datum != old) { modified = true; transient.put(name, datum); - return true; } - return false; } bool contains(const string& name) { @@ -183,10 +200,13 @@ namespace options { } void save() { - QMutexLocker l(&mtx); - modified = false; - saved = transient; - transient.save(); + { + QMutexLocker l(&mtx); + modified = false; + saved = transient; + transient.save(); + } + emit saving(); } bool modifiedp() { @@ -194,9 +214,9 @@ namespace options { return modified; } }; - + class opt_bundle; - + namespace { template<typename k, typename v, typename cnt = int> @@ -210,51 +230,52 @@ namespace options { map<k, tt> implsgl_data; public: opt_singleton() : implsgl_mtx(QMutex::Recursive) {} - + static opt_singleton<k, v>& datum() { static auto ret = std::make_shared<opt_singleton<k, v>>(); return *ret; } - + pbundle bundle(const k& key) { QMutexLocker l(&implsgl_mtx); - + if (implsgl_data.count(key) != 0) return std::get<1>(implsgl_data[key]); + qDebug() << "bundle +" << QString::fromStdString(key); + auto shr = std::make_shared<v>(key); implsgl_data[key] = tt(cnt(1), shr); return shr; } - + void bundle_decf(const k& key) { QMutexLocker l(&implsgl_mtx); - + if (--std::get<0>(implsgl_data[key]) == 0) implsgl_data.erase(key); } - + ~opt_singleton() { implsgl_data.clear(); } }; - + using pbundle = std::shared_ptr<opt_bundle>; using t_fact = opt_singleton<string, opt_bundle>; } - + static inline t_fact::pbundle bundle(const string name) { return t_fact::datum().bundle(name); } - + class opt_bundle : public impl_bundle { public: opt_bundle() : impl_bundle("i-have-no-name") {} opt_bundle(const string& group_name) : impl_bundle(group_name) { - qDebug() << "bundle +" << QString::fromStdString(group_name); } - + ~opt_bundle() { qDebug() << "bundle -" << QString::fromStdString(group_name); @@ -281,16 +302,18 @@ namespace options { template<typename t> void store(const t& datum) { - if (b->store_kv(self_name, datum)) - emit valueChanged(static_cast<t>(datum)); + b->store_kv(self_name, datum); + emit valueChanged(static_cast<t>(datum)); } public slots: DEFINE_SLOT(double) DEFINE_SLOT(int) DEFINE_SLOT(QString) DEFINE_SLOT(bool) + public slots: + virtual void reload() = 0; }; - + static inline string string_from_qstring(const QString& datum) { auto tmp = datum.toUtf8(); @@ -309,6 +332,9 @@ namespace options { static constexpr const Qt::ConnectionType SAFE_CONNTYPE = Qt::UniqueConnection; value(pbundle b, const string& name, t def) : base_value(b, name) { + QObject::connect(b.get(), SIGNAL(reloading()), + this, SLOT(reload()), + DIRECT_CONNTYPE); if (!b->contains(name) || b->get<QVariant>(name).type() == QVariant::Invalid) *this = def; } @@ -319,6 +345,9 @@ namespace options { { return b->get<t>(self_name); } + void reload() override { + *this = static_cast<t>(*this); + } }; template<typename t, typename q> @@ -389,4 +418,12 @@ namespace options { lb->setText(v); base_value::connect(&v, SIGNAL(valueChanged(QString)), lb, SLOT(setText(QString)), v.SAFE_CONNTYPE); } + + template<> + inline void tie_setting(value<int>& v, QTabWidget* t) + { + t->setCurrentIndex(v); + base_value::connect(t, SIGNAL(currentChanged(int)), &v, SLOT(setValue(int)), v.DIRECT_CONNTYPE); + base_value::connect(&v, SIGNAL(valueChanged(int)), t, SLOT(setCurrentIndex(int)), v.SAFE_CONNTYPE); + } } diff --git a/opentrack/plugin-support.cpp b/opentrack/plugin-support.cpp index ec56b1e1..2c129906 100644 --- a/opentrack/plugin-support.cpp +++ b/opentrack/plugin-support.cpp @@ -5,6 +5,8 @@ #include <QFile> #include <QDir> +#include <iostream> + #ifndef _WIN32 # include <dlfcn.h> #endif @@ -14,16 +16,19 @@ SelectedLibraries::~SelectedLibraries() } template<typename t> -static ptr<t> make_instance(ptr<dylib> lib) +static mem<t> make_instance(mem<dylib> lib) { - ptr<t> ret = nullptr; - if (lib && lib->Constructor) - ret = ptr<t>(reinterpret_cast<t*>(reinterpret_cast<CTOR_FUNPTR>(lib->Constructor)())); - //qDebug() << "lib" << (lib ? lib->filename : "<null>") << "ptr" << (intptr_t)ret.get(); + mem<t> ret; + if (lib != nullptr && lib->Constructor) + { + qDebug() << "dylib" << (lib ? lib->filename : "<null>") << "ptr" << (intptr_t) lib->Constructor; + std::cout.flush(); + ret = mem<t>(reinterpret_cast<t*>(reinterpret_cast<CTOR_FUNPTR>(lib->Constructor)())); + } return ret; } -SelectedLibraries::SelectedLibraries(QFrame* frame, dylibtr t, dylibtr p, dylibtr f) : +SelectedLibraries::SelectedLibraries(QFrame* frame, dylibptr t, dylibptr p, dylibptr f) : pTracker(nullptr), pFilter(nullptr), pProtocol(nullptr), @@ -32,20 +37,19 @@ SelectedLibraries::SelectedLibraries(QFrame* frame, dylibtr t, dylibtr p, dylibt pTracker = make_instance<ITracker>(t); pProtocol = make_instance<IProtocol>(p); pFilter = make_instance<IFilter>(f); - - if (!pTracker|| !pProtocol) + + if (!pTracker || !pProtocol) { - qDebug() << "load failure tracker" << (intptr_t)pTracker.get() << "protocol" << (intptr_t)pProtocol.get(); + qDebug() << "dylib load failure"; + return; + } + + if(!pProtocol->correct()) + { + qDebug() << "protocol load failure"; return; } - if (pProtocol) - if(!pProtocol->correct()) - { - qDebug() << "protocol load failure"; - return; - } - pTracker->start_tracker(frame); correct = true; @@ -67,7 +71,7 @@ SelectedLibraries::SelectedLibraries(QFrame* frame, dylibtr t, dylibtr p, dylibt # define LIB_PREFIX "lib" #endif -static bool get_metadata(ptr<dylib> lib, QString& name, QIcon& icon) +static bool get_metadata(mem<dylib> lib, QString& name, QIcon& icon) { Metadata* meta; if (!lib->Meta || ((meta = lib->Meta()), !meta)) @@ -78,7 +82,7 @@ static bool get_metadata(ptr<dylib> lib, QString& name, QIcon& icon) return true; } -QList<ptr<dylib>> dylib::enum_libraries() +QList<mem<dylib>> dylib::enum_libraries() { #define BASE "opentrack-" #define SUFF "-*." @@ -86,11 +90,11 @@ QList<ptr<dylib>> dylib::enum_libraries() BASE "tracker" SUFF, BASE "proto" SUFF }; const Type filters_t[] = { Filter, Tracker, Protocol }; - + QDir settingsDir( QCoreApplication::applicationDirPath() ); - - QList<ptr<dylib>> ret; - + + QList<mem<dylib>> ret; + for (int i = 0; i < 3; i++) { QString filter = filters_n[i]; @@ -110,7 +114,7 @@ QList<ptr<dylib>> dylib::enum_libraries() ret.push_back(lib); } } - + return ret; } @@ -123,12 +127,12 @@ dylib::dylib(const QString& filename, Type t) : // otherwise dlopen opens the calling executable if (filename.size() == 0) return; - + this->filename = filename; #if defined(_WIN32) QString fullPath = QCoreApplication::applicationDirPath() + "/" + this->filename; handle = new QLibrary(fullPath); - + struct _foo { static bool die(QLibrary*& l, bool failp) { @@ -141,18 +145,18 @@ dylib::dylib(const QString& filename, Type t) : return failp; } }; - + if (_foo::die(handle, !handle->load())) return; - + Dialog = (CTOR_FUNPTR) handle->resolve("GetDialog"); if (_foo::die(handle, !Dialog)) return; - + Constructor = (CTOR_FUNPTR) handle->resolve("GetConstructor"); if (_foo::die(handle, !Constructor)) return; - + Meta = (METADATA_FUNPTR) handle->resolve("GetMetadata"); if (_foo::die(handle, !Meta)) return; @@ -199,9 +203,9 @@ dylib::dylib(const QString& filename, Type t) : (void) _foo::err(handle); } #endif - - auto m = ptr<Metadata>(Meta()); - + + auto m = mem<Metadata>(Meta()); + icon = m->icon(); name = m->name(); } @@ -209,7 +213,8 @@ dylib::dylib(const QString& filename, Type t) : dylib::~dylib() { #if defined(_WIN32) - handle->unload(); + if (handle) + delete handle; #else if (handle) (void) dlclose(handle); diff --git a/opentrack/plugin-support.h b/opentrack/plugin-support.h index 238aeb53..a2b6d403 100644 --- a/opentrack/plugin-support.h +++ b/opentrack/plugin-support.h @@ -1,6 +1,7 @@ #pragma once #include "plugin-api.hpp" +#include "options.hpp" #include <QWidget> #include <QDebug> @@ -9,8 +10,6 @@ #include <QFrame> #include <QList> -#include <memory> -template<typename t> using ptr = std::shared_ptr<t>; extern "C" typedef void* (*CTOR_FUNPTR)(void); extern "C" typedef Metadata* (*METADATA_FUNPTR)(void); @@ -20,7 +19,7 @@ struct dylib { dylib(const QString& filename, Type t); ~dylib(); - static QList<ptr<dylib>> enum_libraries(); + static QList<mem<dylib>> enum_libraries(); Type type; QString filename; @@ -40,12 +39,12 @@ private: }; struct SelectedLibraries { - using dylibtr = ptr<dylib>; - ptr<ITracker> pTracker; - ptr<IFilter> pFilter; - ptr<IProtocol> pProtocol; - SelectedLibraries(QFrame* frame, dylibtr t, dylibtr p, dylibtr f); + 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) {} ~SelectedLibraries(); bool correct; -};
\ No newline at end of file +}; diff --git a/opentrack/pose.hpp b/opentrack/pose.hpp index 41e984f5..93d467a9 100644 --- a/opentrack/pose.hpp +++ b/opentrack/pose.hpp @@ -2,7 +2,6 @@ #include <utility> #include <algorithm> -#include "./quat.hpp" #include "./plugin-api.hpp" class Pose { @@ -13,32 +12,11 @@ private: double axes[6]; public: - Pose() : axes {0,0,0, 0,0,0 } {} + Pose() : axes {0,0,0, 0,0,0} {} inline operator double*() { return axes; } inline operator const double*() const { return axes; } inline double& operator()(int i) { return axes[i]; } inline double operator()(int i) const { return axes[i]; } - - Quat quat() const - { - return Quat(axes[Yaw]*d2r, axes[Pitch]*d2r, axes[Roll]*d2r); - } - - static Pose fromQuat(const Quat& q) - { - Pose ret; - q.to_euler_degrees(ret(Yaw), ret(Pitch), ret(Roll)); - return ret; - } - - Pose operator&(const Pose& B) const - { - const Quat q = quat() * B.quat().inv(); - Pose ret = fromQuat(q); - for (int i = TX; i < TX + 3; i++) - ret(i) = axes[i] - B.axes[i]; - return ret; - } }; diff --git a/opentrack/posix-version-script.txt b/opentrack/posix-version-script.txt new file mode 100644 index 00000000..97edb9aa --- /dev/null +++ b/opentrack/posix-version-script.txt @@ -0,0 +1,8 @@ +{ + global: + GetDialog; + GetConstructor; + GetMetadata; + local: + *; +};
\ No newline at end of file diff --git a/opentrack/quat.hpp b/opentrack/quat.hpp deleted file mode 100644 index 6d777b28..00000000 --- a/opentrack/quat.hpp +++ /dev/null @@ -1,66 +0,0 @@ -/* Copyright (c) 2012 Patrick Ruoff - * - * 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 <cmath> - -class Quat { -private: - static constexpr double pi = 3.141592653; - static constexpr double r2d = 180./pi; - double a,b,c,d; // quaternion coefficients -public: - Quat() : a(1.),b(0.),c(0.),d(0.) {} - Quat(double yaw, double pitch, double roll) { from_euler_rads(yaw, pitch, roll); } - Quat(double a, double b, double c, double d) : a(a),b(b),c(c),d(d) {} - - Quat inv(){ - return Quat(a,-b,-c, -d); - } - - // conversions - // see http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles - void from_euler_rads(double yaw, double pitch, double roll) - { - - const double sin_phi = sin(roll/2.); - const double cos_phi = cos(roll/2.); - const double sin_the = sin(pitch/2.); - const double cos_the = cos(pitch/2.); - const double sin_psi = sin(yaw/2.); - const double cos_psi = cos(yaw/2.); - - a = cos_phi*cos_the*cos_psi + sin_phi*sin_the*sin_psi; - b = sin_phi*cos_the*cos_psi - cos_phi*sin_the*sin_psi; - c = cos_phi*sin_the*cos_psi + sin_phi*cos_the*sin_psi; - d = cos_phi*cos_the*sin_psi - sin_phi*sin_the*cos_psi; - } - - void to_euler_rads(double& yaw, double& pitch, double& roll) const - { - roll = atan2(2.*(a*b + c*d), 1. - 2.*(b*b + c*c)); - pitch = asin(2.*(a*c - b*d)); - yaw = atan2(2.*(a*d + b*c), 1. - 2.*(c*c + d*d)); - } - - void to_euler_degrees(double& yaw, double& pitch, double& roll) const - { - to_euler_rads(yaw, pitch, roll); - yaw *= r2d; - pitch *= r2d; - roll *= r2d; - } - - const Quat operator*(const Quat& B) const - { - const Quat& A = *this; - return Quat(A.a*B.a - A.b*B.b - A.c*B.c - A.d*B.d, // quaternion multiplication - A.a*B.b + A.b*B.a + A.c*B.d - A.d*B.c, - A.a*B.c - A.b*B.d + A.c*B.a + A.d*B.b, - A.a*B.d + A.b*B.c - A.c*B.b + A.d*B.a); - } -}; diff --git a/opentrack/shortcuts.cpp b/opentrack/shortcuts.cpp index d1cfa503..e81b6bb0 100644 --- a/opentrack/shortcuts.cpp +++ b/opentrack/shortcuts.cpp @@ -1,42 +1,19 @@ #include "shortcuts.h" +#include <QMutexLocker> -KeyboardShortcutDialog::KeyboardShortcutDialog() -{ - ui.setupUi( this ); - - connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(doOK())); - connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(doCancel())); - - for ( int i = 0; i < global_key_sequences.size(); i++) { - ui.cbxCenterKey->addItem(global_key_sequences.at(i)); - ui.cbxToggleKey->addItem(global_key_sequences.at(i)); - } - tie_setting(s.center.key_index, ui.cbxCenterKey); - tie_setting(s.center.alt, ui.chkCenterAlt); - tie_setting(s.center.shift, ui.chkCenterShift); - tie_setting(s.center.ctrl, ui.chkCenterCtrl); - - tie_setting(s.toggle.key_index, ui.cbxToggleKey); - tie_setting(s.toggle.alt, ui.chkToggleAlt); - tie_setting(s.toggle.shift, ui.chkToggleShift); - tie_setting(s.toggle.ctrl, ui.chkToggleCtrl); -} +#if defined(_WIN32) +#include <windows.h> -void KeyboardShortcutDialog::doOK() { - s.b->save(); - this->close(); - emit reload(); -} +void KeybindingWorker::set_keys(Key kCenter_, Key kToggle_, Key kZero_) +{ + QMutexLocker l(&mtx); -void KeyboardShortcutDialog::doCancel() { - s.b->reload(); - close(); + kCenter = kCenter_; + kToggle = kToggle_; + kZero = kZero_; } -#if defined(_WIN32) -#include <windows.h> - KeybindingWorker::~KeybindingWorker() { should_quit = true; wait(); @@ -48,8 +25,8 @@ KeybindingWorker::~KeybindingWorker() { din->Release(); } -KeybindingWorker::KeybindingWorker(Key keyCenter, Key keyToggle, WId handle) : - din(0), dinkeyboard(0), kCenter(keyCenter), kToggle(keyToggle), should_quit(true) +KeybindingWorker::KeybindingWorker(Key keyCenter, Key keyToggle, Key keyZero, WId handle, Shortcuts& sc) : + sc(sc), din(0), dinkeyboard(0), kCenter(keyCenter), kToggle(keyToggle), kZero(keyZero), should_quit(true) { if (DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&din, NULL) != DI_OK) { qDebug() << "setup DirectInput8 Creation failed!" << GetLastError(); @@ -94,7 +71,8 @@ static bool isKeyPressed( const Key *key, const BYTE *keystate ) { bool ctrl; bool alt; - if (keystate[key->keycode] & 0x80) { + if (key->keycode != 0 && keystate[key->keycode] & 0x80) + { shift = ( (keystate[DIK_LSHIFT] & 0x80) || (keystate[DIK_RSHIFT] & 0x80) ); ctrl = ( (keystate[DIK_LCONTROL] & 0x80) || (keystate[DIK_RCONTROL] & 0x80) ); alt = ( (keystate[DIK_LALT] & 0x80) || (keystate[DIK_RALT] & 0x80) ); @@ -108,12 +86,9 @@ static bool isKeyPressed( const Key *key, const BYTE *keystate ) { return false; } -#define PROCESS_KEY(k, s) \ - if (isKeyPressed(&k, keystate) && (!k.ever_pressed ? (k.timer.start(), k.ever_pressed = true) : k.timer.restart() > 100)) \ - emit s; - void KeybindingWorker::run() { BYTE keystate[256]; + while (!should_quit) { if (dinkeyboard->GetDeviceState(256, (LPVOID)keystate) != DI_OK) { @@ -122,10 +97,19 @@ void KeybindingWorker::run() { continue; } - PROCESS_KEY(kCenter, center()); - PROCESS_KEY(kToggle, toggle()); + QMutexLocker l(&mtx); - Sleep(25); + if (isKeyPressed(&kCenter, keystate) && kCenter.should_process()) + emit sc.center(); + + if (isKeyPressed(&kToggle, keystate) && kToggle.should_process()) + emit sc.toggle(); + + if (isKeyPressed(&kZero, keystate) && kZero.should_process()) + emit sc.zero(); + + // keypresses get dropped with high values + Sleep(15); } } #endif @@ -156,16 +140,47 @@ void Shortcuts::bind_keyboard_shortcut(K &key, key_opts& k) } } #else + key = K(); int idx = k.key_index; - if (idx > 0) + key.keycode = 0; + key.shift = key.alt = key.ctrl = 0; + if (idx > 0 && idx < global_windows_key_sequences.size()) + key.keycode = global_windows_key_sequences[idx]; + key.shift = k.shift; + key.alt = k.alt; + key.ctrl = k.ctrl; +#endif +} + +void Shortcuts::reload() { +#ifndef _WIN32 + if (keyCenter) { - key.keycode = 0; - key.shift = key.alt = key.ctrl = 0; - if (idx < global_windows_key_sequences.size()) - key.keycode = global_windows_key_sequences[idx]; - key.shift = k.shift; - key.alt = k.alt; - key.ctrl = k.ctrl; + keyCenter->setShortcut(QKeySequence::UnknownKey); + keyCenter->setEnabled(false); + } + if (keyToggle) + { + keyToggle->setShortcut(QKeySequence::UnknownKey); + keyToggle->setEnabled(false); + } + if (keyZero) + { + keyZero->setShortcut(QKeySequence::UnknownKey); + keyZero->setEnabled(false); } #endif -}
\ No newline at end of file + bind_keyboard_shortcut(keyCenter, s.center); + bind_keyboard_shortcut(keyToggle, s.toggle); + bind_keyboard_shortcut(keyZero, s.zero); +#ifdef _WIN32 + bool is_new = keybindingWorker == nullptr; + if (is_new) + { + keybindingWorker = std::make_shared<KeybindingWorker>(keyCenter, keyToggle, keyZero, handle, *this); + keybindingWorker->start(); + } + else + keybindingWorker->set_keys(keyCenter, keyToggle, keyZero); +#endif +} diff --git a/opentrack/shortcuts.h b/opentrack/shortcuts.h index 8fe1a39b..4d4b19d3 100644 --- a/opentrack/shortcuts.h +++ b/opentrack/shortcuts.h @@ -1,4 +1,5 @@ #pragma once +#include <QObject> #include <QWidget> #include <QElapsedTimer> #include <QThread> @@ -6,11 +7,12 @@ #include <QCheckBox> #include <QComboBox> #include <QSettings> +#include <QMutex> #include "qxt-mini/QxtGlobalShortcut" #include "opentrack/plugin-support.h" #include "opentrack/options.hpp" -#include "ui_ftnoir_keyboardshortcuts.h" +#include "opentrack/main-settings.hpp" using namespace options; @@ -40,112 +42,89 @@ struct Key { bool shift; bool ctrl; bool alt; - bool ever_pressed; QElapsedTimer timer; public: - Key() : keycode(0), shift(false), ctrl(false), alt(false), ever_pressed(false) + Key() : keycode(0), shift(false), ctrl(false), alt(false) { } + + bool should_process() + { + return !timer.isValid() ? (timer.start(), true) : timer.restart() > 100; + } }; #else typedef unsigned char BYTE; struct Key { int foo; }; #endif +struct Shortcuts; + struct KeybindingWorker : public QThread { - Q_OBJECT #ifdef _WIN32 private: + Shortcuts& sc; LPDIRECTINPUT8 din; LPDIRECTINPUTDEVICE8 dinkeyboard; Key kCenter; Key kToggle; + Key kZero; + QMutex mtx; public: volatile bool should_quit; ~KeybindingWorker(); - KeybindingWorker(Key keyCenter, Key keyToggle, WId handle); - void run(); + KeybindingWorker(Key keyCenter, Key keyToggle, Key keyZero, WId handle, Shortcuts& sc); + void run(); + void set_keys(Key kCenter, Key kToggle, Key kZero); #else public: - KeybindingWorker(Key, Key, WId) {} - void run() {} + KeybindingWorker(Key, Key, Key, WId) {} + void run() {} #endif -signals: - void center(); - void toggle(); }; +struct Shortcuts : public QObject { + Q_OBJECT -struct Shortcuts { +public: using K = #ifndef _WIN32 - ptr<QxtGlobalShortcut> + mem<QxtGlobalShortcut> #else Key #endif ; - + K keyCenter; K keyToggle; + K keyZero; WId handle; #ifdef _WIN32 - ptr<KeybindingWorker> keybindingWorker; + mem<KeybindingWorker> keybindingWorker; #endif - + struct settings { pbundle b; - key_opts center, toggle; + key_opts center, toggle, zero; + main_settings s_main; settings() : b(bundle("keyboard-shortcuts")), center(b, "center"), - toggle(b, "toggle") + toggle(b, "toggle"), + zero(b, "zero") {} } s; - Shortcuts(WId handle) : handle(handle) - { - reload(); - } + Shortcuts(WId handle) : handle(handle) { reload(); } - void reload() - { -#ifndef _WIN32 - if (keyCenter) - { - keyCenter->setShortcut(QKeySequence::UnknownKey); - keyCenter->setEnabled(false); - } - if (keyToggle) - { - keyToggle->setShortcut(QKeySequence::UnknownKey); - keyToggle->setEnabled(false); - } -#endif - bind_keyboard_shortcut(keyCenter, s.center); - bind_keyboard_shortcut(keyToggle, s.toggle); -#ifdef _WIN32 - keybindingWorker = nullptr; - keybindingWorker = std::make_shared<KeybindingWorker>(keyCenter, keyToggle, handle); - keybindingWorker->start(); -#endif - } + void reload(); private: void bind_keyboard_shortcut(K &key, key_opts& k); -}; - -class KeyboardShortcutDialog: public QWidget -{ - Q_OBJECT -public: - KeyboardShortcutDialog(); -private: - Ui::UICKeyboardShortcutDialog ui; - Shortcuts::settings s; - ptr<Shortcuts> sc; signals: - void reload(); -private slots: - void doOK(); - void doCancel(); + void center(); + void toggle(); + void zero(); }; + + diff --git a/opentrack/simple-mat.hpp b/opentrack/simple-mat.hpp new file mode 100644 index 00000000..158cb30d --- /dev/null +++ b/opentrack/simple-mat.hpp @@ -0,0 +1,155 @@ +#pragma once +#include <initializer_list> + +template<typename num, int h, int w> +struct Mat +{ + num data[h][w]; + + Mat<num, h, w> operator+(const Mat<num, h, w>& other) const + { + Mat<num, h, w> ret; + for (int j = 0; j < h; j++) + for (int i = 0; i < w; i++) + ret(j, i) = this->operator ()(j, i) + other(j, i); + return ret; + } + + Mat<num, h, w> operator-(const Mat<num, h, w>& other) const + { + Mat<num, h, w> ret; + for (int j = 0; j < h; j++) + for (int i = 0; i < w; i++) + ret(j, i) = this->operator ()(j, i) - other(j, i); + return ret; + } + + template<int p> + Mat<num, w, p> operator*(const Mat<num, w, p>& other) const + { + Mat<num, w, p> ret; + for (int j = 0; j < w; j++) + for (int i = 0; i < p; i++) + { + num sum = num(0); + + for (int k = 0; k < h; k++) + sum += data[j][k]*other.data[k][i]; + + ret.data[j][i] = sum; + } + + return ret; + } + + num operator()(int j, int i) const { return data[j][i]; } + num& operator()(int j, int i) { return data[j][i]; } + + Mat(std::initializer_list<num>&& list) + { + auto iter = list.begin(); + for (int i = 0; i < h; i++) + for (int j = 0; j < w; j++) + data[i][j] = *iter++; + } + + Mat() + { + for (int j = 0; j < h; j++) + for (int i = 0; i < w; i++) + data[j][i] = 0; + } + + Mat(const num* mem) + { + for (int j = 0; j < h; j++) + for (int i = 0; i < w; i++) + data[j][i] = mem[i*h+j]; + } + + // XXX add more operators as needed, third-party dependencies mostly + // not needed merely for matrix algebra -sh 20141030 + + static Mat<num, h, h> eye() + { + Mat<num, h, h> ret; + for (int j = 0; j < h; j++) + for (int i = 0; i < w; i++) + ret.data[j][i] = 0; + + for (int i = 0; i < h; i++) + ret.data[i][i] = 1; + + return ret; + } + + Mat<num, w, h> t() const + { + Mat<num, w, h> ret; + + for (int j = 0; j < h; j++) + for (int i = 0; i < w; i++) + ret.data[i][j] = data[j][i]; + + return ret; + } + + template<int h_, int w_> using dmat = Mat<double, h_, w_>; + + // http://stackoverflow.com/a/18436193 + static dmat<3, 1> rmat_to_euler(const dmat<3, 3>& R) + { + static constexpr double pi = 3.141592653; + const double up = 90 * pi / 180.; + static constexpr double bound = 1. - 2e-4; + if (R(0, 2) > bound) + { + double roll = atan(R(1, 0) / R(2, 0)); + return dmat<3, 1>({0., up, roll}); + } + if (R(0, 2) < -bound) + { + double roll = atan(R(1, 0) / R(2, 0)); + return dmat<3, 1>({0., -up, roll}); + } + double pitch = asin(-R(0, 2)); + double roll = atan2(R(1, 2), R(2, 2)); + double yaw = atan2(R(0, 1), R(0, 0)); + return dmat<3, 1>({yaw, pitch, roll}); + } + + // tait-bryan angles, not euler + static dmat<3, 3> euler_to_rmat(const double* input) + { + static constexpr double pi = 3.141592653; + auto H = input[0] * pi / 180; + auto P = input[1] * pi / 180; + auto B = input[2] * pi / 180; + + const auto c1 = cos(H); + const auto s1 = sin(H); + const auto c2 = cos(P); + const auto s2 = sin(P); + const auto c3 = cos(B); + const auto s3 = sin(B); + + double foo[] = { + // z + c1 * c2, + c1 * s2 * s3 - c3 * s1, + s1 * s3 + c1 * c3 * s2, + // y + c2 * s1, + c1 * c3 + s1 * s2 * s3, + c3 * s1 * s2 - c1 * s3, + // x + -s2, + c2 * s3, + c2 * c3 + }; + + return dmat<3, 3>(foo); + } +}; + +template<int h, int w> using dmat = Mat<double, h, w>; diff --git a/opentrack/state.hpp b/opentrack/state.hpp index 7fde64dc..2c37e5eb 100644 --- a/opentrack/state.hpp +++ b/opentrack/state.hpp @@ -12,18 +12,18 @@ struct Modules { tracker_modules(filter(dylib::Tracker)), protocol_modules(filter(dylib::Protocol)) {} - QList<ptr<dylib>>& filters() { return filter_modules; } - QList<ptr<dylib>>& trackers() { return tracker_modules; } - QList<ptr<dylib>>& protocols() { return protocol_modules; } + QList<mem<dylib>>& filters() { return filter_modules; } + QList<mem<dylib>>& trackers() { return tracker_modules; } + QList<mem<dylib>>& protocols() { return protocol_modules; } private: - QList<ptr<dylib>> module_list; - QList<ptr<dylib>> filter_modules; - QList<ptr<dylib>> tracker_modules; - QList<ptr<dylib>> protocol_modules; + QList<mem<dylib>> module_list; + QList<mem<dylib>> filter_modules; + QList<mem<dylib>> tracker_modules; + QList<mem<dylib>> protocol_modules; - QList<ptr<dylib>> filter(dylib::Type t) + QList<mem<dylib>> filter(dylib::Type t) { - QList<ptr<dylib>> ret; + QList<mem<dylib>> ret; for (auto x : module_list) if (x->type == t) ret.push_back(x); @@ -35,14 +35,11 @@ struct Work; struct State { State() : - b(bundle("opentrack-ui")), - s(b), pose(std::vector<axis_opts*>{&s.a_x, &s.a_y, &s.a_z, &s.a_yaw, &s.a_pitch, &s.a_roll}) {} Modules modules; SelectedLibraries libs; - pbundle b; main_settings s; Mappings pose; - ptr<Work> work; + mem<Work> work; }; diff --git a/opentrack/timer.hpp b/opentrack/timer.hpp index 628365c9..eb956213 100644 --- a/opentrack/timer.hpp +++ b/opentrack/timer.hpp @@ -2,6 +2,9 @@ #include <ctime> #if defined (_WIN32) # include <windows.h> +# ifndef CLOCK_MONOTONIC +# define CLOCK_MONOTONIC -1 +# endif static inline void opentrack_clock_gettime(int, struct timespec* ts) { static LARGE_INTEGER freq; @@ -50,12 +53,8 @@ public: Timer() { start(); } - long start() { - struct timespec cur; - (void) clock_gettime(CLOCK_MONOTONIC, &cur); - long ret = conv(cur); - state = cur; - return ret; + void start() { + (void) clock_gettime(CLOCK_MONOTONIC, &state); } long elapsed() { struct timespec cur; diff --git a/opentrack/tracker.cpp b/opentrack/tracker.cpp index 8f1854e9..f70dd819 100644 --- a/opentrack/tracker.cpp +++ b/opentrack/tracker.cpp @@ -12,9 +12,8 @@ * originally written by Wim Vriend. */ -#include <opencv2/core/core.hpp> -#include "./tracker.h" +#include "tracker.h" #include <cmath> #include <algorithm> @@ -25,10 +24,13 @@ Tracker::Tracker(main_settings& s, Mappings &m, SelectedLibraries &libs) : s(s), m(m), - centerp(false), + centerp(s.center_at_startup), enabledp(true), + zero_(false), should_quit(false), - libs(libs) + libs(libs), + r_b(dmat<3,3>::eye()), + t_b {0,0,0} { } @@ -38,112 +40,145 @@ Tracker::~Tracker() wait(); } -double Tracker::map(double pos, Mapping& axis) { +double Tracker::map(double pos, Mapping& axis) +{ bool altp = (pos < 0) && axis.opts.altp; axis.curve.setTrackingActive( !altp ); axis.curveAlt.setTrackingActive( altp ); auto& fc = altp ? axis.curveAlt : axis.curve; - double invert = axis.opts.invert ? -1 : 1; - return invert * (fc.getValue(pos) + axis.opts.zero); -} - -static cv::Matx33d euler_to_rmat(const double* input) -{ - static constexpr double pi = 3.141592653; - const auto H = input[0] * pi / -180; - const auto P = input[1] * pi / -180; - const auto B = input[2] * pi / 180; - - const auto cosH = cos(H); - const auto sinH = sin(H); - const auto cosP = cos(P); - const auto sinP = sin(P); - const auto cosB = cos(B); - const auto sinB = sin(B); - - double foo[] = { - cosH * cosB - sinH * sinP * sinB, - - sinB * cosP, - sinH * cosB + cosH * sinP * sinB, - cosH * sinB + sinH * sinP * cosB, - cosB * cosP, - sinB * sinH - cosH * sinP * cosB, - - sinH * cosP, - - sinP, - cosH * cosP, - }; - - return cv::Matx33d(foo); + return fc.getValue(pos) + axis.opts.zero; } -void Tracker::t_compensate(const double* input, double* output, bool rz) +void Tracker::t_compensate(const rmat& rmat, const double* xyz, double* output, bool rz) { - const cv::Matx33d rmat = euler_to_rmat(&input[Yaw]); - const cv::Vec3d tvec(input); - const cv::Vec3d ret = rmat * tvec; - - const int max = !rz ? 3 : 2; - - for (int i = 0; i < max; i++) - output[i] = ret(i); + // TY is really yaw axis. need swapping accordingly. + dmat<3, 1> tvec({ xyz[2], -xyz[0], -xyz[1] }); + const dmat<3, 1> ret = rmat * tvec; + if (!rz) + output[2] = ret(0, 0); + else + output[2] = xyz[2]; + output[1] = -ret(2, 0); + output[0] = -ret(1, 0); } void Tracker::logic() { - libs.pTracker->data(newpose); + bool inverts[6] = { + m(0).opts.invert, + m(1).opts.invert, + m(2).opts.invert, + m(3).opts.invert, + m(4).opts.invert, + m(5).opts.invert, + }; - Pose final_raw_; - - if (enabledp) - { + static constexpr double pi = 3.141592653; + static constexpr double r2d = 180. / pi; + + Pose value, raw; + + if (!zero_) for (int i = 0; i < 6; i++) { - auto& axis = m(i); - int k = axis.opts.src; - if (k < 0 || k >= 6) - { - final_raw_(i) = 0; - continue; - } - // not really raw, after axis remap -sh - final_raw_(i) = newpose[k]; + value(i) = newpose[i]; + raw(i) = newpose[i]; + } + else + { + auto mat = rmat::rmat_to_euler(r_b); + + for (int i = 0; i < 3; i++) + { + raw(i+3) = value(i+3) = mat(i, 0) * r2d; + raw(i) = value(i) = t_b[i]; } - final_raw = final_raw_; } + + const double off[] = { + s.camera_yaw, + s.camera_pitch, + 0. + }; + const rmat cam = rmat::euler_to_rmat(off); + rmat r = rmat::euler_to_rmat(&value[Yaw]); + dmat<3, 1> t { value(0), value(1), value(2) }; - Pose filtered_pose; + r = cam * r; + t = cam * t; - if (libs.pFilter) - libs.pFilter->filter(final_raw, filtered_pose); - else - filtered_pose = final_raw; + bool can_center = false; if (centerp) { + for (int i = 0; i < 6; i++) + if (fabs(newpose[i]) != 0) + { + can_center = true; + break; + } + } + + if (can_center) + { centerp = false; - raw_center = final_raw; + for (int i = 0; i < 3; i++) + t_b[i] = t(i, 0); + r_b = r; } - Pose raw_centered = filtered_pose & raw_center; + { + double tmp[3] = { t(0, 0) - t_b[0], t(1, 0) - t_b[1], t(2, 0) - t_b[2] }; + t_compensate(cam, tmp, tmp, false); + const rmat m_ = r * r_b.t(); + const dmat<3, 1> euler = rmat::rmat_to_euler(m_); + for (int i = 0; i < 3; i++) + { + value(i) = tmp[i]; + value(i+3) = euler(i, 0) * r2d; + } + } - Pose mapped_pose_precomp; + for (int i = 3; i < 6; i++) + value(i) = map(value(i), m(i)); - for (int i = 0; i < 6; i++) - mapped_pose_precomp(i) = map(raw_centered(i), m(i)); + { + Pose tmp = value; + + if (libs.pFilter) + libs.pFilter->filter(tmp, value); + } + + if (s.tcomp_p) + t_compensate(rmat::euler_to_rmat(&value[Yaw]), + value, + value, + s.tcomp_tz); - Pose mapped_pose; + for (int i = 0; i < 3; i++) + value(i) = map(value(i), m(i)); - mapped_pose = mapped_pose_precomp; - if (s.tcomp_p) - t_compensate(mapped_pose_precomp, mapped_pose, s.tcomp_tz); + for (int i = 0; i < 6; i++) + value[i] *= inverts[i] ? -1. : 1.; - libs.pProtocol->pose(mapped_pose); + Pose output_pose_; + for (int i = 0; i < 6; i++) { - QMutexLocker foo(&mtx); - output_pose = mapped_pose; - raw_6dof = final_raw; + auto& axis = m(i); + int k = axis.opts.src; + if (k < 0 || k >= 6) + output_pose_(i) = 0; + else + output_pose_(i) = value(k); } + + + libs.pProtocol->pose(output_pose_); + + QMutexLocker foo(&mtx); + output_pose = output_pose_; + raw_6dof = raw; } void Tracker::run() { @@ -156,13 +191,28 @@ void Tracker::run() { while (!should_quit) { t.start(); - + + double tmp[6] {0,0,0, 0,0,0}; + libs.pTracker->data(tmp); + + if (enabledp) + for (int i = 0; i < 6; i++) + newpose[i] = tmp[i]; + logic(); - double q = sleep_ms * 1000L; - q -= t.elapsed(); - q = std::max(0., q); - usleep((long)q); + long q = sleep_ms * 1000L - t.elapsed()/1000L; + usleep(std::max(1L, q)); + } + + { + // do one last pass with origin pose + for (int i = 0; i < 6; i++) + newpose[i] = 0; + logic(); + // filter may inhibit exact origin + Pose p; + libs.pProtocol->pose(p); } #if defined(_WIN32) diff --git a/opentrack/tracker.h b/opentrack/tracker.h index 462f4e50..ace9fa3c 100644 --- a/opentrack/tracker.h +++ b/opentrack/tracker.h @@ -1,16 +1,16 @@ #pragma once -#include <atomic> #include <vector> -#include "./timer.hpp" -#include "./plugin-support.h" -#include "./mappings.hpp" -#include "./pose.hpp" +#include "timer.hpp" +#include "plugin-support.h" +#include "mappings.hpp" +#include "pose.hpp" +#include "simple-mat.hpp" #include "../qfunctionconfigurator/functionconfig.h" -#include "./main-settings.hpp" -#include "./options.hpp" +#include "main-settings.hpp" +#include "options.hpp" #include <QMutex> #include <QThread> @@ -21,26 +21,35 @@ private: QMutex mtx; main_settings& s; Mappings& m; - + Timer t; - Pose output_pose, raw_6dof, raw_center, final_raw; + Pose output_pose, raw_6dof; + double newpose[6]; - std::atomic<bool> centerp; - std::atomic<bool> enabledp; - std::atomic<bool> should_quit; + volatile bool centerp; + volatile bool enabledp; + volatile bool zero_; + volatile bool should_quit; SelectedLibraries const& libs; + + using rmat = dmat<3, 3>; + dmat<3, 3> r_b; + double t_b[3]; + double map(double pos, Mapping& axis); void logic(); - - static void t_compensate(const double* input, double* output, bool rz); + + void t_compensate(const dmat<3, 3>& rmat, const double* ypr, double* output, bool rz); void run() override; + public: Tracker(main_settings& s, Mappings& m, SelectedLibraries& libs); ~Tracker(); void get_raw_and_mapped_poses(double* mapped, double* raw) const; void start() { QThread::start(); } - void toggle_enabled() { enabledp.store(!enabledp.load()); } - void center() { centerp.store(!centerp.load()); } + void toggle_enabled() { enabledp = !enabledp; } + void center() { centerp = !centerp; } + void zero() { zero_ = !zero_; } }; diff --git a/opentrack/work.hpp b/opentrack/work.hpp index d0130018..b93c71b6 100644 --- a/opentrack/work.hpp +++ b/opentrack/work.hpp @@ -13,10 +13,10 @@ struct Work { main_settings& s; SelectedLibraries libs; - ptr<Tracker> tracker; - ptr<Shortcuts> sc; + mem<Tracker> tracker; + mem<Shortcuts> sc; WId handle; - + Work(main_settings& s, Mappings& m, SelectedLibraries& libs, QObject* recv, WId handle) : s(s), libs(libs), tracker(std::make_shared<Tracker>(s, m, libs)), @@ -26,22 +26,24 @@ struct Work #ifndef _WIN32 QObject::connect(sc->keyCenter.get(), SIGNAL(activated()), recv, SLOT(shortcutRecentered())); QObject::connect(sc->keyToggle.get(), SIGNAL(activated()), recv, SLOT(shortcutToggled())); + QObject::connect(sc->keyZero.get(), SIGNAL(activated()), recv, SLOT(shortcutZeroed())); #else - QObject::connect(sc->keybindingWorker.get(), SIGNAL(center()), recv, SLOT(shortcutRecentered())); - QObject::connect(sc->keybindingWorker.get(), SIGNAL(toggle()), recv, SLOT(shortcutToggled())); + QObject::connect(sc.get(), SIGNAL(center()), recv, SLOT(shortcutRecentered())); + QObject::connect(sc.get(), SIGNAL(toggle()), recv, SLOT(shortcutToggled())); + QObject::connect(sc.get(), SIGNAL(zero()), recv, SLOT(shortcutZeroed())); #endif tracker->start(); } - + void reload_shortcuts() { sc->reload(); } - + ~Work() { // order matters, otherwise use-after-free -sh tracker = nullptr; libs = SelectedLibraries(); - } + } }; |