diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2016-01-06 20:07:13 +0100 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2016-01-06 20:16:18 +0100 |
commit | 82f3d7373234cc0db79a22d476cb54b5eda7a0ea (patch) | |
tree | 65ee0194ad064cc470f95f7ca8efd533b089ca96 | |
parent | 7e3807d048c5e0a8e0aa64fb49807bf5dfd11fc1 (diff) | |
parent | f02baa0868f219076a641634625f7c032d3a9eef (diff) |
Merge branch 'unstable' into trackhat
* unstable: (140 commits)
tracker/pt: increase auto threshold bucket size again
tracker/pt: limit max amount of extracted blobs
gui: don't update main window if we're minimized
tracker/pt: only show widget if the frame is visible
tracker/pt: don't resize twice in widget
freetrack/games: regen
contrib/make-csv: perl sort isn't stable, don't ignore case
tracker/pt: avoid widget temp QImage allocation
spline-widget: oops, pass by reference
tracker/pt: don't allocate temporary dynamic size arrays
tracker/pt: don't copy points array needlessly
tracker/pt: don't allocate temporary frame
tracker/pt: cv::Mat::at<T> is slow, use cv::Mat::ptr
tracker/pt: avoid widget malloc when able
tracker/pt: optimize widget
tracker/pt: update video widget at 40 -> 50 ms
cmake/mingw-w64: update
tracker/pt: reduce mutex contention
gui: fix left margin
tracker/pt: remove krap
tracker/pt: move ctor out of the loop
tracker/pt: nix unused
tracker/pt: don't fill mask on frame
pose-widget: also bilinear interpolation of alpha value
ui: adjust margin
ui: make more compact
glwidget: use transparent octopus background
api/mat: fix typos/breakage
api/joy: refresh only manually on certain events
pt: histogram more granular 6 -> 8
cmake/api: link with strmiids.lib on win32
tracker/pt: reduce auto thresholding histogram bucket size
api/keys: prevent idempotent keys
api/joy: move from header
api/joy: prevent idempotent keypressed passed to receiver
compat/options: get rid of std::string usage
compat/options: move from header
gui/settings: set parent, otherwise not modal
gui/settings: don't forget to show a modal dialog before executing
gui/main: don't raise a new window, it's enough to set visible
api/joy: speed up poll_axis path
api/joy: nix static, now that we're not a singleton
tracker/joy: adapt to non-singleton joy worker
joystick: no longer singleton, use fake window handle
api/keys: use a fake window for DirectInput handle
gui/keys: allow for pausing global keystrokes for options dialog
api/keys: nix tautological #ifdef
contrib/aruco: oops, right extension
contrib/aruco: use @frost555's marker image
api/camera-names: move to compat/
...
112 files changed, 2941 insertions, 2080 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 00b9bcdc..2be2a878 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,8 +22,8 @@ file(GLOB opentrack-subprojects "csv/${C}" "pose-widget/${C}" "spline-widget/${C}" - "macosx/${C}" "qxt-mini/${C}" + "macosx/${C}" ) foreach(i ${opentrack-subprojects}) get_filename_component(i ${i} DIRECTORY) @@ -22,7 +22,7 @@ Not to be confused with railway planning software <<http://opentrack.ch>> # Tracking sources - PointTracker by Patrick Ruoff, freetrack-like light sources -- Oculus Rift DK2 +- Oculus Rift DK1, DK2 and legacy versions - Paper marker support via the ArUco library <<https://github.com/rmsalinas/aruco>> - Human face tracker <<https://github.com/sthalik/headtracker>> - Razer Hydra diff --git a/cmake/mingw-w64.cmake b/cmake/mingw-w64.cmake index 02ab66cb..679f67de 100644 --- a/cmake/mingw-w64.cmake +++ b/cmake/mingw-w64.cmake @@ -27,7 +27,7 @@ SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) # oldest CPU supported here is Northwood-based Pentium 4. -sh 20150811 set(fpu "-ffast-math -fno-finite-math-only -mfpmath=both") -set(cpu "-O3 -march=pentium4 -mtune=corei7-avx ${fpu} -msse -msse2 -mno-sse3") +set(cpu "-O3 -march=pentium4 -mtune=corei7-avx ${fpu} -msse -msse2 -mno-sse3 -frename-registers") set(CFLAGS-OVERRIDE "" CACHE STRING "") diff --git a/cmake/opentrack-macros.cmake b/cmake/opentrack-macros.cmake index e43dc3b5..d84f9175 100644 --- a/cmake/opentrack-macros.cmake +++ b/cmake/opentrack-macros.cmake @@ -32,7 +32,7 @@ endfunction() macro(opentrack_library n dir) cmake_parse_arguments(opentrack-foolib - "NO-LIBRARY;STATIC;NO-COMPAT;NO-LINKER-SCRIPT" + "NO-LIBRARY;STATIC;NO-COMPAT;NO-LINKER-SCRIPT;LINKAGE" "LINK;COMPILE;GNU-LINK;GNU-COMPILE" "" ${ARGN} @@ -53,20 +53,33 @@ macro(opentrack_library n dir) target_link_libraries(${n} opentrack-api opentrack-compat) endif() target_link_libraries(${n} ${MY_QT_LIBS}) - if(CMAKE_COMPILER_IS_GNUCXX AND NOT APPLE AND NOT opentrack-foolib_NO-LINKER-SCRIPT) - SET_TARGET_PROPERTIES(${n} PROPERTIES - LINK_FLAGS "${opentrack-foolib_LINK} ${opentrack-foolib_GNU-LINK} -Wl,--as-needed -Wl,--version-script=\"${CMAKE_SOURCE_DIR}/opentrack-compat/${version-script}-version-script.txt\"" + if(CMAKE_COMPILER_IS_GNUCXX AND NOT opentrack-foolib_NO-LINKER-SCRIPT) + set(l-flags) + if(NOT APPLE) + set(l-flags "-Wl,--as-needed -Wl,--version-script=\"${CMAKE_SOURCE_DIR}/opentrack-compat/${version-script}-version-script.txt\"") + endif() + set_target_properties(${n} PROPERTIES + LINK_FLAGS "${opentrack-foolib_LINK} ${opentrack-foolib_GNU-LINK} ${l-flags}" COMPILE_FLAGS "${opentrack-foolib_COMPILE} ${opentrack-foolib_GNU-COMPILE} -fvisibility=hidden -fvisibility-inlines-hidden" ) else() - set(link-flags) - if(MSVC) - set(link-flags "${msvc-subsystem} /DEBUG /OPT:ICF") + set(c-props) + set(l-props) + if(opentrack-foolib_LINKAGE AND CMAKE_COMPILER_IS_GNUCXX AND NOT APPLE) + set(c-props "${opentrack-foolib_COMPILE} ${opentrack-foolib_GNU-COMPILE} -fvisibility=hidden -fvisibility-inlines-hidden") + set(l-props "${opentrack-foolib_LINK} ${opentrack-foolib_GNU-LINK} -Wl,--as-needed") + else() + if(MSVC) + set(l-props "${msvc-subsystem} /DEBUG /OPT:ICF") + endif() endif() - set_target_properties(${n} PROPERTIES LINK_FLAGS "${link-flags} ${opentrack-foolib_LINK}" COMPILE_FLAGS "${opentrack-foolib_COMPILE}") - set(link-flags) + set_target_properties(${n} PROPERTIES + LINK_FLAGS "${l-props} ${opentrack-foolib_LINK}" + COMPILE_FLAGS "${c-props} ${opentrack-foolib_COMPILE}" + ) endif() - string(REPLACE "-" "_" n_ ${n}) + string(REGEX REPLACE "^opentrack-" "" n_ ${n}) + string(REPLACE "-" "_" n_ ${n_}) target_compile_definitions(${n} PRIVATE "BUILD_${n_}") if(NOT opentrack-foolib_STATIC) install(TARGETS ${n} RUNTIME DESTINATION . LIBRARY DESTINATION .) diff --git a/contrib/aruco/test3.jpg b/contrib/aruco/test3.jpg Binary files differdeleted file mode 100644 index 2ff6dbd0..00000000 --- a/contrib/aruco/test3.jpg +++ /dev/null diff --git a/contrib/aruco/test3.png b/contrib/aruco/test3.png Binary files differnew file mode 100644 index 00000000..81f2d201 --- /dev/null +++ b/contrib/aruco/test3.png diff --git a/contrib/very-important-source-code/make-csv.pl b/contrib/very-important-source-code/make-csv.pl index ee60364e..fcac9369 100644 --- a/contrib/very-important-source-code/make-csv.pl +++ b/contrib/very-important-source-code/make-csv.pl @@ -58,7 +58,7 @@ sub merge { } } print "No;Game Name;Game protocol;Supported since;Verified;By;INTERNATIONAL_ID;FTN_ID\n"; - for (sort { lc($a->{name}) cmp lc($b->{name}) } values %game_hash) { + for (sort { $a->{name} cmp $b->{name} } values %game_hash) { my $g = {%$_}; if (!defined $g->{key}) { $g->{key} = (sprintf "%04X", $g->{no}) . (join"", map { sprintf "%02X", int rand 256 } 0 .. 7) . '00'; diff --git a/csv/CMakeLists.txt b/csv/CMakeLists.txt index 7e80317c..7bafc7ff 100644 --- a/csv/CMakeLists.txt +++ b/csv/CMakeLists.txt @@ -1 +1 @@ -opentrack_boilerplate(opentrack-csv NO-LINKER-SCRIPT) +opentrack_boilerplate(opentrack-csv NO-LINKER-SCRIPT LINKAGE) @@ -7,7 +7,7 @@ #include <QRegExp> #include <QtGlobal> -#ifdef BUILD_opentrack_csv +#ifdef BUILD_csv # define CSV_EXPORT Q_DECL_EXPORT #else # define CSV_EXPORT Q_DECL_IMPORT diff --git a/filter-accela/ftnoir_filter_accela.cpp b/filter-accela/ftnoir_filter_accela.cpp index e43db7e4..b29c989a 100644 --- a/filter-accela/ftnoir_filter_accela.cpp +++ b/filter-accela/ftnoir_filter_accela.cpp @@ -12,11 +12,13 @@ #include "opentrack/plugin-api.hpp" static constexpr double rot_gains[][2] = { + { 4.0, 350 }, + //{ 3.33, 200 }, { 2.66, 110 }, - { 2.33, 80 }, - { 2, 50 }, + //{ 2.33, 85 }, + //{ 2, 45 }, { 1.66, 30 }, - { 1.33, 15 }, + //{ 1.33, 15 }, { 1, 5 }, { .66, 1.4 }, { .33, .4 }, diff --git a/filter-accela/ftnoir_filter_accela.h b/filter-accela/ftnoir_filter_accela.h index 3242c9e1..94408fb1 100644 --- a/filter-accela/ftnoir_filter_accela.h +++ b/filter-accela/ftnoir_filter_accela.h @@ -11,7 +11,7 @@ #include <QMutex> #include <QTimer> -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; #include "opentrack-compat/timer.hpp" diff --git a/filter-ewma2/ftnoir_filter_ewma2.h b/filter-ewma2/ftnoir_filter_ewma2.h index bf4e83ad..bdb9cedc 100644 --- a/filter-ewma2/ftnoir_filter_ewma2.h +++ b/filter-ewma2/ftnoir_filter_ewma2.h @@ -5,7 +5,7 @@ #include <QElapsedTimer> #include <QWidget> #include <QMutex> -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; struct settings : opts { diff --git a/filter-kalman/ftnoir_filter_kalman.h b/filter-kalman/ftnoir_filter_kalman.h index a6f40bb7..773f61d5 100644 --- a/filter-kalman/ftnoir_filter_kalman.h +++ b/filter-kalman/ftnoir_filter_kalman.h @@ -16,7 +16,7 @@ #include <QString> #include <QElapsedTimer> #include <QWidget> -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; struct settings : opts { diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index f56641fb..778cbf08 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -41,4 +41,18 @@ if(LINUX) target_link_libraries(opentrack procps) endif() +set(c-props) +set(l-props) +if(CMAKE_COMPILER_IS_GNUCXX) + set(c-props "-fvisibility=hidden -fvisibility-inlines-hidden") + if(NOT APPLE) + set(l-props "-Wl,--as-needed") + endif() +endif() + +set_target_properties(opentrack PROPERTIES + LINK_FLAGS "${l-props}" + COMPILE_FLAGS "${c-props}" +) + install(TARGETS opentrack DESTINATION .) diff --git a/gui/curve-config.cpp b/gui/curve-config.cpp index 2e9065b4..7cd78580 100644 --- a/gui/curve-config.cpp +++ b/gui/curve-config.cpp @@ -54,6 +54,12 @@ MapWidget::MapWidget(Mappings& m, main_settings& s) : qfc.setEnabled(qfcs[i].checkbox->isChecked()); qfc.force_redraw(); } + + if (qfcs[i].axis >= 3) + qfcs[i].qfc->set_snap(2, 5); + else + qfcs[i].qfc->set_snap(1, 5); + qfcs[i].qfc->setConfig(conf, name); } } diff --git a/gui/keyboard.h b/gui/keyboard.h index 62a9ce20..696df605 100644 --- a/gui/keyboard.h +++ b/gui/keyboard.h @@ -2,7 +2,7 @@ #include "ui_keyboard_listener.h" #ifdef _WIN32 #include "opentrack/win32-shortcuts.h" -#include "opentrack/shortcuts.h" +#include "opentrack/keybinding-worker.hpp" #endif #include <QLabel> #include <QKeyEvent> @@ -13,25 +13,32 @@ class KeyboardListener : public QLabel Q_OBJECT Ui_keyboard_listener ui; #ifdef _WIN32 - KeybindingWorker w; + KeybindingWorker::Token token; #endif public: KeyboardListener(QWidget* parent = nullptr) : QLabel(parent) #ifdef _WIN32 - , w([&](Key& k) - { - Qt::KeyboardModifiers m; - QKeySequence k_; - if (win_key::to_qt(k, k_, m)) - key_pressed(static_cast<QVariant>(k_).toInt() | m); - }, this->winId()) + , token([&](const Key& k) { + if(k.guid != "") + { + int mods = 0; + if (k.alt) mods |= Qt::AltModifier; + if (k.shift) mods |= Qt::ShiftModifier; + if (k.ctrl) mods |= Qt::ControlModifier; + joystick_button_pressed(k.guid, k.keycode | mods, k.held); + } + else + { + Qt::KeyboardModifiers m; + QKeySequence k_; + if (win_key::to_qt(k, k_, m)) + key_pressed(static_cast<QVariant>(k_).toInt() | m); + } + }) #endif { ui.setupUi(this); setFocusPolicy(Qt::StrongFocus); -#ifdef _WIN32 - w.start(); -#endif } #ifndef _WIN32 void keyPressEvent(QKeyEvent* event) override @@ -47,4 +54,5 @@ public: #endif signals: void key_pressed(QKeySequence k); + void joystick_button_pressed(QString guid, int idx, bool held); }; diff --git a/gui/main.cpp b/gui/main.cpp index 4e56b3df..43a8b0c6 100644 --- a/gui/main.cpp +++ b/gui/main.cpp @@ -5,8 +5,8 @@ #include "opentrack/opencv-camera-dialog.hpp" #include "wizard.h" #include "ui.h" -#include "opentrack/options.hpp" #include "ui_install-driver-dialog.h" +#include "opentrack-compat/options.hpp" using namespace options; #include <QApplication> #include <QCommandLineParser> diff --git a/gui/main.ui b/gui/main.ui index 532d3124..43f725af 100644 --- a/gui/main.ui +++ b/gui/main.ui @@ -7,8 +7,8 @@ <rect> <x>0</x> <y>0</y> - <width>693</width> - <height>575</height> + <width>646</width> + <height>435</height> </rect> </property> <property name="windowIcon"> @@ -37,10 +37,10 @@ <number>0</number> </property> <property name="rightMargin"> - <number>0</number> + <number>6</number> </property> <property name="bottomMargin"> - <number>0</number> + <number>6</number> </property> <item> <widget class="QFrame" name="frame"> @@ -53,7 +53,10 @@ <property name="lineWidth"> <number>0</number> </property> - <layout class="QGridLayout" name="gridLayout_5"> + <layout class="QVBoxLayout" name="verticalLayout_5"> + <property name="spacing"> + <number>0</number> + </property> <property name="leftMargin"> <number>0</number> </property> @@ -66,11 +69,14 @@ <property name="bottomMargin"> <number>0</number> </property> - <property name="spacing"> - <number>0</number> - </property> - <item row="0" column="0"> + <item> <widget class="QFrame" name="top"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> <property name="frameShape"> <enum>QFrame::NoFrame</enum> </property> @@ -88,26 +94,20 @@ <number>0</number> </property> <property name="bottomMargin"> - <number>0</number> + <number>4</number> </property> <item> <widget class="QFrame" name="video_feed"> <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="minimumSize"> <size> - <width>480</width> - <height>360</height> - </size> - </property> - <property name="maximumSize"> - <size> - <width>480</width> - <height>360</height> + <width>320</width> + <height>240</height> </size> </property> <widget class="QFrame" name="video_frame"> @@ -115,12 +115,12 @@ <rect> <x>0</x> <y>0</y> - <width>480</width> - <height>360</height> + <width>320</width> + <height>240</height> </rect> </property> <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> @@ -130,8 +130,8 @@ <rect> <x>0</x> <y>0</y> - <width>480</width> - <height>360</height> + <width>320</width> + <height>240</height> </rect> </property> <property name="sizePolicy"> @@ -142,83 +142,761 @@ </property> <property name="minimumSize"> <size> - <width>480</width> - <height>360</height> + <width>320</width> + <height>240</height> </size> </property> <property name="maximumSize"> <size> - <width>480</width> - <height>360</height> + <width>320</width> + <height>240</height> </size> </property> <property name="text"> <string/> </property> + <property name="pixmap"> + <pixmap resource="ui-res.qrc">:/images/no-feed.png</pixmap> + </property> + <property name="scaledContents"> + <bool>true</bool> + </property> </widget> </widget> </widget> </item> <item> - <widget class="QFrame" name="top_display"> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> + <widget class="GLWidget" name="pose_display" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> </property> - <property name="lineWidth"> - <number>0</number> + <property name="minimumSize"> + <size> + <width>320</width> + <height>240</height> + </size> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QFrame" name="top_display"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <property name="spacing"> + <number>6</number> + </property> + <property name="leftMargin"> + <number>5</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>6</number> + </property> + <item> + <widget class="QGroupBox" name="box_raw_headpose"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string notr="true">Raw tracker data</string> </property> - <layout class="QVBoxLayout"> + <layout class="QGridLayout" name="gridLayout_12"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> <property name="spacing"> - <number>12</number> + <number>0</number> </property> + <item row="0" column="3"> + <widget class="QLCDNumber" name="raw_yaw"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="lineWidth"> + <number>1</number> + </property> + <property name="smallDecimalPoint"> + <bool>true</bool> + </property> + <property name="digitCount"> + <number>4</number> + </property> + <property name="segmentStyle"> + <enum>QLCDNumber::Outline</enum> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="lblZ_4"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="autoFillBackground"> + <bool>false</bool> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="text"> + <string>TZ</string> + </property> + </widget> + </item> + <item row="1" column="2"> + <widget class="QLabel" name="lblRotY_4"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="text"> + <string>pitch</string> + </property> + </widget> + </item> + <item row="1" column="3"> + <widget class="QLCDNumber" name="raw_pitch"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="lineWidth"> + <number>1</number> + </property> + <property name="smallDecimalPoint"> + <bool>true</bool> + </property> + <property name="digitCount"> + <number>4</number> + </property> + <property name="segmentStyle"> + <enum>QLCDNumber::Outline</enum> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="lblY_4"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="autoFillBackground"> + <bool>false</bool> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="text"> + <string>TY</string> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="lblX_4"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="text"> + <string>TX</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLCDNumber" name="raw_x"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="lineWidth"> + <number>1</number> + </property> + <property name="smallDecimalPoint"> + <bool>true</bool> + </property> + <property name="digitCount"> + <number>4</number> + </property> + <property name="segmentStyle"> + <enum>QLCDNumber::Outline</enum> + </property> + </widget> + </item> + <item row="2" column="2"> + <widget class="QLabel" name="lblRotZ_4"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="text"> + <string>roll</string> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="lblRotX_4"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="text"> + <string>yaw</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLCDNumber" name="raw_y"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="lineWidth"> + <number>1</number> + </property> + <property name="smallDecimalPoint"> + <bool>true</bool> + </property> + <property name="digitCount"> + <number>4</number> + </property> + <property name="segmentStyle"> + <enum>QLCDNumber::Outline</enum> + </property> + </widget> + </item> + <item row="2" column="3"> + <widget class="QLCDNumber" name="raw_roll"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="lineWidth"> + <number>1</number> + </property> + <property name="smallDecimalPoint"> + <bool>true</bool> + </property> + <property name="digitCount"> + <number>4</number> + </property> + <property name="segmentStyle"> + <enum>QLCDNumber::Outline</enum> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLCDNumber" name="raw_z"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="lineWidth"> + <number>1</number> + </property> + <property name="smallDecimalPoint"> + <bool>true</bool> + </property> + <property name="digitCount"> + <number>4</number> + </property> + <property name="segmentStyle"> + <enum>QLCDNumber::Outline</enum> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="box_mapped_headpose"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string notr="true">Game data</string> + </property> + <layout class="QGridLayout" name="gridLayout_14"> <property name="leftMargin"> - <number>6</number> + <number>0</number> </property> <property name="topMargin"> - <number>12</number> + <number>0</number> </property> <property name="rightMargin"> - <number>8</number> + <number>0</number> </property> <property name="bottomMargin"> - <number>4</number> + <number>0</number> </property> - <item> - <widget class="GLWidget" name="pose_display" native="true"> + <property name="spacing"> + <number>0</number> + </property> + <item row="1" column="3"> + <widget class="QLCDNumber" name="pose_pitch"> + <property name="enabled"> + <bool>true</bool> + </property> <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"> + <sizepolicy hsizetype="Minimum" vsizetype="Maximum"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="maximumSize"> - <size> - <width>110</width> - <height>120</height> - </size> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="smallDecimalPoint"> + <bool>true</bool> + </property> + <property name="digitCount"> + <number>4</number> + </property> + <property name="segmentStyle"> + <enum>QLCDNumber::Flat</enum> </property> </widget> </item> - <item> - <widget class="QGroupBox" name="box_raw_headpose"> + <item row="0" column="3"> + <widget class="QLCDNumber" name="pose_yaw"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="smallDecimalPoint"> + <bool>true</bool> + </property> + <property name="digitCount"> + <number>4</number> + </property> + <property name="segmentStyle"> + <enum>QLCDNumber::Flat</enum> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLCDNumber" name="pose_z"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="smallDecimalPoint"> + <bool>true</bool> + </property> + <property name="digitCount"> + <number>4</number> + </property> + <property name="segmentStyle"> + <enum>QLCDNumber::Flat</enum> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="lblx"> <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="text"> + <string>TX</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="lblY_2"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="autoFillBackground"> + <bool>false</bool> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="text"> + <string>TY</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLCDNumber" name="pose_x"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="smallDecimalPoint"> + <bool>true</bool> + </property> + <property name="digitCount"> + <number>4</number> + </property> + <property name="segmentStyle"> + <enum>QLCDNumber::Flat</enum> + </property> + </widget> + </item> + <item row="1" column="2"> + <widget class="QLabel" name="lblRotY_2"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="text"> + <string>pitch</string> + </property> + </widget> + </item> + <item row="2" column="2"> + <widget class="QLabel" name="lblRotZ_2"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="text"> + <string>roll</string> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="lblRotX_2"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="text"> + <string>yaw</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="lblZ_2"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="autoFillBackground"> + <bool>false</bool> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="text"> + <string>TZ</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLCDNumber" name="pose_y"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="smallDecimalPoint"> + <bool>true</bool> + </property> + <property name="digitCount"> + <number>4</number> + </property> + <property name="segmentStyle"> + <enum>QLCDNumber::Flat</enum> + </property> + </widget> + </item> + <item row="2" column="3"> + <widget class="QLCDNumber" name="pose_roll"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="smallDecimalPoint"> + <bool>true</bool> + </property> + <property name="digitCount"> + <number>4</number> + </property> + <property name="segmentStyle"> + <enum>QLCDNumber::Flat</enum> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QFrame" name="bottom_controls"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <layout class="QGridLayout" name="gridLayout_2"> + <property name="leftMargin"> + <number>6</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <item row="0" column="0"> + <widget class="QFrame" name="frame_2"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>4</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="spacing"> + <number>2</number> + </property> + <property name="leftMargin"> + <number>3</number> + </property> + <property name="topMargin"> + <number>2</number> + </property> + <property name="rightMargin"> + <number>3</number> + </property> + <property name="bottomMargin"> + <number>8</number> + </property> + <item> + <widget class="QGroupBox" name="groupGameProtocol"> <property name="title"> - <string notr="true">Raw tracker data</string> + <string>Protocol</string> </property> - <layout class="QGridLayout" name="gridLayout_12"> + <layout class="QGridLayout" name="gridLayout_4"> <property name="leftMargin"> - <number>0</number> + <number>4</number> </property> <property name="topMargin"> <number>0</number> </property> <property name="rightMargin"> - <number>0</number> + <number>4</number> </property> <property name="bottomMargin"> <number>0</number> @@ -227,322 +905,47 @@ <number>3</number> </property> <property name="verticalSpacing"> - <number>2</number> + <number>0</number> </property> - <item row="0" column="1"> - <widget class="QLCDNumber" name="raw_x"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Plain</enum> - </property> - <property name="lineWidth"> - <number>1</number> - </property> - <property name="smallDecimalPoint"> - <bool>true</bool> - </property> - <property name="digitCount"> - <number>4</number> - </property> - <property name="segmentStyle"> - <enum>QLCDNumber::Outline</enum> - </property> - </widget> - </item> - <item row="0" column="2"> - <widget class="QLabel" name="lblRotX_4"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <property name="text"> - <string>yaw</string> - </property> - </widget> - </item> - <item row="2" column="2"> - <widget class="QLabel" name="lblRotZ_4"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <property name="text"> - <string>roll</string> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="lblZ_4"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="autoFillBackground"> - <bool>false</bool> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <property name="text"> - <string>TZ</string> - </property> - </widget> - </item> - <item row="1" column="2"> - <widget class="QLabel" name="lblRotY_4"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <property name="text"> - <string>pitch</string> - </property> - </widget> + <item row="1" column="0"> + <widget class="QComboBox" name="iconcomboProtocol"/> </item> <item row="1" column="1"> - <widget class="QLCDNumber" name="raw_y"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Plain</enum> - </property> - <property name="lineWidth"> - <number>1</number> - </property> - <property name="smallDecimalPoint"> - <bool>true</bool> - </property> - <property name="digitCount"> - <number>4</number> - </property> - <property name="segmentStyle"> - <enum>QLCDNumber::Outline</enum> - </property> - </widget> - </item> - <item row="0" column="3"> - <widget class="QLCDNumber" name="raw_yaw"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Plain</enum> - </property> - <property name="lineWidth"> - <number>1</number> - </property> - <property name="smallDecimalPoint"> - <bool>true</bool> - </property> - <property name="digitCount"> - <number>4</number> - </property> - <property name="segmentStyle"> - <enum>QLCDNumber::Outline</enum> - </property> - </widget> - </item> - <item row="2" column="3"> - <widget class="QLCDNumber" name="raw_roll"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Plain</enum> - </property> - <property name="lineWidth"> - <number>1</number> - </property> - <property name="smallDecimalPoint"> - <bool>true</bool> - </property> - <property name="digitCount"> - <number>4</number> - </property> - <property name="segmentStyle"> - <enum>QLCDNumber::Outline</enum> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="QLCDNumber" name="raw_z"> + <widget class="QToolButton" name="btnShowServerControls"> <property name="enabled"> <bool>true</bool> </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Plain</enum> - </property> - <property name="lineWidth"> - <number>1</number> - </property> - <property name="smallDecimalPoint"> - <bool>true</bool> - </property> - <property name="digitCount"> - <number>4</number> - </property> - <property name="segmentStyle"> - <enum>QLCDNumber::Outline</enum> - </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QLabel" name="lblX_4"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> <property name="text"> - <string>TX</string> - </property> - </widget> - </item> - <item row="1" column="3"> - <widget class="QLCDNumber" name="raw_pitch"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Plain</enum> - </property> - <property name="lineWidth"> - <number>1</number> - </property> - <property name="smallDecimalPoint"> - <bool>true</bool> - </property> - <property name="digitCount"> - <number>4</number> - </property> - <property name="segmentStyle"> - <enum>QLCDNumber::Outline</enum> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="lblY_4"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> + <string>...</string> </property> - <property name="autoFillBackground"> + <property name="flat" stdset="0"> <bool>false</bool> </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <property name="text"> - <string>TY</string> - </property> </widget> </item> </layout> </widget> </item> <item> - <widget class="QGroupBox" name="box_mapped_headpose"> + <widget class="QGroupBox" name="groupStartStop"> <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum"> - <horstretch>0</horstretch> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>3</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="title"> - <string notr="true">Game data</string> + <string notr="true">Controls</string> </property> - <layout class="QGridLayout" name="gridLayout_14"> + <layout class="QHBoxLayout" name="horizontalLayout_4"> + <property name="spacing"> + <number>8</number> + </property> <property name="leftMargin"> <number>0</number> </property> <property name="topMargin"> - <number>0</number> + <number>4</number> </property> <property name="rightMargin"> <number>0</number> @@ -550,267 +953,32 @@ <property name="bottomMargin"> <number>0</number> </property> - <property name="horizontalSpacing"> - <number>3</number> - </property> - <property name="verticalSpacing"> - <number>2</number> - </property> - <item row="1" column="0"> - <widget class="QLabel" name="lblY_2"> - <property name="enabled"> - <bool>true</bool> - </property> + <item> + <widget class="QToolButton" name="btnStartTracker"> <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> + <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="autoFillBackground"> - <bool>false</bool> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> <property name="text"> - <string>TY</string> + <string>Start</string> </property> </widget> </item> - <item row="2" column="0"> - <widget class="QLabel" name="lblZ_2"> + <item> + <widget class="QToolButton" name="btnStopTracker"> <property name="enabled"> - <bool>true</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="autoFillBackground"> <bool>false</bool> </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <property name="text"> - <string>TZ</string> - </property> - </widget> - </item> - <item row="2" column="2"> - <widget class="QLabel" name="lblRotZ_2"> <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> + <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> <property name="text"> - <string>roll</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QLCDNumber" name="pose_x"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="smallDecimalPoint"> - <bool>true</bool> - </property> - <property name="digitCount"> - <number>4</number> - </property> - <property name="segmentStyle"> - <enum>QLCDNumber::Flat</enum> - </property> - </widget> - </item> - <item row="0" column="2"> - <widget class="QLabel" name="lblRotX_2"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <property name="text"> - <string>yaw</string> - </property> - </widget> - </item> - <item row="1" column="2"> - <widget class="QLabel" name="lblRotY_2"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <property name="text"> - <string>pitch</string> - </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QLabel" name="lblx"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <property name="text"> - <string>TX</string> - </property> - </widget> - </item> - <item row="1" column="3"> - <widget class="QLCDNumber" name="pose_pitch"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="smallDecimalPoint"> - <bool>true</bool> - </property> - <property name="digitCount"> - <number>4</number> - </property> - <property name="segmentStyle"> - <enum>QLCDNumber::Flat</enum> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QLCDNumber" name="pose_y"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="smallDecimalPoint"> - <bool>true</bool> - </property> - <property name="digitCount"> - <number>4</number> - </property> - <property name="segmentStyle"> - <enum>QLCDNumber::Flat</enum> - </property> - </widget> - </item> - <item row="2" column="3"> - <widget class="QLCDNumber" name="pose_roll"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="smallDecimalPoint"> - <bool>true</bool> - </property> - <property name="digitCount"> - <number>4</number> - </property> - <property name="segmentStyle"> - <enum>QLCDNumber::Flat</enum> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="QLCDNumber" name="pose_z"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="smallDecimalPoint"> - <bool>true</bool> - </property> - <property name="digitCount"> - <number>4</number> - </property> - <property name="segmentStyle"> - <enum>QLCDNumber::Flat</enum> - </property> - </widget> - </item> - <item row="0" column="3"> - <widget class="QLCDNumber" name="pose_yaw"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="smallDecimalPoint"> - <bool>true</bool> - </property> - <property name="digitCount"> - <number>4</number> - </property> - <property name="segmentStyle"> - <enum>QLCDNumber::Flat</enum> + <string>Stop</string> </property> </widget> </item> @@ -820,141 +988,89 @@ </layout> </widget> </item> - </layout> - </widget> - </item> - <item row="1" column="0"> - <widget class="QFrame" name="bottom_controls"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <layout class="QGridLayout" name="gridLayout_2"> - <property name="leftMargin"> - <number>4</number> - </property> - <property name="topMargin"> - <number>8</number> - </property> - <property name="rightMargin"> - <number>10</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <property name="horizontalSpacing"> - <number>4</number> - </property> - <property name="verticalSpacing"> - <number>0</number> - </property> - <item row="1" column="1"> - <widget class="QGroupBox" name="groupWindows"> + <item row="0" column="1"> + <widget class="QFrame" name="groupWindows"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>4</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="title"> - <string>Settings</string> - </property> - <property name="flat"> - <bool>true</bool> + <property name="lineWidth"> + <number>0</number> </property> <layout class="QVBoxLayout" name="verticalLayout_3"> <property name="spacing"> <number>3</number> </property> <property name="leftMargin"> - <number>4</number> + <number>0</number> </property> <property name="topMargin"> - <number>2</number> + <number>0</number> </property> <property name="rightMargin"> <number>0</number> </property> <property name="bottomMargin"> - <number>6</number> + <number>0</number> </property> <item> - <widget class="QGroupBox" name="groupGameProtocol"> - <property name="title"> - <string>Protocol</string> + <widget class="QFrame" name="groupProfile"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> </property> - <layout class="QGridLayout" name="gridLayout_4"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="spacing"> + <number>0</number> + </property> <property name="leftMargin"> - <number>4</number> + <number>0</number> </property> <property name="topMargin"> <number>0</number> </property> <property name="rightMargin"> - <number>4</number> - </property> - <property name="bottomMargin"> <number>0</number> </property> - <property name="horizontalSpacing"> - <number>3</number> - </property> - <property name="verticalSpacing"> + <property name="bottomMargin"> <number>0</number> </property> - <item row="0" column="0"> - <widget class="QComboBox" name="iconcomboProtocol"/> - </item> - <item row="0" column="1"> - <widget class="QToolButton" name="btnShowServerControls"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="text"> - <string>...</string> - </property> - <property name="flat" stdset="0"> - <bool>false</bool> - </property> - </widget> - </item> </layout> </widget> </item> <item> - <widget class="QFrame" name="groupProfile"> + <widget class="QFrame" name="frame_3"> <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding"> + <sizepolicy hsizetype="Minimum" vsizetype="Maximum"> <horstretch>0</horstretch> - <verstretch>2</verstretch> + <verstretch>0</verstretch> </sizepolicy> </property> - <layout class="QHBoxLayout" name="horizontalLayout"> + <layout class="QHBoxLayout" name="horizontalLayout_5"> <property name="spacing"> <number>0</number> </property> <property name="leftMargin"> <number>0</number> </property> + <property name="topMargin"> + <number>0</number> + </property> <property name="rightMargin"> - <number>2</number> + <number>0</number> </property> <property name="bottomMargin"> - <number>2</number> + <number>0</number> </property> <item> <widget class="QToolButton" name="profile_button"> <property name="enabled"> <bool>true</bool> </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> <property name="text"> <string>Profile</string> </property> @@ -975,7 +1091,7 @@ <item> <widget class="QComboBox" name="iconcomboProfile"> <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> @@ -991,9 +1107,9 @@ <item> <widget class="QPushButton" name="btnEditCurves"> <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> <horstretch>0</horstretch> - <verstretch>3</verstretch> + <verstretch>0</verstretch> </sizepolicy> </property> <property name="text"> @@ -1014,9 +1130,9 @@ <item> <widget class="QPushButton" name="btnShortcuts"> <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> <horstretch>0</horstretch> - <verstretch>3</verstretch> + <verstretch>0</verstretch> </sizepolicy> </property> <property name="text"> @@ -1037,68 +1153,6 @@ </layout> </widget> </item> - <item row="1" column="0"> - <widget class="QGroupBox" name="groupStartStop"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>3</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="title"> - <string notr="true">Controls</string> - </property> - <property name="flat"> - <bool>true</bool> - </property> - <layout class="QVBoxLayout" name="verticalLayout_4"> - <property name="spacing"> - <number>8</number> - </property> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>8</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>9</number> - </property> - <item> - <widget class="QToolButton" name="btnStartTracker"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Start</string> - </property> - </widget> - </item> - <item> - <widget class="QToolButton" name="btnStopTracker"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Stop</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> </layout> </widget> </item> @@ -1116,12 +1170,12 @@ </customwidget> </customwidgets> <tabstops> - <tabstop>btnStartTracker</tabstop> <tabstop>btnStopTracker</tabstop> <tabstop>iconcomboProtocol</tabstop> <tabstop>btnShowServerControls</tabstop> - <tabstop>btnEditCurves</tabstop> <tabstop>btnShortcuts</tabstop> + <tabstop>profile_button</tabstop> + <tabstop>iconcomboProfile</tabstop> </tabstops> <resources> <include location="ui-res.qrc"/> diff --git a/gui/new_file_dialog.h b/gui/new_file_dialog.h index 3a35cf71..5fdabb3a 100644 --- a/gui/new_file_dialog.h +++ b/gui/new_file_dialog.h @@ -1,7 +1,7 @@ #pragma once #include "ui_new_config.h" -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" #include <QFile> #include <QRegExp> #include <QString> diff --git a/gui/options-dialog.cpp b/gui/options-dialog.cpp index 06346b25..1e734135 100644 --- a/gui/options-dialog.cpp +++ b/gui/options-dialog.cpp @@ -11,38 +11,42 @@ #include "keyboard.h" #include <QPushButton> #include <QLayout> +#include <QDialog> -OptionsDialog::OptionsDialog(State& state) : state(state), trans_calib_running(false) +static QString kopts_to_string(const key_opts& kopts) { - ui.setupUi( this ); + if (static_cast<QString>(kopts.guid) != "") + { + const int btn = kopts.button & ~Qt::KeyboardModifierMask; + const int mods = kopts.button & Qt::KeyboardModifierMask; + QString mm; + if (mods & Qt::ControlModifier) mm += "Control+"; + if (mods & Qt::AltModifier) mm += "Alt+"; + if (mods & Qt::ShiftModifier) mm += "Shift+"; + return mm + "Joy button " + QString::number(btn); + } + if (static_cast<QString>(kopts.keycode) == "") + return "None"; + return kopts.keycode; +} + +OptionsDialog::OptionsDialog(main_settings& main, + State& state, + std::function<void()> register_global_keys, + std::function<void(bool)> pause_keybindings) : + main(main), + state(state), + register_global_keys(register_global_keys), + pause_keybindings(pause_keybindings) +{ + ui.setupUi(this); connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(doOK())); connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(doCancel())); - tie_setting(s.s_main.tray_enabled, ui.trayp); - - tie_setting(s.s_main.center_at_startup, ui.center_at_startup); + tie_setting(main.tray_enabled, ui.trayp); - tie_setting(s.s_main.tcomp_p, ui.tcomp_enable); - tie_setting(s.s_main.tcomp_tz, ui.tcomp_rz); - - tie_setting(s.s_main.a_yaw.invert, ui.invert_yaw); - tie_setting(s.s_main.a_pitch.invert, ui.invert_pitch); - tie_setting(s.s_main.a_roll.invert, ui.invert_roll); - tie_setting(s.s_main.a_x.invert, ui.invert_x); - tie_setting(s.s_main.a_y.invert, ui.invert_y); - tie_setting(s.s_main.a_z.invert, ui.invert_z); - - tie_setting(s.s_main.a_yaw.src, ui.src_yaw); - tie_setting(s.s_main.a_pitch.src, ui.src_pitch); - tie_setting(s.s_main.a_roll.src, ui.src_roll); - tie_setting(s.s_main.a_x.src, ui.src_x); - tie_setting(s.s_main.a_y.src, ui.src_y); - tie_setting(s.s_main.a_z.src, ui.src_z); - - tie_setting(s.s_main.camera_yaw, ui.camera_yaw); - tie_setting(s.s_main.camera_pitch, ui.camera_pitch); - tie_setting(s.s_main.camera_roll, ui.camera_roll); + tie_setting(main.center_at_startup, ui.center_at_startup); tie_setting(pt.camera_mode, ui.camera_mode); @@ -86,48 +90,96 @@ OptionsDialog::OptionsDialog(State& state) : state(state), trans_calib_running(f timer.start(100); - connect(ui.bind_center, &QPushButton::pressed, [&]() -> void { bind_key(s.center.keycode, ui.center_text); }); - connect(ui.bind_zero, &QPushButton::pressed, [&]() -> void { bind_key(s.zero.keycode, ui.zero_text); }); - connect(ui.bind_toggle, &QPushButton::pressed, [&]() -> void { bind_key(s.toggle.keycode, ui.toggle_text); }); + tie_setting(main.tcomp_p, ui.tcomp_enable); + tie_setting(main.tcomp_tz, ui.tcomp_rz); + + tie_setting(main.a_yaw.invert, ui.invert_yaw); + tie_setting(main.a_pitch.invert, ui.invert_pitch); + tie_setting(main.a_roll.invert, ui.invert_roll); + tie_setting(main.a_x.invert, ui.invert_x); + tie_setting(main.a_y.invert, ui.invert_y); + tie_setting(main.a_z.invert, ui.invert_z); - ui.center_text->setText(s.center.keycode == "" ? "None" : static_cast<QString>(s.center.keycode)); - ui.toggle_text->setText(s.toggle.keycode == "" ? "None" : static_cast<QString>(s.toggle.keycode)); - ui.zero_text->setText(s.zero.keycode == "" ? "None" : static_cast<QString>(s.zero.keycode)); + tie_setting(main.a_yaw.src, ui.src_yaw); + tie_setting(main.a_pitch.src, ui.src_pitch); + tie_setting(main.a_roll.src, ui.src_roll); + tie_setting(main.a_x.src, ui.src_x); + tie_setting(main.a_y.src, ui.src_y); + tie_setting(main.a_z.src, ui.src_z); + + tie_setting(main.camera_yaw, ui.camera_yaw); + tie_setting(main.camera_pitch, ui.camera_pitch); + tie_setting(main.camera_roll, ui.camera_roll); + + tie_setting(main.center_method, ui.center_method); + + connect(ui.bind_center, &QPushButton::pressed, [&]() -> void { bind_key(main.key_center, ui.center_text); }); + connect(ui.bind_zero, &QPushButton::pressed, [&]() -> void { bind_key(main.key_zero, ui.zero_text); }); + connect(ui.bind_toggle, &QPushButton::pressed, [&]() -> void { bind_key(main.key_toggle, ui.toggle_text); }); + connect(ui.bind_start, &QPushButton::pressed, [&]() -> void { bind_key(main.key_start_tracking, ui.start_tracking_text); }); + connect(ui.bind_stop, &QPushButton::pressed, [&]() -> void { bind_key(main.key_stop_tracking, ui.stop_tracking_text); }); + connect(ui.bind_toggle_tracking, &QPushButton::pressed, [&]() -> void { bind_key(main.key_toggle_tracking, ui.toggle_tracking_text); }); + + ui.center_text->setText(kopts_to_string(main.key_center)); + ui.toggle_text->setText(kopts_to_string(main.key_toggle)); + ui.zero_text->setText(kopts_to_string(main.key_zero)); + + ui.start_tracking_text->setText(kopts_to_string(main.key_start_tracking)); + ui.stop_tracking_text->setText(kopts_to_string(main.key_stop_tracking)); + ui.toggle_tracking_text->setText(kopts_to_string(main.key_toggle_tracking)); } -void OptionsDialog::bind_key(value<QString>& ret, QLabel* label) +void OptionsDialog::bind_key(key_opts& kopts, QLabel* label) { - ret = ""; - QDialog d; + kopts.button = -1; + kopts.guid = ""; + kopts.keycode = ""; + QDialog d(this); auto l = new QHBoxLayout; l->setMargin(0); - auto k = new KeyboardListener; - l->addWidget(k); + KeyboardListener k; + l->addWidget(&k); d.setLayout(l); d.setFixedSize(QSize(500, 300)); d.setWindowFlags(Qt::Dialog); - connect(k, &KeyboardListener::key_pressed, [&] (QKeySequence s) -> void { ret = s.toString(QKeySequence::PortableText); d.close(); }); + d.setWindowModality(Qt::ApplicationModal); + connect(&k, &KeyboardListener::key_pressed, [&] (QKeySequence s) -> void { + kopts.keycode = s.toString(QKeySequence::PortableText); + kopts.guid = ""; + kopts.button = -1; + d.close(); + }); + connect(&k, &KeyboardListener::joystick_button_pressed, [&](QString guid, int idx, bool held) -> void { + if (!held) + { + kopts.guid = guid; + kopts.keycode = ""; + kopts.button = idx; + d.close(); + } + }); + pause_keybindings(true); + d.show(); d.exec(); - label->setText(ret == "" ? "None" : static_cast<QString>(ret)); - delete k; + pause_keybindings(false); + register_global_keys(); + label->setText(kopts_to_string(kopts)); delete l; } void OptionsDialog::doOK() { - s.b->save(); pt.b->save(); - s.s_main.b->save(); acc.b->save(); + main.b->save(); ui.game_detector->save(); this->close(); emit reload(); } void OptionsDialog::doCancel() { - s.b->reload(); pt.b->reload(); - s.s_main.b->reload(); acc.b->reload(); + main.b->reload(); ui.game_detector->revert(); close(); } diff --git a/gui/options-dialog.hpp b/gui/options-dialog.hpp index 8fc16611..f333c690 100644 --- a/gui/options-dialog.hpp +++ b/gui/options-dialog.hpp @@ -10,6 +10,9 @@ #include "trans_calib.h" #include "tracker-pt/ftnoir_tracker_pt.h" #include "filter-accela/ftnoir_filter_accela.h" +#include <QObject> +#include <QWidget> +#include <functional> class OptionsDialog: public QWidget { @@ -17,14 +20,16 @@ class OptionsDialog: public QWidget signals: void reload(); public: - OptionsDialog(State &state); + OptionsDialog(main_settings& main, State& state, std::function<void()> register_global_keys, std::function<void(bool)> pause_keybindings); private: + main_settings& main; + State& state; + std::function<void()> register_global_keys; + std::function<void(bool)> pause_keybindings; Ui::UI_Settings ui; - Shortcuts::settings s; settings_pt pt; settings_accela acc; QTimer timer; - State& state; TranslationCalibrator trans_calib; bool trans_calib_running; @@ -42,5 +47,5 @@ private slots: void startstop_trans_calib(bool start); void poll_tracker_info(); void trans_calib_step(); - void bind_key(value<QString>& ret, QLabel* label); + void bind_key(key_opts &kopts, QLabel* label); }; diff --git a/gui/process_detector.h b/gui/process_detector.h index f6497c90..e395e1a2 100644 --- a/gui/process_detector.h +++ b/gui/process_detector.h @@ -13,7 +13,7 @@ #include <QTableWidget> #include <QResizeEvent> -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; class FancyTable : public QTableWidget diff --git a/gui/settings.ui b/gui/settings.ui index 5bf819fd..cb292a35 100644 --- a/gui/settings.ui +++ b/gui/settings.ui @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>428</width> - <height>535</height> + <height>525</height> </rect> </property> <property name="windowTitle"> @@ -34,6 +34,33 @@ <string>Shortcuts</string> </attribute> <layout class="QGridLayout" name="gridLayout_9"> + <item row="2" column="0"> + <widget class="QCheckBox" name="center_at_startup"> + <property name="text"> + <string>Center at startup</string> + </property> + </widget> + </item> + <item row="4" column="0"> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item row="3" column="0"> + <widget class="QCheckBox" name="trayp"> + <property name="text"> + <string>Minimize to tray</string> + </property> + </widget> + </item> <item row="0" column="0"> <widget class="QGroupBox" name="groupBox_8"> <property name="title"> @@ -62,8 +89,15 @@ <string notr="true">QGroupBox { border: 0; }</string> </property> <layout class="QGridLayout" name="gridLayout_8"> - <item row="0" column="1"> - <widget class="QLabel" name="center_text"> + <item row="6" column="1"> + <widget class="QLabel" name="zero_text"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="5" column="1"> + <widget class="QLabel" name="toggle_text"> <property name="text"> <string/> </property> @@ -79,17 +113,10 @@ </property> </widget> </item> - <item row="6" column="1"> - <widget class="QLabel" name="zero_text"> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item row="5" column="1"> - <widget class="QLabel" name="toggle_text"> + <item row="0" column="2"> + <widget class="QPushButton" name="bind_center"> <property name="text"> - <string/> + <string>Bind</string> </property> </widget> </item> @@ -113,8 +140,8 @@ </property> </widget> </item> - <item row="0" column="2"> - <widget class="QPushButton" name="bind_center"> + <item row="6" column="2"> + <widget class="QPushButton" name="bind_zero"> <property name="text"> <string>Bind</string> </property> @@ -127,13 +154,85 @@ </property> </widget> </item> - <item row="6" column="2"> - <widget class="QPushButton" name="bind_zero"> + <item row="7" column="0"> + <widget class="QLabel" name="textLabel2_7"> + <property name="text"> + <string>Start tracking</string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLabel" name="center_text"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="8" column="0"> + <widget class="QLabel" name="textLabel2_8"> + <property name="text"> + <string>Stop tracking</string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="9" column="0"> + <widget class="QLabel" name="textLabel2_9"> + <property name="text"> + <string>Toggle tracking</string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="7" column="2"> + <widget class="QPushButton" name="bind_start"> + <property name="text"> + <string>Bind</string> + </property> + </widget> + </item> + <item row="8" column="2"> + <widget class="QPushButton" name="bind_stop"> <property name="text"> <string>Bind</string> </property> </widget> </item> + <item row="9" column="2"> + <widget class="QPushButton" name="bind_toggle_tracking"> + <property name="text"> + <string>Bind</string> + </property> + </widget> + </item> + <item row="7" column="1"> + <widget class="QLabel" name="start_tracking_text"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="8" column="1"> + <widget class="QLabel" name="stop_tracking_text"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="9" column="1"> + <widget class="QLabel" name="toggle_tracking_text"> + <property name="text"> + <string/> + </property> + </widget> + </item> </layout> </widget> </item> @@ -141,32 +240,45 @@ </widget> </item> <item row="1" column="0"> - <widget class="QCheckBox" name="center_at_startup"> - <property name="text"> - <string>Center at startup</string> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QCheckBox" name="trayp"> - <property name="text"> - <string>Minimize to tray</string> + <widget class="QGroupBox" name="groupBox_9111"> + <property name="title"> + <string>Centering method</string> </property> + <layout class="QGridLayout" name="gridLayout111"> + <item row="1" column="0"> + <widget class="QLabel" name="label_26"> + <property name="text"> + <string>Method</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="center_method"> + <item> + <property name="text"> + <string>Relative (inertial device)</string> + </property> + </item> + <item> + <property name="text"> + <string>Absolute (camera device)</string> + </property> + </item> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLabel" name="label_25"> + <property name="text"> + <string>Try changing this if centering doesn't perform correctly for your input device.</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> </widget> </item> - <item row="3" column="0"> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> </layout> </widget> <widget class="QWidget" name="tab_3"> diff --git a/gui/software-update-dialog.hpp b/gui/software-update-dialog.hpp index fe132402..21d92ecc 100644 --- a/gui/software-update-dialog.hpp +++ b/gui/software-update-dialog.hpp @@ -7,7 +7,7 @@ #include <QRegExp> #include <functional> #include "ui_software-update.h" -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" extern "C" const char* opentrack_version; @@ -8,9 +8,9 @@ #include "ui.h" #include "opentrack/tracker.h" -#include "opentrack/options.hpp" #include "tracker-pt/ftnoir_tracker_pt.h" #include "filter-accela/ftnoir_filter_accela.h" +#include "opentrack-compat/options.hpp" #include "new_file_dialog.h" #include <QFileDialog> #include <QDesktopServices> @@ -24,8 +24,8 @@ MainWindow::MainWindow() : pose_update_timer(this), kbd_quit(QKeySequence("Ctrl+Q"), this), - no_feed_pixmap(":/images/no-feed.png"), is_refreshing_profiles(false), + keys_paused(false), update_query(this) { ui.setupUi(this); @@ -33,7 +33,6 @@ MainWindow::MainWindow() : setFixedSize(size()); updateButtonState(false, false); - ui.video_frame_label->setPixmap(no_feed_pixmap); connect(ui.btnEditCurves, SIGNAL(clicked()), this, SLOT(showCurveConfiguration())); connect(ui.btnShortcuts, SIGNAL(clicked()), this, SLOT(show_options_dialog())); @@ -91,7 +90,23 @@ MainWindow::MainWindow() : "Configuration not saved.", "Can't create configuration directory! Expect major malfunction.", QMessageBox::Ok, QMessageBox::NoButton); - + + connect(this, &MainWindow::emit_start_tracker, + this, [&]() -> void { if (keys_paused) return; qDebug() << "start tracker"; startTracker(); }, + Qt::QueuedConnection); + + connect(this, &MainWindow::emit_stop_tracker, + this, [&]() -> void { if (keys_paused) return; qDebug() << "stop tracker"; stopTracker(); }, + Qt::QueuedConnection); + + connect(this, &MainWindow::emit_toggle_tracker, + this, [&]() -> void { if (keys_paused) return; qDebug() << "toggle tracker"; if (work) stopTracker(); else startTracker(); }, + Qt::QueuedConnection); + + register_shortcuts(); + + connect(this, &MainWindow::emit_minimized, this, &MainWindow::mark_minimized, Qt::QueuedConnection); + ui.btnStartTracker->setFocus(); update_query.maybe_show_dialog(); @@ -105,6 +120,22 @@ void MainWindow::closeEvent(QCloseEvent *e) e->accept(); } +void MainWindow::register_shortcuts() +{ + using t_shortcut = std::tuple<key_opts&, Shortcuts::fun>; + + std::vector<t_shortcut> keys { + t_shortcut(s.key_start_tracking, [&]() -> void { emit_start_tracker(); }), + t_shortcut(s.key_stop_tracking, [&]() -> void { emit_stop_tracker(); }), + t_shortcut(s.key_toggle_tracking, [&]() -> void { emit_toggle_tracker(); }), + }; + + global_shortcuts.reload(keys); + + if (work) + work->reload_shortcuts(); +} + bool MainWindow::get_new_config_name_from_dialog(QString& ret) { new_file_dialog dlg; @@ -252,6 +283,9 @@ void MainWindow::reload_options() } void MainWindow::startTracker() { + if (work) + return; + // tracker dtor needs run first work = nullptr; @@ -272,7 +306,7 @@ void MainWindow::startTracker() { return; } - work = std::make_shared<Work>(s, pose, libs, this, winId()); + work = std::make_shared<Work>(s, pose, libs, winId()); reload_options(); @@ -291,7 +325,10 @@ void MainWindow::startTracker() { ui.btnStopTracker->setFocus(); } -void MainWindow::stopTracker( ) { +void MainWindow::stopTracker() { + if (!work) + return; + //ui.game_name->setText("Not connected"); pose_update_timer.stop(); @@ -361,6 +398,9 @@ void MainWindow::set_title(const QString& game_title_) void MainWindow::showHeadPose() { + if (!ui.video_frame->isEnabled()) + return; + double mapped[6], raw[6]; work->tracker->get_raw_and_mapped_poses(mapped, raw); @@ -386,7 +426,6 @@ bool mk_dialog(mem<dylib> lib, mem<t>* orig) *orig = dialog; dialog->show(); - dialog->raise(); return true; } @@ -398,7 +437,7 @@ void MainWindow::showProtocolSettings() { pProtocolDialog->register_protocol(libs.pProtocol.get()); } template<typename t, typename... Args> -bool mk_window(mem<t>* place, Args... params) +bool mk_window(mem<t>* place, Args&&... params) { if (*place && (*place)->isVisible()) { @@ -408,21 +447,24 @@ bool mk_window(mem<t>* place, Args... params) } else { - *place = std::make_shared<t>(params...); + *place = std::make_shared<t>(std::forward<Args>(params)...); (*place)->setWindowFlags(Qt::Dialog); (*place)->show(); - (*place)->raise(); return true; } } void MainWindow::show_options_dialog() { - if (mk_window<OptionsDialog, State&>(&options_widget, static_cast<State&>(*this))) + if (mk_window(&options_widget, + s, + *this, + [&]() -> void { register_shortcuts(); }, + [&](bool flag) -> void { keys_paused = flag; })) connect(options_widget.get(), SIGNAL(reload()), this, SLOT(reload_options())); } void MainWindow::showCurveConfiguration() { - mk_window<MapWidget, Mappings&, main_settings&>(&mapping_widget, pose, s); + mk_window(&mapping_widget, pose, s); } bool MainWindow::maybe_not_close_tracking() @@ -468,27 +510,6 @@ void MainWindow::profileSelected(QString name) } } -void MainWindow::shortcutRecentered() -{ - qDebug() << "Center"; - if (work) - work->tracker->center(); -} - -void MainWindow::shortcutToggled() -{ - qDebug() << "Toggle"; - if (work) - work->tracker->toggle_enabled(); -} - -void MainWindow::shortcutZeroed() -{ - qDebug() << "Zero"; - if (work) - work->tracker->zero(); -} - void MainWindow::ensure_tray() { if (tray) @@ -512,15 +533,28 @@ void MainWindow::restore_from_tray(QSystemTrayIcon::ActivationReason) void MainWindow::changeEvent(QEvent* e) { - if (s.tray_enabled && e->type() == QEvent::WindowStateChange && (windowState() & Qt::WindowMinimized)) + if (e->type() == QEvent::WindowStateChange) { - if (!tray) - ensure_tray(); - hide(); + const bool is_minimized = windowState() & Qt::WindowMinimized; + + if (s.tray_enabled && is_minimized) + { + if (!tray) + ensure_tray(); + hide(); + } + + emit_minimized(is_minimized); } + QMainWindow::changeEvent(e); } +void MainWindow::mark_minimized(bool is_minimized) +{ + ui.video_frame->setEnabled(!is_minimized); +} + void MainWindow::maybe_start_profile_from_executable() { if (!work) @@ -17,9 +17,12 @@ #include <QString> #include <QMenu> +#include <vector> +#include <tuple> + #include "ui_main.h" -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" #include "opentrack/main-settings.hpp" #include "opentrack/plugin-support.hpp" #include "opentrack/tracker.h" @@ -33,9 +36,11 @@ using namespace options; -class MainWindow : public QMainWindow, private State +class MainWindow : public QMainWindow, public State { Q_OBJECT + + Shortcuts global_shortcuts; Ui::OpentrackUI ui; mem<QSystemTrayIcon> tray; @@ -45,11 +50,11 @@ class MainWindow : public QMainWindow, private State mem<OptionsDialog> options_widget; mem<MapWidget> mapping_widget; QShortcut kbd_quit; - QPixmap no_feed_pixmap; mem<IProtocolDialog> pProtocolDialog; process_detector_worker det; QMenu profile_menu; bool is_refreshing_profiles; + volatile bool keys_paused; QTimer save_timer; update_dialog::query update_query; @@ -70,6 +75,7 @@ class MainWindow : public QMainWindow, private State void maybe_save(); bool maybe_not_close_tracking(); void closeEvent(QCloseEvent *e) override; + void register_shortcuts(); private slots: void _save(); void save(); @@ -92,10 +98,13 @@ private slots: void startTracker(); void stopTracker(); void reload_options(); -public slots: - void shortcutRecentered(); - void shortcutToggled(); - void shortcutZeroed(); + void mark_minimized(bool is_minimized); +signals: + void emit_start_tracker(); + void emit_stop_tracker(); + void emit_toggle_tracker(); + + void emit_minimized(bool); public: MainWindow(); ~MainWindow(); diff --git a/gui/wizard.h b/gui/wizard.h index ea848e36..9d359172 100644 --- a/gui/wizard.h +++ b/gui/wizard.h @@ -1,6 +1,6 @@ #pragma once -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" #include "opentrack/main-settings.hpp" #include "opentrack/mappings.hpp" #include "ui_trackhat-wizard.h" diff --git a/make-tar.sh b/make-tar.sh index 3e119d12..08114127 100644 --- a/make-tar.sh +++ b/make-tar.sh @@ -4,7 +4,7 @@ prefix="$1" filename="$2" bin="$3" -cmake --build "$bin" --target install || exit 1 +cmake --build "$bin" --target install -- -j4 || exit 1 if : && cd $(dirname -- "${prefix}") && diff --git a/opentrack-compat/CMakeLists.txt b/opentrack-compat/CMakeLists.txt index a92f4f31..8dba67e2 100644 --- a/opentrack-compat/CMakeLists.txt +++ b/opentrack-compat/CMakeLists.txt @@ -1,4 +1,5 @@ -opentrack_boilerplate(opentrack-compat NO-COMPAT NO-LINKER-SCRIPT) +opentrack_boilerplate(opentrack-compat NO-COMPAT NO-LINKER-SCRIPT LINKAGE) if(NOT WIN32 AND NOT APPLE) target_link_libraries(opentrack-compat rt) endif() +link_with_dinput8(opentrack-compat) diff --git a/opentrack/camera-names.hpp b/opentrack-compat/camera-names.cpp index f6ab736e..72bcf41a 100644 --- a/opentrack/camera-names.hpp +++ b/opentrack-compat/camera-names.cpp @@ -1,16 +1,4 @@ -/* 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 <QList> -#include <QString> -#include <QDebug> +#include "camera-names.hpp" #if defined(OPENTRACK_API) && defined(_WIN32) # define NO_DSHOW_STRSAFE @@ -29,8 +17,18 @@ #include <cerrno> #endif -template<typename = void> -QList<QString> get_camera_names() { +#include <QDebug> + +OPENTRACK_COMPAT_EXPORT int camera_name_to_index(const QString &name) +{ + auto list = get_camera_names(); + int ret = list.indexOf(name); + if (ret < 0) + ret = 0; + return ret; +} + +OPENTRACK_COMPAT_EXPORT QList<QString> get_camera_names() { QList<QString> ret; #if defined(_WIN32) // Create the System Device Enumerator. @@ -112,14 +110,4 @@ QList<QString> get_camera_names() { } #endif return ret; -} - -template<typename = void> -int camera_name_to_index(const QString &name) -{ - auto list = get_camera_names(); - int ret = list.indexOf(name); - if (ret < 0) - ret = 0; - return ret; -} +}
\ No newline at end of file diff --git a/opentrack-compat/camera-names.hpp b/opentrack-compat/camera-names.hpp new file mode 100644 index 00000000..c2879000 --- /dev/null +++ b/opentrack-compat/camera-names.hpp @@ -0,0 +1,22 @@ +/* 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 <QList> +#include <QString> + +#ifdef BUILD_compat +# include "compat-export.hpp" +#else +# include "compat-import.hpp" +#endif + +OPENTRACK_COMPAT_EXPORT QList<QString> get_camera_names(); +OPENTRACK_COMPAT_EXPORT int camera_name_to_index(const QString &name); + diff --git a/opentrack-compat/compat-export.hpp b/opentrack-compat/compat-export.hpp new file mode 100644 index 00000000..2d6f1d3d --- /dev/null +++ b/opentrack-compat/compat-export.hpp @@ -0,0 +1,15 @@ +#pragma once + +#ifndef OPENTRACK_COMPAT_EXPORT +# ifdef _WIN32 +# define OPENTRACK_COMPAT_LINKAGE __declspec(dllexport) +# else +# define OPENTRACK_COMPAT_LINKAGE +# endif + +# ifndef _MSC_VER +# define OPENTRACK_COMPAT_EXPORT __attribute__ ((visibility ("default"))) OPENTRACK_COMPAT_LINKAGE +# else +# define OPENTRACK_COMPAT_EXPORT OPENTRACK_COMPAT_LINKAGE +# endif +#endif diff --git a/opentrack-compat/compat-import.hpp b/opentrack-compat/compat-import.hpp new file mode 100644 index 00000000..161ccc5d --- /dev/null +++ b/opentrack-compat/compat-import.hpp @@ -0,0 +1,15 @@ +#pragma once + +#ifndef OPENTRACK_COMPAT_EXPORT +# ifdef _WIN32 +# define OPENTRACK_COMPAT_LINKAGE __declspec(dllimport) +# else +# define OPENTRACK_COMPAT_LINKAGE +# endif + +# ifndef _MSC_VER +# define OPENTRACK_COMPAT_EXPORT __attribute__ ((visibility ("default"))) OPENTRACK_COMPAT_LINKAGE +# else +# define OPENTRACK_COMPAT_EXPORT OPENTRACK_COMPAT_LINKAGE +# endif +#endif diff --git a/opentrack-compat/export.hpp b/opentrack-compat/export.hpp index f0983b75..100950a0 100644 --- a/opentrack-compat/export.hpp +++ b/opentrack-compat/export.hpp @@ -1,13 +1,15 @@ #pragma once -#ifdef _WIN32 -# define OPENTRACK_LINKAGE __declspec(dllexport) -#else -# define OPENTRACK_LINKAGE -#endif +#ifndef OPENTRACK_EXPORT +# ifdef _WIN32 +# define OPENTRACK_LINKAGE __declspec(dllexport) +# else +# define OPENTRACK_LINKAGE +# endif -#ifndef _MSC_VER -# define OPENTRACK_EXPORT __attribute__ ((visibility ("default"))) OPENTRACK_LINKAGE -#else -# define OPENTRACK_EXPORT OPENTRACK_LINKAGE -#endif
\ No newline at end of file +# ifndef _MSC_VER +# define OPENTRACK_EXPORT __attribute__ ((visibility ("default"))) OPENTRACK_LINKAGE +# else +# define OPENTRACK_EXPORT OPENTRACK_LINKAGE +# endif +#endif diff --git a/opentrack-compat/import.hpp b/opentrack-compat/import.hpp new file mode 100644 index 00000000..3747b141 --- /dev/null +++ b/opentrack-compat/import.hpp @@ -0,0 +1,15 @@ +#pragma once + +#ifndef OPENTRACK_EXPORT +# ifdef _WIN32 +# define OPENTRACK_LINKAGE __declspec(dllimport) +# else +# define OPENTRACK_LINKAGE +# endif + +# ifndef _MSC_VER +# define OPENTRACK_EXPORT __attribute__ ((visibility ("default"))) OPENTRACK_LINKAGE +# else +# define OPENTRACK_EXPORT OPENTRACK_LINKAGE +# endif +#endif diff --git a/opentrack-compat/options.cpp b/opentrack-compat/options.cpp new file mode 100644 index 00000000..550fec24 --- /dev/null +++ b/opentrack-compat/options.cpp @@ -0,0 +1,199 @@ +#include "options.hpp" + +namespace options +{ + +namespace detail +{ +OPENTRACK_COMPAT_EXPORT opt_singleton& singleton() +{ + static opt_singleton ret; + return ret; +} + +} + +group::group(const QString& name) : name(name) +{ + auto conf = ini_file(); + conf->beginGroup(name); + for (auto& k_ : conf->childKeys()) + { + auto tmp = k_.toUtf8(); + QString k(tmp); + kvs[k] = conf->value(k_); + } + conf->endGroup(); +} + +void group::save() +{ + auto s = ini_file(); + s->beginGroup(name); + for (auto& i : kvs) + s->setValue(i.first, i.second); + s->endGroup(); + s->sync(); +} + +void group::put(const QString &s, const QVariant &d) +{ + kvs[s] = d; +} + +bool group::contains(const QString &s) +{ + return kvs.count(s) != 0; +} + +QString group::ini_directory() +{ + const auto dirs = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation); + if (dirs.size() == 0) + return ""; + if (QDir(dirs[0]).mkpath(OPENTRACK_ORG)) + return dirs[0] + "/" OPENTRACK_ORG; + return ""; +} + +QString group::ini_filename() +{ + QSettings settings(OPENTRACK_ORG); + return settings.value(OPENTRACK_CONFIG_FILENAME_KEY, OPENTRACK_DEFAULT_CONFIG).toString(); +} + +QString group::ini_pathname() +{ + const auto dir = ini_directory(); + if (dir == "") + return ""; + QSettings settings(OPENTRACK_ORG); + return dir + "/" + settings.value(OPENTRACK_CONFIG_FILENAME_KEY, OPENTRACK_DEFAULT_CONFIG).toString(); +} + +const QStringList group::ini_list() +{ + const auto dirname = ini_directory(); + if (dirname == "") + return QStringList(); + QDir settings_dir(dirname); + return settings_dir.entryList( QStringList { "*.ini" } , QDir::Files, QDir::Name ); +} + +const mem<QSettings> group::ini_file() +{ + const auto pathname = ini_pathname(); + if (pathname != "") + return std::make_shared<QSettings>(ini_pathname(), QSettings::IniFormat); + return std::make_shared<QSettings>(); +} + +impl_bundle::impl_bundle(const QString &group_name) + : + mtx(QMutex::Recursive), + group_name(group_name), + saved(group_name), + transient(saved), + modified(false) +{} + +void impl_bundle::reload() +{ + { + QMutexLocker l(&mtx); + saved = group(group_name); + transient = saved; + modified = false; + } + emit reloading(); +} + +void impl_bundle::store_kv(const QString &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); + } +} + +bool impl_bundle::contains(const QString &name) +{ + QMutexLocker l(&mtx); + return transient.contains(name); +} + +void impl_bundle::save() +{ + { + QMutexLocker l(&mtx); + modified = false; + saved = transient; + transient.save(); + } + emit saving(); +} + +bool impl_bundle::modifiedp() +{ + QMutexLocker l(&mtx); + return modified; +} + +namespace detail +{ + +pbundle opt_singleton::bundle(const opt_singleton::k &key) +{ + QMutexLocker l(&implsgl_mtx); + + if (implsgl_data.count(key) != 0) + { + auto shared = std::get<1>(implsgl_data[key]).lock(); + if (shared != nullptr) + return shared; + } + + qDebug() << "bundle +" << key; + + auto shr = std::make_shared<v>(key); + implsgl_data[key] = tt(cnt(1), shr); + return shr; +} + +void opt_singleton::bundle_decf(const opt_singleton::k &key) +{ + QMutexLocker l(&implsgl_mtx); + + if (--std::get<0>(implsgl_data[key]) == 0) + implsgl_data.erase(key); +} + +opt_singleton::opt_singleton() : implsgl_mtx(QMutex::Recursive) {} + +} + +opt_bundle::opt_bundle(const QString &group_name) + : impl_bundle(group_name) +{ +} + +opt_bundle::~opt_bundle() +{ + qDebug() << "bundle -" << group_name; + detail::singleton().bundle_decf(group_name); +} + +base_value::base_value(pbundle b, const QString &name) : b(b), self_name(name) {} + +opts::~opts() +{ + b->reload(); +} + +opts::opts(const QString &name) : b(bundle(name)) {} + +} diff --git a/opentrack/options.hpp b/opentrack-compat/options.hpp index f2c09479..a317a1f7 100644 --- a/opentrack/options.hpp +++ b/opentrack-compat/options.hpp @@ -10,7 +10,6 @@ #include <memory> #include <tuple> #include <map> -#include <string> #include <QObject> #include <QSettings> @@ -37,6 +36,13 @@ #include <QDebug> #include <memory> + +#ifdef BUILD_compat +# include "compat-export.hpp" +#else +# include "compat-import.hpp" +#endif + template<typename t> using mem = std::shared_ptr<t>; #define OPENTRACK_CONFIG_FILENAME_KEY "settings-filename" @@ -44,9 +50,7 @@ template<typename t> using mem = std::shared_ptr<t>; #define OPENTRACK_ORG "TrackHat opentrack-2.3" namespace options { - template<typename k, typename v> - using map = std::map<k, v>; - using std::string; + template<typename k, typename v> using map = std::map<k, v>; template<typename t> // don't elide usages of the function, qvariant default implicit @@ -84,103 +88,33 @@ namespace options { } // snapshot of qsettings group at given time - class group { + class OPENTRACK_COMPAT_EXPORT group { private: - map<string, QVariant> kvs; - string name; + map<QString, QVariant> kvs; + QString name; public: - group(const string& name) : name(name) - { - auto conf = ini_file(); - auto q_name = QString::fromStdString(name); - conf->beginGroup(q_name); - for (auto& k_ : conf->childKeys()) - { - auto tmp = k_.toUtf8(); - string k(tmp); - kvs[k] = conf->value(k_); - } - conf->endGroup(); - } - - void save() - { - auto s = ini_file(); - auto q_name = QString::fromStdString(name); - s->beginGroup(q_name); - for (auto& i : kvs) - { - auto k = QString::fromStdString(i.first); - s->setValue(k, i.second); - } - s->endGroup(); - s->sync(); - } + group(const QString& name); + void save(); + void put(const QString& s, const QVariant& d); + bool contains(const QString& s); + static QString ini_directory(); + static QString ini_filename(); + static QString ini_pathname(); + static const QStringList ini_list(); + static const mem<QSettings> ini_file(); template<typename t> - t get(const string& k) + t get(const QString& 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 QString ini_directory() - { - const auto dirs = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation); - if (dirs.size() == 0) - return ""; - if (QDir(dirs[0]).mkpath(OPENTRACK_ORG)) - return dirs[0] + "/" OPENTRACK_ORG; - return ""; - } - - static QString ini_filename() - { - QSettings settings(OPENTRACK_ORG); - return settings.value(OPENTRACK_CONFIG_FILENAME_KEY, OPENTRACK_DEFAULT_CONFIG).toString(); - } - - static QString ini_pathname() - { - const auto dir = ini_directory(); - if (dir == "") - return ""; - QSettings settings(OPENTRACK_ORG); - return dir + "/" + settings.value(OPENTRACK_CONFIG_FILENAME_KEY, OPENTRACK_DEFAULT_CONFIG).toString(); - } - - static const QStringList ini_list() - { - const auto dirname = ini_directory(); - if (dirname == "") - return QStringList(); - QDir settings_dir(dirname); - return settings_dir.entryList( QStringList { "*.ini" } , QDir::Files, QDir::Name ); - } - - static const mem<QSettings> ini_file() - { - const auto pathname = ini_pathname(); - if (pathname != "") - return std::make_shared<QSettings>(ini_pathname(), QSettings::IniFormat); - return std::make_shared<QSettings>(); - } }; - class impl_bundle : public QObject { + class OPENTRACK_COMPAT_EXPORT impl_bundle : public QObject { Q_OBJECT protected: QMutex mtx; - const string group_name; + const QString group_name; group saved; group transient; bool modified; @@ -190,144 +124,66 @@ namespace options { void reloading(); void saving(); public: - impl_bundle(const string& group_name) : - mtx(QMutex::Recursive), - group_name(group_name), - saved(group_name), - transient(saved), - modified(false) - { - } - - string name() { return group_name; } - - void reload() { - { - QMutexLocker l(&mtx); - saved = group(group_name); - transient = saved; - modified = false; - } - emit reloading(); - } - - 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); - } - } - bool contains(const string& name) - { - QMutexLocker l(&mtx); - return transient.contains(name); - } + impl_bundle(const QString& group_name); + QString name() { return group_name; } + void reload(); + void store_kv(const QString& name, const QVariant& datum); + bool contains(const QString& name); + void save(); + bool modifiedp(); + template<typename t> - t get(const string& name) + t get(const QString& name) { QMutexLocker l(&mtx); return transient.get<t>(name); } - void save() - { - { - QMutexLocker l(&mtx); - modified = false; - saved = transient; - transient.save(); - } - emit saving(); - } - - bool modifiedp() { - QMutexLocker l(&mtx); - return modified; - } }; class opt_bundle; - namespace + namespace detail { - template<typename k, typename v, typename cnt = int> - struct opt_singleton + struct OPENTRACK_COMPAT_EXPORT opt_singleton { public: + using k = QString; + using v = opt_bundle; + using cnt = int; using pbundle = std::shared_ptr<v>; using tt = std::tuple<cnt, std::weak_ptr<v>>; private: QMutex implsgl_mtx; 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) - { - auto shared = std::get<1>(implsgl_data[key]).lock(); - if (shared != nullptr) - return shared; - } - - 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(); + pbundle bundle(const k& key); + void bundle_decf(const k& key); }; - - using pbundle = std::shared_ptr<opt_bundle>; - using t_fact = opt_singleton<string, opt_bundle>; + + OPENTRACK_COMPAT_EXPORT opt_singleton& singleton(); } + + using pbundle = std::shared_ptr<opt_bundle>; + + static inline pbundle bundle(const QString name) { return detail::singleton().bundle(name); } - static inline t_fact::pbundle bundle(const string name) { return t_fact::datum().bundle(name); } - - class opt_bundle : public impl_bundle + class OPENTRACK_COMPAT_EXPORT opt_bundle : public impl_bundle { public: opt_bundle() : impl_bundle("i-have-no-name") {} - opt_bundle(const string& group_name) : impl_bundle(group_name) - { - } - - ~opt_bundle() - { - qDebug() << "bundle -" << QString::fromStdString(group_name); - t_fact::datum().bundle_decf(group_name); - } + opt_bundle(const QString& group_name); + ~opt_bundle(); }; - class base_value : public QObject + class OPENTRACK_COMPAT_EXPORT base_value : public QObject { Q_OBJECT #define DEFINE_SLOT(t) void setValue(t datum) { store(datum); } #define DEFINE_SIGNAL(t) void valueChanged(t) public: - string name() { return self_name; } - base_value(pbundle b, const string& name) : b(b), self_name(name) {} + QString name() { return self_name; } + base_value(pbundle b, const QString& name); signals: DEFINE_SIGNAL(double); DEFINE_SIGNAL(int); @@ -335,7 +191,7 @@ namespace options { DEFINE_SIGNAL(QString); protected: pbundle b; - string self_name; + QString self_name; template<typename t> void store(const t& datum) @@ -352,12 +208,6 @@ namespace options { virtual void reload() = 0; }; - static inline string string_from_qstring(const QString& datum) - { - auto tmp = datum.toUtf8(); - return string(tmp.constData()); - } - template<typename t> class value : public base_value { public: @@ -368,7 +218,7 @@ namespace options { } static constexpr const Qt::ConnectionType DIRECT_CONNTYPE = Qt::DirectConnection; static constexpr const Qt::ConnectionType SAFE_CONNTYPE = Qt::UniqueConnection; - value(pbundle b, const string& name, t def) : base_value(b, name), def(def) + value(pbundle b, const QString& name, t def) : base_value(b, name), def(def) { QObject::connect(b.get(), SIGNAL(reloading()), this, SLOT(reload()), @@ -376,10 +226,9 @@ namespace options { if (!b->contains(name) || b->get<QVariant>(name).type() == QVariant::Invalid) *this = def; } - value(pbundle b, const QString& name, t def) : value(b, string_from_qstring(name), def) {} - value(pbundle b, const char* name, t def) : value(b, string(name), def) {} + value(pbundle b, const char* name, t def) : value(b, QString(name), def) {} - operator t() + operator t() const { return b->contains(self_name) ? b->get<t>(self_name) : def; } @@ -390,18 +239,13 @@ namespace options { t def; }; - struct opts + struct OPENTRACK_COMPAT_EXPORT opts { pbundle b; - - opts(const std::string& name) : b(bundle(name)) {} - - ~opts() - { - b->reload(); - } + opts(const QString& name); + ~opts(); }; - + template<typename t, typename q> inline void tie_setting(value<t>&, q*); diff --git a/opentrack-compat/shm.cpp b/opentrack-compat/shm.cpp index 029a4c95..55aa7a41 100644 --- a/opentrack-compat/shm.cpp +++ b/opentrack-compat/shm.cpp @@ -5,25 +5,140 @@ * copyright notice and this permission notice appear in all copies. */ -#include <cstring> #include "shm.h" #if defined(_WIN32) + +#include <cstring> +#include <stdio.h> + +#include <accctrl.h> +#include <aclapi.h> + +struct secattr +{ + bool success; + SECURITY_DESCRIPTOR* pSD; + SECURITY_ATTRIBUTES attrs; + PSID pEveryoneSID; + PACL pACL; + + void cleanup() + { + if (pEveryoneSID) + FreeSid(pEveryoneSID); + if (pACL) + LocalFree(pACL); + if (pSD) + LocalFree(pSD); + success = false; + pSD = nullptr; + pEveryoneSID = nullptr; + pACL = nullptr; + } + + secattr(DWORD perms) : success(true), pSD(nullptr), pEveryoneSID(nullptr), pACL(nullptr) + { + SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY; + EXPLICIT_ACCESS ea; + + if(!AllocateAndInitializeSid(&SIDAuthWorld, 1, + SECURITY_WORLD_RID, + 0, 0, 0, 0, 0, 0, 0, + &pEveryoneSID)) + { + fprintf(stderr, "AllocateAndInitializeSid: %d\n", (int) GetLastError()); + goto cleanup; + } + + memset(&ea, 0, sizeof(ea)); + + ea.grfAccessPermissions = perms; + ea.grfAccessMode = SET_ACCESS; + ea.grfInheritance = NO_INHERITANCE; + ea.Trustee.TrusteeForm = TRUSTEE_IS_SID; + ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; + ea.Trustee.ptstrName = (LPTSTR) pEveryoneSID; + + if (SetEntriesInAcl(1, &ea, NULL, &pACL) != ERROR_SUCCESS) + { + fprintf(stderr, "SetEntriesInAcl: %d\n", (int) GetLastError()); + goto cleanup; + } + + pSD = (SECURITY_DESCRIPTOR*) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); + if (pSD == nullptr) + { + fprintf(stderr, "LocalAlloc: %d\n", (int) GetLastError()); + goto cleanup; + } + + if (!InitializeSecurityDescriptor(pSD, + SECURITY_DESCRIPTOR_REVISION)) + { + fprintf(stderr, "InitializeSecurityDescriptor: %d\n", (int) GetLastError()); + goto cleanup; + } + + if (!SetSecurityDescriptorDacl(pSD, + TRUE, + pACL, + FALSE)) + { + fprintf(stderr, "SetSecurityDescriptorDacl: %d\n", (int) GetLastError()); + goto cleanup; + } + + attrs.bInheritHandle = false; + attrs.lpSecurityDescriptor = pSD; + attrs.nLength = sizeof(SECURITY_ATTRIBUTES); + + fflush(stderr); + + return; +cleanup: + fflush(stderr); + cleanup(); + } + + ~secattr() + { + cleanup(); + } +}; + PortableLockedShm::PortableLockedShm(const char* shmName, const char* mutexName, int mapSize) { - hMutex = CreateMutexA(NULL, false, mutexName); + secattr sa(GENERIC_ALL|SYNCHRONIZE); + + hMutex = CreateMutexA(sa.success ? &sa.attrs : nullptr, false, mutexName); + if (!hMutex) + { + fprintf(stderr, "CreateMutexA: %d\n", (int) GetLastError()); + fflush(stderr); + } hMapFile = CreateFileMappingA( INVALID_HANDLE_VALUE, - NULL, + sa.success ? &sa.attrs : nullptr, PAGE_READWRITE, 0, mapSize, shmName); + if (!hMapFile) + { + fprintf(stderr, "CreateFileMappingA: %d\n", (int) GetLastError()); + fflush(stderr); + } mem = MapViewOfFile(hMapFile, FILE_MAP_WRITE, 0, 0, mapSize); + if (!mem) + { + fprintf(stderr, "MapViewOfFile: %d\n", (int) GetLastError()); + fflush(stderr); + } } PortableLockedShm::~PortableLockedShm() diff --git a/opentrack-compat/shm.h b/opentrack-compat/shm.h index c74534e7..3edb0080 100644 --- a/opentrack-compat/shm.h +++ b/opentrack-compat/shm.h @@ -19,32 +19,18 @@ #include <sys/types.h> #endif -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wattributes" - #ifdef __GNUC__ -# define COMPAT_GNUC_VISIBILITY __attribute__ ((visibility ("default"))) -#else -# define COMPAT_GNUC_VISIBILITY +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wattributes" #endif -#ifdef BUILD_opentrack_compat -# ifdef _WIN32 -# define COMPAT_WIN32_EXPORT __declspec(dllexport) -# else -# define COMPAT_WIN32_EXPORT -# endif +#ifdef BUILD_compat +# include "compat-export.hpp" #else -# ifdef _WIN32 -# define COMPAT_WIN32_EXPORT __declspec(dllimport) -# else -# define COMPAT_WIN32_EXPORT -# endif +# include "compat-import.hpp" #endif -#define COMPAT_EXPORT COMPAT_WIN32_EXPORT COMPAT_GNUC_VISIBILITY - -class COMPAT_EXPORT PortableLockedShm { +class OPENTRACK_COMPAT_EXPORT PortableLockedShm { public: PortableLockedShm(const char *shmName, const char *mutexName, int mapSize); ~PortableLockedShm(); @@ -61,4 +47,6 @@ private: #endif }; -#pragma GCC diagnostic pop +#ifdef __GNUC__ +# pragma GCC diagnostic pop +#endif diff --git a/opentrack/CMakeLists.txt b/opentrack/CMakeLists.txt index 590eaca5..6baa05db 100644 --- a/opentrack/CMakeLists.txt +++ b/opentrack/CMakeLists.txt @@ -1,6 +1,8 @@ -opentrack_boilerplate(opentrack-api NO-LINKER-SCRIPT NO-COMPAT) +opentrack_boilerplate(opentrack-api NO-LINKER-SCRIPT NO-COMPAT LINKAGE) if(NOT WIN32) target_link_libraries(opentrack-api opentrack-qxt-mini opentrack-compat dl) else() target_link_libraries(opentrack-api winmm) endif() +target_link_libraries(opentrack-api opentrack-spline-widget) +link_with_dinput8(opentrack-api) diff --git a/opentrack/keybinding-worker.cpp b/opentrack/keybinding-worker.cpp new file mode 100644 index 00000000..39693a7c --- /dev/null +++ b/opentrack/keybinding-worker.cpp @@ -0,0 +1,192 @@ +/* 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. + */ + +#ifdef _WIN32 + +#include "keybinding-worker.hpp" +#include <functional> +#include <windows.h> +#include <QDebug> +#include <QMutexLocker> + +bool Key::should_process() +{ + if (keycode == 0 && guid == "") + return false; + bool ret = timer.elapsed_ms() > 100; + timer.start(); + return ret; +} + +KeybindingWorker::~KeybindingWorker() { + should_quit = true; + wait(); + if (dinkeyboard) { + dinkeyboard->Unacquire(); + dinkeyboard->Release(); + } + if (din) + din->Release(); +} + +KeybindingWorker::KeybindingWorker() : + should_quit(true) +{ + if (DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&din, NULL) != DI_OK) { + qDebug() << "setup DirectInput8 Creation failed!" << GetLastError(); + return; + } + if (din->CreateDevice(GUID_SysKeyboard, &dinkeyboard, NULL) != DI_OK) { + din->Release(); + din = 0; + qDebug() << "setup CreateDevice function failed!" << GetLastError(); + return; + } + if (dinkeyboard->SetDataFormat(&c_dfDIKeyboard) != DI_OK) { + qDebug() << "setup SetDataFormat function failed!" << GetLastError(); + dinkeyboard->Release(); + dinkeyboard = 0; + din->Release(); + din = 0; + return; + } + + if (dinkeyboard->SetCooperativeLevel((HWND) fake_main_window.winId(), DISCL_NONEXCLUSIVE | DISCL_BACKGROUND) != DI_OK) { + dinkeyboard->Release(); + din->Release(); + din = 0; + dinkeyboard = 0; + qDebug() << "setup SetCooperativeLevel function failed!" << GetLastError(); + return; + } + if (dinkeyboard->Acquire() != DI_OK) + { + dinkeyboard->Release(); + din->Release(); + din = 0; + dinkeyboard = 0; + qDebug() << "setup dinkeyboard Acquire failed!" << GetLastError(); + return; + } + should_quit = false; + start(); +} + +KeybindingWorker& KeybindingWorker::make() +{ + static KeybindingWorker k; + return k; +} + +void KeybindingWorker::run() { + BYTE keystate[256] = {0}; + BYTE old_keystate[256] = {0}; + + while (!should_quit) + { + { + QMutexLocker l(&mtx); + + if (receivers.size()) + { + { + const HRESULT hr = dinkeyboard->GetDeviceState(256, (LPVOID)keystate); + + if (hr != DI_OK) { + qDebug() << "Tracker::run GetDeviceState function failed!" << GetLastError(); + Sleep(25); + continue; + } + } + + { + using joy_fn = std::function<void(const QString& guid, int idx, bool held)>; + + joy_fn f = [&](const QString& guid, int idx, bool held) -> void { + Key k; + k.keycode = idx; + k.shift = !!(keystate[DIK_LSHIFT] & 0x80 || keystate[DIK_RSHIFT] & 0x80); + k.alt = !!(keystate[DIK_LALT] & 0x80 || keystate[DIK_RALT] & 0x80); + k.ctrl = !!(keystate[DIK_LCONTROL] & 0x80 || keystate[DIK_RCONTROL] & 0x80); + k.guid = guid; + k.held = held; + + for (auto& r : receivers) + r->operator()(k); + }; + + joy_ctx.poll(f); + } + + for (int i = 0; i < 256; i++) + { + Key k; + if (old_keystate[i] != keystate[i] && keystate[i] & 0x80) + { + switch (i) + { + case DIK_LCONTROL: + case DIK_LSHIFT: + case DIK_LALT: + case DIK_RCONTROL: + case DIK_RSHIFT: + case DIK_RALT: + break; + default: + k.shift = !!(keystate[DIK_LSHIFT] & 0x80) || !!(keystate[DIK_RSHIFT] & 0x80); + k.alt = !!(keystate[DIK_LALT] & 0x80) || !!(keystate[DIK_RALT] & 0x80); + k.ctrl = !!(keystate[DIK_LCONTROL] & 0x80) || !!(keystate[DIK_RCONTROL] & 0x80); + k.keycode = i; + + for (auto& r : receivers) + r->operator()(k); + break; + } + } + old_keystate[i] = keystate[i]; + } + } + } + + // keypresses get dropped with high values + Sleep(4); + } +} + +KeybindingWorker::fun* KeybindingWorker::_add_receiver(fun& receiver) +{ + QMutexLocker l(&mtx); + receivers.push_back(std::unique_ptr<fun>(new fun(receiver))); + fun* f = receivers[receivers.size() - 1].get(); + qDebug() << "add receiver" << (long) f; + joy_ctx.refresh(); + return f; +} + +void KeybindingWorker::remove_receiver(KeybindingWorker::fun* pos) +{ + QMutexLocker l(&mtx); + bool ok = false; + + for (int i = receivers.size() - 1; i >= 0; i--) + { + if (receivers[i].get() == pos) + { + ok = true; + qDebug() << "remove receiver" << (long) pos; + receivers.erase(receivers.begin() + i); + break; + } + } + if (!ok) + { + qDebug() << "bad remove receiver" << (long) pos; + } +} + +#endif diff --git a/opentrack/keybinding-worker.hpp b/opentrack/keybinding-worker.hpp new file mode 100644 index 00000000..fa50a974 --- /dev/null +++ b/opentrack/keybinding-worker.hpp @@ -0,0 +1,81 @@ +/* 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 + +#ifdef BUILD_api +# include "opentrack-compat/export.hpp" +#else +# include "opentrack-compat/import.hpp" +#endif + +#include "opentrack-compat/timer.hpp" +#include "opentrack/win32-joystick.hpp" +#include <QThread> +#include <QMutex> +#include <QWidget> +#include <QMainWindow> +#include <functional> +#include <vector> + +#undef DIRECTINPUT_VERSION +#define DIRECTINPUT_VERSION 0x0800 +#include <windows.h> +#include <dinput.h> +struct Key { + BYTE keycode; + QString guid; + bool shift; + bool ctrl; + bool alt; + bool held; + Timer timer; +public: + Key() : keycode(0), shift(false), ctrl(false), alt(false), held(true) {} + + bool should_process(); +}; + +struct OPENTRACK_EXPORT KeybindingWorker : private QThread +{ +private: + LPDIRECTINPUT8 din; + LPDIRECTINPUTDEVICE8 dinkeyboard; + win32_joy_ctx joy_ctx; + volatile bool should_quit; + using fun = std::function<void(const Key&)>; + std::vector<std::unique_ptr<fun>> receivers; + QMutex mtx; + QMainWindow fake_main_window; + + void run() override; + KeybindingWorker(); + + KeybindingWorker(const KeybindingWorker&) = delete; + KeybindingWorker& operator=(KeybindingWorker&) = delete; + static KeybindingWorker& make(); + fun* _add_receiver(fun &receiver); + void remove_receiver(fun* pos); + ~KeybindingWorker(); +public: + class Token + { + fun* pos; + Token(const Token&) = delete; + Token& operator=(Token&) = delete; + public: + ~Token() + { + make().remove_receiver(pos); + } + Token(fun receiver) + { + pos = make()._add_receiver(receiver); + } + }; +}; diff --git a/opentrack/main-settings.hpp b/opentrack/main-settings.hpp index dd61143e..2d1c1f22 100644 --- a/opentrack/main-settings.hpp +++ b/opentrack/main-settings.hpp @@ -9,7 +9,7 @@ #pragma once #include <QString> -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" #include "opentrack/plugin-api.hpp" using namespace options; @@ -30,13 +30,27 @@ private: } }; -struct main_settings : opts { +struct key_opts { + value<QString> keycode, guid; + value<int> button; + + key_opts(pbundle 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) + {} +}; + +struct main_settings : opts { value<QString> protocol_dll; axis_opts a_x, a_y, a_z, a_yaw, a_pitch, a_roll; value<bool> tcomp_p, tcomp_tz; value<bool> tray_enabled; value<int> camera_yaw, camera_pitch, camera_roll; value<bool> center_at_startup, wizard_done; + value<int> center_method; + key_opts key_start_tracking, key_stop_tracking, key_toggle_tracking; + key_opts key_center, key_toggle, key_zero; main_settings() : opts("opentrack-ui"), protocol_dll(b, "protocol-dll", "freetrack 2.0 Enhanced"), @@ -53,6 +67,14 @@ struct main_settings : opts { camera_pitch(b, "camera-pitch", 0), camera_roll(b, "camera-roll", 0), center_at_startup(b, "center-at-startup", true), - wizard_done(b, "wizard-done", false) - {} + wizard_done(b, "wizard-done", false), + center_method(b, "centering-method", true), + key_start_tracking(b, "start-tracking"), + key_stop_tracking(b, "stop-tracking"), + key_toggle_tracking(b, "toggle-tracking"), + key_center(b, "center"), + key_toggle(b, "toggle"), + key_zero(b, "zero") + { + } }; diff --git a/opentrack/mappings.hpp b/opentrack/mappings.hpp index bb38a3ca..087ea7f3 100644 --- a/opentrack/mappings.hpp +++ b/opentrack/mappings.hpp @@ -8,7 +8,7 @@ #pragma once #include <QSettings> -#include "options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; #include "spline-widget/functionconfig.h" #include "main-settings.hpp" diff --git a/opentrack/opencv-camera-dialog.hpp b/opentrack/opencv-camera-dialog.hpp index 0d4a51af..96c7a643 100644 --- a/opentrack/opencv-camera-dialog.hpp +++ b/opentrack/opencv-camera-dialog.hpp @@ -12,7 +12,7 @@ #include <QMutex> #include <QMutexLocker> #include <opencv2/videoio.hpp> -#include "opentrack/camera-names.hpp" +#include "opentrack-compat/camera-names.hpp" #ifdef __linux #include <QProcess> diff --git a/opentrack/plugin-api.hpp b/opentrack/plugin-api.hpp index a57077ab..5fdc3bcb 100644 --- a/opentrack/plugin-api.hpp +++ b/opentrack/plugin-api.hpp @@ -8,17 +8,38 @@ #pragma once -#include "../opentrack-compat/export.hpp" #include <QString> #include <QWidget> #include <QFrame> #include <QIcon> +#ifdef BUILD_api +# include "opentrack-compat/export.hpp" +#else +# include "opentrack-compat/import.hpp" +#endif + +#ifndef OPENTRACK_PLUGIN_EXPORT +# ifdef _WIN32 +# define OPENTRACK_PLUGIN_LINKAGE __declspec(dllexport) +# else +# define OPENTRACK_PLUGIN_LINKAGE +# endif +# ifndef _MSC_VER +# define OPENTRACK_PLUGIN_EXPORT __attribute__ ((visibility ("default"))) OPENTRACK_PLUGIN_LINKAGE +# else +# define OPENTRACK_PLUGIN_EXPORT OPENTRACK_PLUGIN_LINKAGE +# endif +#endif + enum Axis { TX = 0, TY, TZ, Yaw, Pitch, Roll }; -class BaseDialog : public QWidget +namespace plugin_api { +namespace detail { + +class OPENTRACK_EXPORT BaseDialog : public QWidget { Q_OBJECT public: @@ -27,16 +48,19 @@ signals: void closing(); }; +} // ns +} // ns + #define OPENTRACK_DECLARE_PLUGIN_INTERNAL(ctor_class, ctor_ret_class, metadata_class, dialog_class, dialog_ret_class) \ - extern "C" OPENTRACK_EXPORT ctor_ret_class* GetConstructor() \ + extern "C" OPENTRACK_PLUGIN_EXPORT ctor_ret_class* GetConstructor() \ { \ return new ctor_class; \ } \ - extern "C" OPENTRACK_EXPORT Metadata* GetMetadata() \ + extern "C" OPENTRACK_PLUGIN_EXPORT Metadata* GetMetadata() \ { \ return new metadata_class; \ } \ - extern "C" OPENTRACK_EXPORT dialog_ret_class* GetDialog() \ + extern "C" OPENTRACK_PLUGIN_EXPORT dialog_ret_class* GetDialog() \ { \ return new dialog_class; \ } @@ -65,7 +89,7 @@ struct IFilter virtual void center() {} }; -struct IFilterDialog : public BaseDialog +struct IFilterDialog : public plugin_api::detail::BaseDialog { // optional destructor virtual ~IFilterDialog() {} @@ -93,7 +117,7 @@ struct IProtocol virtual QString game_name() = 0; }; -struct IProtocolDialog : public BaseDialog +struct IProtocolDialog : public plugin_api::detail::BaseDialog { // optional destructor virtual ~IProtocolDialog() {} @@ -118,7 +142,7 @@ struct ITracker virtual void data(double *data) = 0; }; -struct ITrackerDialog : public BaseDialog +struct ITrackerDialog : public plugin_api::detail::BaseDialog { // optional destructor virtual ~ITrackerDialog() {} diff --git a/opentrack/plugin-support.hpp b/opentrack/plugin-support.hpp index 3a0a3420..9968890d 100644 --- a/opentrack/plugin-support.hpp +++ b/opentrack/plugin-support.hpp @@ -8,7 +8,7 @@ #pragma once #include "plugin-api.hpp" -#include "options.hpp" +#include "opentrack-compat/options.hpp" #include <QWidget> #include <QDebug> diff --git a/opentrack/selected-libraries.hpp b/opentrack/selected-libraries.hpp index 7779c231..5384f9e2 100644 --- a/opentrack/selected-libraries.hpp +++ b/opentrack/selected-libraries.hpp @@ -11,7 +11,14 @@ #include "opentrack/plugin-support.hpp" #include <QFrame> -struct SelectedLibraries { + +#ifdef BUILD_api +# include "opentrack-compat/export.hpp" +#else +# include "opentrack-compat/import.hpp" +#endif + +struct OPENTRACK_EXPORT SelectedLibraries { using dylibptr = mem<dylib>; mem<ITracker> pTracker; mem<IFilter> pFilter; diff --git a/opentrack/shortcuts.cpp b/opentrack/shortcuts.cpp index a33cf088..bab1283a 100644 --- a/opentrack/shortcuts.cpp +++ b/opentrack/shortcuts.cpp @@ -7,112 +7,9 @@ */ #include "shortcuts.h" -#include <QMutexLocker> - -#if defined(_WIN32) -#include <functional> -#include <windows.h> #include "win32-shortcuts.h" -KeybindingWorker::~KeybindingWorker() { - should_quit = true; - wait(); - if (dinkeyboard) { - dinkeyboard->Unacquire(); - dinkeyboard->Release(); - } - if (din) - din->Release(); -} - -KeybindingWorker::KeybindingWorker(std::function<void(Key&)> receiver, WId h) : - should_quit(true), receiver(receiver) -{ - HWND handle = reinterpret_cast<HWND>(h); - - if (DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&din, NULL) != DI_OK) { - qDebug() << "setup DirectInput8 Creation failed!" << GetLastError(); - return; - } - if (din->CreateDevice(GUID_SysKeyboard, &dinkeyboard, NULL) != DI_OK) { - din->Release(); - din = 0; - qDebug() << "setup CreateDevice function failed!" << GetLastError(); - return; - } - if (dinkeyboard->SetDataFormat(&c_dfDIKeyboard) != DI_OK) { - qDebug() << "setup SetDataFormat function failed!" << GetLastError(); - dinkeyboard->Release(); - dinkeyboard = 0; - din->Release(); - din = 0; - return; - } - if (dinkeyboard->SetCooperativeLevel((HWND) handle, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND) != DI_OK) { - dinkeyboard->Release(); - din->Release(); - din = 0; - dinkeyboard = 0; - qDebug() << "setup SetCooperativeLevel function failed!" << GetLastError(); - return; - } - if (dinkeyboard->Acquire() != DI_OK) - { - dinkeyboard->Release(); - din->Release(); - din = 0; - dinkeyboard = 0; - qDebug() << "setup dinkeyboard Acquire failed!" << GetLastError(); - return; - } - should_quit = false; -} - -void KeybindingWorker::run() { - BYTE keystate[256]; - - while (!should_quit) - { - if (dinkeyboard->GetDeviceState(256, (LPVOID)keystate) != DI_OK) { - qDebug() << "Tracker::run GetDeviceState function failed!" << GetLastError(); - Sleep(25); - continue; - } - - QMutexLocker l(&mtx); - - for (int i = 0; i < 256; i++) - { - Key k; - if (keystate[i] & 0x80) - { - switch (i) - { - case DIK_LCONTROL: - case DIK_LSHIFT: - case DIK_LALT: - case DIK_RCONTROL: - case DIK_RSHIFT: - case DIK_RALT: - break; - default: - k.shift = !!(keystate[DIK_LSHIFT] & 0x80) || !!(keystate[DIK_RSHIFT] & 0x80); - k.alt = !!(keystate[DIK_LALT] & 0x80) || !!(keystate[DIK_RALT] & 0x80); - k.ctrl = !!(keystate[DIK_LCONTROL] & 0x80) || !!(keystate[DIK_RCONTROL] & 0x80); - k.keycode = i; - receiver(k); - break; - } - } - } - - // keypresses get dropped with high values - Sleep(4); - } -} -#endif - -void Shortcuts::bind_keyboard_shortcut(K &key, key_opts& k) +void Shortcuts::bind_keyboard_shortcut(K &key, const key_opts& k) { #if !defined(_WIN32) using sh = QxtGlobalShortcut; @@ -136,56 +33,73 @@ void Shortcuts::bind_keyboard_shortcut(K &key, key_opts& k) key = K(); int idx = 0; QKeySequence code; - - if (k.keycode == "") - code = QKeySequence(Qt::Key_unknown); + + if (k.guid != "") + { + key.guid = k.guid; + key.keycode = k.button & ~Qt::KeyboardModifierMask; + key.ctrl = !!(k.button & Qt::ControlModifier); + key.alt = !!(k.button & Qt::AltModifier); + key.shift = !!(k.button & Qt::ShiftModifier); + } else - 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.shift = !!(mods & Qt::ShiftModifier); - key.alt = !!(mods & Qt::AltModifier); - key.ctrl = !!(mods & Qt::ControlModifier); - key.keycode = idx; + { + if (k.keycode == "") + code = QKeySequence(Qt::Key_unknown); + else + 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.shift = !!(mods & Qt::ShiftModifier); + key.alt = !!(mods & Qt::AltModifier); + key.ctrl = !!(mods & Qt::ControlModifier); + key.keycode = idx; + } } #endif #ifdef _WIN32 -void Shortcuts::receiver(Key &k) +void Shortcuts::receiver(const Key& k) { - std::vector<K*> ks { &keyCenter, &keyToggle, &keyZero }; - for (K* k_ : ks) + const int sz = keys.size(); + for (int i = 0; i < sz; i++) { - if (k.keycode != k_->keycode) + K& k_ = std::get<0>(keys[i]); + auto& fun = std::get<1>(keys[i]); + if (k.guid != k_.guid) + continue; + if (k.keycode != k_.keycode) + continue; + if (!k.held) continue; - if (!k_->should_process()) + if (!k_.should_process()) continue; - if (k_->alt && !k.alt) continue; - if (k_->ctrl && !k.ctrl) continue; - if (k_->shift && !k.shift) continue; + if (k_.alt && !k.alt) continue; + if (k_.ctrl && !k.ctrl) continue; + if (k_.shift && !k.shift) continue; - if (k_ == &keyCenter) - emit center(); - else if (k_ == &keyToggle) - emit toggle(); - else if (k_ == &keyZero) - emit zero(); + fun(); } } #endif -void Shortcuts::reload() { - 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) +void Shortcuts::reload(const std::vector<std::tuple<key_opts&, fun> > &keys_) +{ + const int sz = keys_.size(); + keys = std::vector<tt>(); + + for (int i = 0; i < sz; i++) { - keybindingWorker = std::make_shared<KeybindingWorker>([&](Key& k) { receiver(k); }, handle); - keybindingWorker->start(); - } + const auto& kk = keys_[i]; + const key_opts& opts = std::get<0>(kk); + auto& fun = std::get<1>(kk); + K k; + bind_keyboard_shortcut(k, opts); + keys.push_back(std::tuple<K, Shortcuts::fun>(k, fun)); +#ifndef _WIN32 + connect(k.get(), &QxtGlobalShortcut::activated, fun); #endif + } } diff --git a/opentrack/shortcuts.h b/opentrack/shortcuts.h index 63d91829..38037923 100644 --- a/opentrack/shortcuts.h +++ b/opentrack/shortcuts.h @@ -8,86 +8,27 @@ #pragma once #include <QObject> -#include <QWidget> -#include "opentrack-compat/timer.hpp" -#include <QThread> -#include <QMessageBox> -#include <QCheckBox> -#include <QComboBox> -#include <QSettings> -#include <QMutex> +#include <tuple> +#include <vector> +#include <functional> -#include "qxt-mini/QxtGlobalShortcut" -#include "opentrack/plugin-support.hpp" -#include "opentrack/options.hpp" -#include "opentrack/main-settings.hpp" - -using namespace options; - -extern QList<QString> global_key_sequences; - -struct key_opts { - value<QString> keycode; - - key_opts(pbundle b, const QString& name) : - keycode(b, QString("keycode-%1").arg(name), "") - {} -}; - -#if defined(_WIN32) -extern QList<int> global_windows_key_sequences; -# undef DIRECTINPUT_VERSION -# define DIRECTINPUT_VERSION 0x0800 -# include <windows.h> -# include <dinput.h> - -struct Key { - BYTE keycode; - bool shift; - bool ctrl; - bool alt; - Timer timer; -public: - Key() : keycode(0), shift(false), ctrl(false), alt(false) - { - } - - bool should_process() - { - if (keycode == 0) - return false; - bool ret = timer.elapsed_ms() > 100; - timer.start(); - return ret; - } -}; +#ifdef BUILD_api +# include "opentrack-compat/export.hpp" #else -typedef unsigned char BYTE; -struct Key { int foo; }; +# include "opentrack-compat/import.hpp" #endif -struct Shortcuts; +#include "qxt-mini/QxtGlobalShortcut" +#include "opentrack-compat/options.hpp" +#include "opentrack/main-settings.hpp" -struct KeybindingWorker : public QThread { #ifdef _WIN32 -private: - LPDIRECTINPUT8 din; - LPDIRECTINPUTDEVICE8 dinkeyboard; - QMutex mtx; -public: - volatile bool should_quit; - std::function<void(Key&)> receiver; - ~KeybindingWorker(); - KeybindingWorker(std::function<void(Key&)> receiver, WId h); - void run(); -#else -public: - KeybindingWorker(Key, Key, Key, WId) {} - void run() {} +# include "keybinding-worker.hpp" #endif -}; -struct Shortcuts : public QObject { +using namespace options; + +struct OPENTRACK_EXPORT Shortcuts : public QObject { Q_OBJECT public: @@ -98,39 +39,24 @@ public: Key #endif ; - - K keyCenter; - K keyToggle; - K keyZero; - - WId handle; + + using fun = std::function<void(void)>; + using tt = std::tuple<K, fun>; + std::vector<tt> keys; #ifdef _WIN32 - mem<KeybindingWorker> keybindingWorker; + KeybindingWorker::Token key_token; #endif - struct settings : opts { - key_opts center, toggle, zero; - main_settings s_main; - settings() : - opts("keyboard-shortcuts"), - center(b, "center"), - toggle(b, "toggle"), - zero(b, "zero") - {} - } s; - - Shortcuts(WId handle) : handle(handle) { reload(); } + Shortcuts() +#ifdef _WIN32 + : key_token([&](const Key& k) { receiver(k); }) +#endif + {} - void reload(); + void reload(const std::vector<std::tuple<key_opts &, fun> > &keys); private: - void bind_keyboard_shortcut(K &key, key_opts& k); + void bind_keyboard_shortcut(K &key, const key_opts& k); #ifdef _WIN32 - void receiver(Key& k); + void receiver(const Key& k); #endif -signals: - void center(); - void toggle(); - void zero(); }; - - diff --git a/opentrack/simple-mat.hpp b/opentrack/simple-mat.hpp index e462812b..4f885f4f 100644 --- a/opentrack/simple-mat.hpp +++ b/opentrack/simple-mat.hpp @@ -157,7 +157,7 @@ public: return ret; } - Mat<num, h_, w_> operator*(const num& other) const + Mat<num, h_, w_> operator*(const num other) const { Mat<num, h_, w_> ret; for (int j = 0; j < h_; j++) @@ -167,20 +167,16 @@ public: } template<int p> - Mat<num, w_, p> operator*(const Mat<num, w_, p>& other) const + Mat<num, h_, p> operator*(const Mat<num, w_, p>& other) const { - Mat<num, w_, p> ret; - for (int j = 0; j < w_; j++) + Mat<num, h_, p> ret; + for (int k = 0; k < h_; k++) for (int i = 0; i < p; i++) { - num sum = num(0); - - for (int k = 0; k < h_; k++) - sum += data[j][k]*other(k, i); - - ret(j, i) = sum; + ret(k, i) = 0; + for (int j = 0; j < w_; j++) + ret(k, i) += data[k][j] * other(j, i); } - return ret; } @@ -189,7 +185,7 @@ public: template<typename... ts, int h__ = h_, int w__ = w_, typename = typename std::enable_if<is_arglist_correct<num, h__, w__, ts...>::value>::type> - Mat(ts const&... xs) + Mat(const ts... xs) { const std::initializer_list<num> init = { static_cast<num>(xs)... }; auto iter = init.begin(); @@ -198,14 +194,6 @@ public: data[j][i] = *iter++; } - template<typename t> - Mat(const t* xs) - { - for (int j = 0; j < h_; j++) - for (int i = 0; i < w_; i++) - data[j][i] = num(*xs++); - } - Mat() { for (int j = 0; j < h_; j++) @@ -244,7 +232,7 @@ public: for (int j = 0; j < h_; j++) for (int i = 0; i < w_; i++) - ret.data[i][j] = data[j][i]; + ret(i, j) = data[j][i]; return ret; } diff --git a/opentrack/state.hpp b/opentrack/state.hpp index e4cb0f04..dcb18293 100644 --- a/opentrack/state.hpp +++ b/opentrack/state.hpp @@ -9,7 +9,7 @@ #pragma once #include <vector> -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; #include "opentrack/plugin-support.hpp" #include "opentrack/main-settings.hpp" diff --git a/opentrack/tracker.h b/opentrack/tracker.h index 890660e1..36b5cad4 100644 --- a/opentrack/tracker.h +++ b/opentrack/tracker.h @@ -18,7 +18,7 @@ #include "spline-widget/functionconfig.h" #include "main-settings.hpp" -#include "options.hpp" +#include "opentrack-compat/options.hpp" #include <QMutex> #include <QThread> @@ -40,7 +40,13 @@ public: inline double operator()(int i) const { return axes[i]; } }; -class Tracker : private QThread { +#ifdef BUILD_api +# include "opentrack-compat/export.hpp" +#else +# include "opentrack-compat/import.hpp" +#endif + +class OPENTRACK_EXPORT Tracker : private QThread { Q_OBJECT private: QMutex mtx; @@ -74,7 +80,7 @@ public: void get_raw_and_mapped_poses(double* mapped, double* raw) const; void start() { QThread::start(); } - void toggle_enabled() { enabledp = !enabledp; } - void center() { centerp = !centerp; } - void zero() { zero_ = !zero_; } + void toggle_enabled() { qDebug() << "toggle enabled"; enabledp = !enabledp; } + void center() { qDebug() << "toggle center"; centerp = !centerp; } + void zero() { qDebug() << "toggle zero"; zero_ = !zero_; } }; diff --git a/opentrack/win32-joystick.cpp b/opentrack/win32-joystick.cpp new file mode 100644 index 00000000..5e6f2011 --- /dev/null +++ b/opentrack/win32-joystick.cpp @@ -0,0 +1,299 @@ +#undef NDEBUG +#include <cassert> +#include "win32-joystick.hpp" + +#ifdef _WIN32 + +void win32_joy_ctx::poll(fn f) +{ + //refresh(false); + + QMutexLocker l(&mtx); + + for (auto& j : joys) + { + j.second->poll(f); + } +} + +bool win32_joy_ctx::poll_axis(const QString &guid, int axes[]) +{ + //refresh(false); + + QMutexLocker l(&mtx); + + auto iter = joys.find(guid); + + if (iter == joys.end()) + return false; + + auto& j = iter->second; + + auto& joy_handle = j->joy_handle; + bool ok = false; + HRESULT hr; + + (void) joy_handle->Acquire(); + + if (!FAILED(hr = joy_handle->Poll())) + ok = true; + + if (!ok) + { + qDebug() << "joy acquire failed" << guid << hr; + (void) joy_handle->Unacquire(); + return false; + } + + DIJOYSTATE2 js; + memset(&js, 0, sizeof(js)); + + if (FAILED(hr = joy_handle->GetDeviceState(sizeof(js), &js))) + { + qDebug() << "joy get state failed" << guid << hr; + return false; + } + + const int values[] = { + js.lX, + js.lY, + js.lZ, + js.lRx, + js.lRy, + js.lRz, + js.rglSlider[0], + js.rglSlider[1] + }; + + for (int i = 0; i < 8; i++) + axes[i] = values[i]; + + return true; +} + +win32_joy_ctx::~win32_joy_ctx() +{ + release(); +} + +std::vector<win32_joy_ctx::joy_info> win32_joy_ctx::get_joy_info() +{ + QMutexLocker l(&mtx); + + std::vector<joy_info> ret; + + for (auto& j : joys) + ret.push_back(joy_info { j.second->name, j.first }); + + return ret; +} + +win32_joy_ctx::win32_joy_ctx() +{ + if (DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&di, NULL) != DI_OK) { + qDebug() << "setup DirectInput8 Creation failed!" << GetLastError(); + assert(!"direct input handle can't be created"); + } + refresh(); +} + +void win32_joy_ctx::release() +{ + joys = std::unordered_map<QString, std::shared_ptr<joy>>(); + di->Release(); + di = nullptr; +} + +void win32_joy_ctx::refresh() +{ + QMutexLocker l(&mtx); + + qDebug() << "joy list refresh"; + enum_state st(joys, fake_main_window, di); +} + +QString win32_joy_ctx::guid_to_string(const GUID guid) +{ + char buf[40] = {0}; + wchar_t szGuidW[40] = {0}; + + StringFromGUID2(guid, szGuidW, 40); + WideCharToMultiByte(0, 0, szGuidW, -1, buf, 40, NULL, NULL); + + return QString(buf); +} + +using fn = win32_joy_ctx::fn; + +void win32_joy_ctx::joy::release() +{ + if (joy_handle) + { + (void) joy_handle->Unacquire(); + joy_handle->Release(); + joy_handle = nullptr; + } +} + +bool win32_joy_ctx::joy::poll(fn f) +{ + HRESULT hr; + bool ok = false; + + (void) joy_handle->Acquire(); + + if (!FAILED(hr = joy_handle->Poll())) + ok = true; + + if (!ok) + { + qDebug() << "joy acquire failed" << guid << hr; + (void) joy_handle->Unacquire(); + return false; + } + + DIJOYSTATE2 js; + memset(&js, 0, sizeof(js)); + + if (FAILED(hr = joy_handle->GetDeviceState(sizeof(js), &js))) + { + qDebug() << "joy get state failed" << guid << hr; + return false; + } + + for (int i = 0; i < 128; i++) + { + const bool state = !!(js.rgbButtons[i] & 0x80) && js.rgbButtons[i] != js_old.rgbButtons[i]; + if (state != pressed[i]) + { + f(guid, i, state); + qDebug() << "btn" << guid << i << state; + } + pressed[i] = state; + } + + js_old = js; + + return true; +} + +win32_joy_ctx::enum_state::enum_state(std::unordered_map<QString, std::shared_ptr<joy>> &joys, + QMainWindow &fake_main_window, + LPDIRECTINPUT8 di) : + fake_main_window(fake_main_window), + di(di) +{ + this->joys = joys; + + HRESULT hr; + + if(FAILED(hr = di->EnumDevices(DI8DEVCLASS_GAMECTRL, + EnumJoysticksCallback, + this, + DIEDFL_ATTACHEDONLY))) + { + qDebug() << "failed enum joysticks" << hr; + return; + } + + auto& js = this->joys; + + for (auto it = js.begin(); it != js.end(); ) + { + if (std::find_if(all.cbegin(), all.cend(), [&](const QString& guid2) -> bool { return it->second->guid == guid2; }) == all.cend()) + it = js.erase(it); + else + it++; + } + + joys = this->joys; +} + +win32_joy_ctx::enum_state::EnumJoysticksCallback(const DIDEVICEINSTANCE *pdidInstance, void *pContext) +{ + enum_state& state = *reinterpret_cast<enum_state*>(pContext); + const QString guid = guid_to_string(pdidInstance->guidInstance); + const QString name = QString(pdidInstance->tszInstanceName); + + auto it = state.joys.find(guid); + const bool exists = it != state.joys.end(); + + state.all.push_back(guid); + + if (!exists) + { + HRESULT hr; + LPDIRECTINPUTDEVICE8 h; + if (FAILED(hr = state.di->CreateDevice(pdidInstance->guidInstance, &h, nullptr))) + { + qDebug() << "createdevice" << guid << hr; + goto end; + } + if (FAILED(h->SetDataFormat(&c_dfDIJoystick2))) + { + qDebug() << "format"; + h->Release(); + goto end; + } + + if (FAILED(h->SetCooperativeLevel((HWND) state.fake_main_window.winId(), DISCL_NONEXCLUSIVE | DISCL_BACKGROUND))) + { + qDebug() << "coop"; + h->Release(); + goto end; + } + if (FAILED(hr = h->EnumObjects(EnumObjectsCallback, h, DIDFT_ALL))) + { + qDebug() << "enum-objects"; + h->Release(); + goto end; + } + + qDebug() << "add joy" << guid; + state.joys[guid] = std::make_shared<joy>(h, guid, name); + } +end: + return DIENUM_CONTINUE; +} + +win32_joy_ctx::enum_state::EnumObjectsCallback(const DIDEVICEOBJECTINSTANCE *pdidoi, void *ctx) +{ + if (pdidoi->dwType & DIDFT_AXIS) + { + DIPROPRANGE diprg; + memset(&diprg, 0, sizeof(diprg)); + diprg.diph.dwSize = sizeof( DIPROPRANGE ); + diprg.diph.dwHeaderSize = sizeof( DIPROPHEADER ); + diprg.diph.dwHow = DIPH_BYID; + diprg.diph.dwObj = pdidoi->dwType; + diprg.lMax = joy_axis_size; + diprg.lMin = -joy_axis_size; + + HRESULT hr; + + if (FAILED(hr = reinterpret_cast<LPDIRECTINPUTDEVICE8>(ctx)->SetProperty(DIPROP_RANGE, &diprg.diph))) + { + qDebug() << "DIPROP_RANGE" << hr; + return DIENUM_STOP; + } + } + + return DIENUM_CONTINUE; +} + +win32_joy_ctx::joy::joy(LPDIRECTINPUTDEVICE8 handle, const QString &guid, const QString &name) + : joy_handle(handle), guid(guid), name(name) +{ + qDebug() << "got joy" << guid; + for (int i = 0; i < 128; i++) + pressed[i] = false; + memset(&js_old, 0, sizeof(js_old)); +} + +win32_joy_ctx::joy::~joy() +{ + qDebug() << "nix joy" << guid; + release(); +} + +#endif diff --git a/opentrack/win32-joystick.hpp b/opentrack/win32-joystick.hpp new file mode 100644 index 00000000..9c888326 --- /dev/null +++ b/opentrack/win32-joystick.hpp @@ -0,0 +1,100 @@ +#pragma once + +#ifdef _WIN32 + +#include <cstring> +#include <memory> +#include <vector> +#include <functional> +#include <algorithm> +#include <unordered_map> +#ifndef DIRECTINPUT_VERSION +# define DIRECTINPUT_VERSION 0x800 +#endif +#include <dinput.h> +#include <windows.h> +#include "opentrack-compat/timer.hpp" +#include <QString> +#include <QDebug> +#include <QMutex> +#include <QMutexLocker> +#include <QMainWindow> + +namespace std { +template<> +struct hash<QString> +{ + inline std::size_t operator()(const QString& value) const + { + return qHash(value); + } +}; +} + +#ifdef BUILD_api +# include "opentrack-compat/export.hpp" +#else +# include "opentrack-compat/import.hpp" +#endif + +struct OPENTRACK_EXPORT win32_joy_ctx +{ + using fn = std::function<void(const QString& guid, int btn, bool held)>; + + enum { joy_axis_size = 65535 }; + + struct joy_info + { + QString name, guid; + }; + + void poll(fn f); + bool poll_axis(const QString& guid, int axes[8]); + std::vector<joy_info> get_joy_info(); + + win32_joy_ctx(const win32_joy_ctx&) = delete; + win32_joy_ctx& operator=(const win32_joy_ctx&) = delete; + + win32_joy_ctx(); + ~win32_joy_ctx(); + void refresh(); +private: + QMutex mtx; + QMainWindow fake_main_window; + LPDIRECTINPUT8 di; + + static QString guid_to_string(const GUID guid); + void release(); + + struct joy + { + LPDIRECTINPUTDEVICE8 joy_handle; + QString guid, name; + bool pressed[128]; + Timer first_timer; + DIJOYSTATE2 js_old; + + joy(LPDIRECTINPUTDEVICE8 handle, const QString& guid, const QString& name); + ~joy(); + + void release(); + bool poll(fn f); + }; + + std::unordered_map<QString, std::shared_ptr<joy>> joys; + + class enum_state + { + std::unordered_map<QString, std::shared_ptr<joy>> joys; + QMainWindow& fake_main_window; + LPDIRECTINPUT8 di; + + std::vector<QString> all; + static BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE* pdidInstance, VOID* pContext); + static BOOL CALLBACK EnumObjectsCallback(const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* ctx); + public: + enum_state(std::unordered_map<QString, std::shared_ptr<joy>>& joys, QMainWindow& fake_main_window, LPDIRECTINPUT8 di); + }; +}; + +#endif diff --git a/opentrack/win32-shortcuts.cpp b/opentrack/win32-shortcuts.cpp index a0ed51b3..fb84e709 100644 --- a/opentrack/win32-shortcuts.cpp +++ b/opentrack/win32-shortcuts.cpp @@ -116,6 +116,7 @@ QList<win_key> windows_key_sequences = win_key(DIK_Z, Qt::Key::Key_Z ), win_key(DIK_RETURN, Qt::Key::Key_Return), win_key(DIK_INSERT, Qt::Key::Key_Insert), + win_key(DIK_DELETE, Qt::Key::Key_Delete), win_key(DIK_SPACE, Qt::Key::Key_Space), win_key(DIK_SYSRQ, Qt::Key::Key_Print), win_key(DIK_SCROLL, Qt::Key::Key_ScrollLock), diff --git a/opentrack/win32-shortcuts.h b/opentrack/win32-shortcuts.h index fe92ae53..9b2c6121 100644 --- a/opentrack/win32-shortcuts.h +++ b/opentrack/win32-shortcuts.h @@ -10,7 +10,13 @@ struct win_key; extern QList<win_key> windows_key_mods; extern QList<win_key> windows_key_sequences; -struct win_key +#ifdef BUILD_api +# include "opentrack-compat/export.hpp" +#else +# include "opentrack-compat/import.hpp" +#endif + +struct OPENTRACK_EXPORT win_key { win_key(int win, Qt::Key qt) : win(win), qt(qt) {} int win; diff --git a/opentrack/work.hpp b/opentrack/work.hpp index 5d1f6b54..4188b937 100644 --- a/opentrack/work.hpp +++ b/opentrack/work.hpp @@ -16,6 +16,9 @@ #include <QObject> #include <QFrame> #include <memory> +#include <vector> +#include <functional> +#include <tuple> struct Work { @@ -24,32 +27,33 @@ struct Work mem<Tracker> tracker; mem<Shortcuts> sc; WId handle; - - Work(main_settings& s, Mappings& m, SelectedLibraries& libs, QObject* recv, WId handle) : + using fn = std::function<void(void)>; + using tt = std::tuple<key_opts&, fn>; + std::vector<std::tuple<key_opts&, fn>> keys; + + Work(main_settings& s, Mappings& m, SelectedLibraries& libs, WId handle) : s(s), libs(libs), tracker(std::make_shared<Tracker>(s, m, libs)), - sc(std::make_shared<Shortcuts>(handle)), - handle(handle) + sc(std::make_shared<Shortcuts>()), + handle(handle), + keys { + tt(s.key_center, [&]() -> void { tracker->center(); }), + tt(s.key_toggle, [&]() -> void { tracker->toggle_enabled(); }), + tt(s.key_zero, [&]() -> void { tracker->zero(); }), + } { -#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.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(); + reload_shortcuts(); + tracker->start(); } void reload_shortcuts() { - sc->reload(); + sc->reload(keys); } ~Work() { + sc = nullptr; // order matters, otherwise use-after-free -sh tracker = nullptr; libs = SelectedLibraries(); diff --git a/pose-widget/CMakeLists.txt b/pose-widget/CMakeLists.txt index 66cafef7..e48660d7 100644 --- a/pose-widget/CMakeLists.txt +++ b/pose-widget/CMakeLists.txt @@ -1 +1 @@ -opentrack_boilerplate(opentrack-pose-widget NO-LINKER-SCRIPT) +opentrack_boilerplate(opentrack-pose-widget NO-LINKER-SCRIPT LINKAGE) diff --git a/pose-widget/glwidget.cpp b/pose-widget/glwidget.cpp index 3ee480a1..1b30e585 100644 --- a/pose-widget/glwidget.cpp +++ b/pose-widget/glwidget.cpp @@ -98,16 +98,18 @@ inline GLWidget::vec3 GLWidget::normal(const vec3& p1, const vec3& p2, const vec void GLWidget::project_quad_texture() { const int sx = width(), sy = height(); - vec2 pt[4]; + const int ow = front.width(), oh = front.height(); const vec3 corners[] = { - vec3(0., 0, 0), - vec3(sx-1, 0, 0), - vec3(0, sy-1, 0), - vec3(sx-1, sy-1, 0.) + vec3(-ow/2., -oh/2, 0), + vec3(ow/2, -oh/2, 0), + vec3(-ow/2, oh/2, 0), + vec3(ow/2, oh/2, 0.) }; + vec2 pt[4]; + vec2 sz((sx-ow)/2, (sy-oh)/2); for (int i = 0; i < 4; i++) - pt[i] = project(vec3(corners[i].x() - sx/2, corners[i].y() - sy/2, 0)) + vec2(sx/2, sy/2); + pt[i] = project(corners[i]) + vec2(sx/2, sy/2); vec3 normal1(0, 0, 1); vec3 normal2; @@ -122,9 +124,7 @@ void GLWidget::project_quad_texture() { QImage& tex = dir < 0 ? back : front; - int ow = tex.width(), oh = tex.height(); - - QImage texture(QSize(sx, sy), QImage::Format_RGB888); + QImage texture(QSize(sx, sy), QImage::Format_RGBA8888); QColor bgColor = palette().color(QPalette::Current, QPalette::Window); texture.fill(bgColor); @@ -199,6 +199,11 @@ void GLWidget::project_quad_texture() { const unsigned char r___ = orig[orig_pos___ + 2]; const unsigned char g___ = orig[orig_pos___ + 1]; const unsigned char b___ = orig[orig_pos___ + 0]; + + const unsigned char a1 = orig[orig_pos + 3]; + const unsigned char a2 = orig[orig_pos_ + 3]; + const unsigned char a3 = orig[orig_pos__ + 3]; + const unsigned char a4 = orig[orig_pos___ + 3]; const int pos = y * dest_pitch + x * dest_depth; @@ -207,6 +212,7 @@ void GLWidget::project_quad_texture() { dest[pos + 0] = (r * ax + r__ * ax_) * ay + (r___ * ax + r_ * ax_) * ay_; dest[pos + 1] = (g * ax + g__ * ax_) * ay + (g___ * ax + g_ * ax_) * ay_; dest[pos + 2] = (b * ax + b__ * ax_) * ay + (b___ * ax + b_ * ax_) * ay_; + dest[pos + 3] = (a1 * ax + a3 * ax_) * ay + (a4 * ax + a2 * ax_) * ay_; break; } diff --git a/pose-widget/glwidget.h b/pose-widget/glwidget.h index fca3502d..8896a3cf 100644 --- a/pose-widget/glwidget.h +++ b/pose-widget/glwidget.h @@ -13,7 +13,7 @@ #include "opentrack/plugin-api.hpp" #include "opentrack/simple-mat.hpp" -#ifdef BUILD_opentrack_pose_widget +#ifdef BUILD_pose_widget # define POSE_WIDGET_EXPORT Q_DECL_EXPORT #else # define POSE_WIDGET_EXPORT Q_DECL_IMPORT diff --git a/pose-widget/images/side1.png b/pose-widget/images/side1.png Binary files differindex 1424faa3..e85a3205 100755 --- a/pose-widget/images/side1.png +++ b/pose-widget/images/side1.png diff --git a/pose-widget/images/side6.png b/pose-widget/images/side6.png Binary files differindex 1424faa3..e85a3205 100755 --- a/pose-widget/images/side6.png +++ b/pose-widget/images/side6.png diff --git a/proto-fg/ftnoir_protocol_fg.h b/proto-fg/ftnoir_protocol_fg.h index de528270..5b1cbc81 100644 --- a/proto-fg/ftnoir_protocol_fg.h +++ b/proto-fg/ftnoir_protocol_fg.h @@ -15,7 +15,7 @@ #include <QUdpSocket> #include <QMessageBox> #include "opentrack/plugin-api.hpp" -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; struct settings : opts { diff --git a/proto-fsuipc/ftnoir_protocol_fsuipc.h b/proto-fsuipc/ftnoir_protocol_fsuipc.h index c8e91a42..af59e988 100644 --- a/proto-fsuipc/ftnoir_protocol_fsuipc.h +++ b/proto-fsuipc/ftnoir_protocol_fsuipc.h @@ -24,7 +24,7 @@ #include <QDebug> #include <QFile> #include <QFileDialog> -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; #define FSUIPC_FILENAME "C:\\Program Files\\Microsoft Games\\Flight Simulator 9\\Modules\\FSUIPC.dll" diff --git a/proto-ft/ftnoir_protocol_ft.h b/proto-ft/ftnoir_protocol_ft.h index 8e50f1cb..9cf16f03 100644 --- a/proto-ft/ftnoir_protocol_ft.h +++ b/proto-ft/ftnoir_protocol_ft.h @@ -19,7 +19,7 @@ #include <QMutex> #include <QMutexLocker> #include "opentrack-compat/shm.h" -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" #include "freetrackclient/fttypes.h" using namespace options; diff --git a/proto-ftn/ftnoir_protocol_ftn.h b/proto-ftn/ftnoir_protocol_ftn.h index 7fe6c225..d8b8aff0 100644 --- a/proto-ftn/ftnoir_protocol_ftn.h +++ b/proto-ftn/ftnoir_protocol_ftn.h @@ -16,7 +16,7 @@ #include <QMessageBox> #include <cmath> #include "opentrack/plugin-api.hpp" -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; struct settings : opts { diff --git a/proto-mouse/ftnoir_protocol_mouse.h b/proto-mouse/ftnoir_protocol_mouse.h index 595be393..f1730777 100644 --- a/proto-mouse/ftnoir_protocol_mouse.h +++ b/proto-mouse/ftnoir_protocol_mouse.h @@ -10,7 +10,7 @@ #include "ui_ftnoir_mousecontrols.h" #include <QDebug> #include "opentrack/plugin-api.hpp" -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; struct settings : opts { diff --git a/proto-sc/ftnoir_protocol_sc.h b/proto-sc/ftnoir_protocol_sc.h index 671a3500..dcc0ca77 100644 --- a/proto-sc/ftnoir_protocol_sc.h +++ b/proto-sc/ftnoir_protocol_sc.h @@ -20,7 +20,7 @@ #include <QProcess> #include <QDebug> #include <QFile> -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; #include <windows.h> diff --git a/qxt-mini/CMakeLists.txt b/qxt-mini/CMakeLists.txt index 5de29cd1..a8b8fb1d 100644 --- a/qxt-mini/CMakeLists.txt +++ b/qxt-mini/CMakeLists.txt @@ -1,5 +1,5 @@ if(UNIX OR APPLE) - opentrack_boilerplate(opentrack-qxt-mini NO-LINKER-SCRIPT NO-COMPAT) + opentrack_boilerplate(opentrack-qxt-mini NO-LINKER-SCRIPT NO-COMPAT LINKAGE) if(NOT APPLE) target_link_libraries(opentrack-qxt-mini X11) else() diff --git a/qxt-mini/QxtGlobalShortcut b/qxt-mini/QxtGlobalShortcut index d673035b..c2827bc2 100644 --- a/qxt-mini/QxtGlobalShortcut +++ b/qxt-mini/QxtGlobalShortcut @@ -1,2 +1,4 @@ -#include "qxtglobalshortcut.h" +#ifndef _WIN32 +# include "qxtglobalshortcut.h" +#endif diff --git a/qxt-mini/qxtglobal.h b/qxt-mini/qxtglobal.h index 64fd35dc..913da556 100644 --- a/qxt-mini/qxtglobal.h +++ b/qxt-mini/qxtglobal.h @@ -51,7 +51,7 @@ #define QXT_DLLEXPORT DO_NOT_USE_THIS_ANYMORE -#ifdef BUILD_opentrack_qxt_mini +#ifdef BUILD_qxt_mini # define QXT_BUILD # define BUILD_QXT_GUI # define BUILD_QXT diff --git a/settings/facetracknoir supported games.csv b/settings/facetracknoir supported games.csv index cf43d7f6..55b38a47 100644 --- a/settings/facetracknoir supported games.csv +++ b/settings/facetracknoir supported games.csv @@ -5,13 +5,17 @@ No;Game Name;Game protocol;Supported since;Verified;By;INTERNATIONAL_ID;FTN_ID 3;3D Instructor;FreeTrack20;V160;;;20490;00034B0FC367116611B100 4;3D Interactive;FreeTrack20;V160;;;20425;0004C6371D77135815A600 505;3D Interieur Visualisation;FreeTrack20;V160;;;20815;01F9EDEE75DAC2968D9A00 -5;3d Nav;FreeTrack20;V160;;;20235;000579EC0E26932651EA00 6;3D-Fahrschule Driving Simulator;FreeTrack20;V160;;;20020;000601075146E0E9625B00 +5;3d Nav;FreeTrack20;V160;;;20235;000579EC0E26932651EA00 7;3ds Max;FreeTrack20;V160;;;8601;00077A32A1A7523A4DE700 +11;ADS;FreeTrack20;V160;;;20690;000BB25377780C8A894400 +20;ANAG 3D;FreeTrack20;V160;;;20250;0014E2D1D7780A72166300 +498;ARI;FreeTrack20;V160;;;20795;01F23FB9A61044E206E200 +32;AV Core Technology;FreeTrack20;V160;;;20016;00204655E791166FEB5300 +33;AVRS;FreeTrack20;V160;;;20340;0021231517525830F41D00 8;Aaaaa!;FreeTrack20;V160;;;1775;00085485D831DA62CA7E00 9;Accessible Computer Games;FreeTrack20;V160;;;4301;000916BC07A2F9B35B6300 10;Aces High II;FreeTrack20;V160;V;bash1;2701;000A4B798B7221A72E5800 -11;ADS;FreeTrack20;V160;;;20690;000BB25377780C8A894400 12;Aerofly FS;FreeTrack20;V160;V;V4Friend;2025;000C3797169752CAB39A00 13;Affineon;FreeTrack20;V160;;;20405;000D662B0374339635A000 14;Air Battles: Sky Defender;FreeTrack20;V160;;;7003;000E7C822098630A2ED700 @@ -20,12 +24,10 @@ No;Game Name;Game protocol;Supported since;Verified;By;INTERNATIONAL_ID;FTN_ID 17;AirBook;FreeTrack20;V160;;;15201;0011D615A9C8430A201A00 18;America's Army;FreeTrack20;V160;;;4101;00120BCF5753D98399E200 19;America's Army 3;FreeTrack20;V170;;;14203;00133F3206BCEA252BB700 -20;ANAG 3D;FreeTrack20;V160;;;20250;0014E2D1D7780A72166300 21;Apache: Air Assault;FreeTrack20;V160;V;paleta77;1875;001591D997A2D912AAA200 519;Apex Motorsports;FreeTrack20;V160;;;3675;02078F3159271BBE676800 22;Aprisoft Gartenplaner;FreeTrack20;V160;;;20014;0016F2F27A5762FA937A00 23;Aprisoft Traumhaus Designer;FreeTrack20;V160;;;20013;00174655E792BB825B9300 -498;ARI;FreeTrack20;V160;;;20795;01F23FB9A61044E206E200 24;ArmA;FreeTrack20;V160;V;EmBeES;10601;0018F2F27A57631A40F200 25;ArmA 2;FreeTrack20;V170;V;V4Friend Ronski;7502;0019EB3616B3A44F05B900 26;ArmA 2 Operation Arrowhead;FreeTrack20;V160;V;vn88holden;0;001ABC224B7783DAF0D500 @@ -36,22 +38,20 @@ No;Game Name;Game protocol;Supported since;Verified;By;INTERNATIONAL_ID;FTN_ID 30;Arvoch Conflict;FreeTrack20;V160;;;14901;001E5C1FDE722DAE2BA900 31;Auditory Displays for the blind;FreeTrack20;V160;;;20035;001F0FC9FF862F9D34BA00 486;Autodesk;FreeTrack20;V160;;;20755;01E6953FA7F759AF33AC00 -32;AV Core Technology;FreeTrack20;V160;;;20016;00204655E791166FEB5300 -33;AVRS;FreeTrack20;V160;;;20340;0021231517525830F41D00 482;B.O.M.B.;FreeTrack20;V160;;;3325;01E248ECCB81191AD49F00 34;BAE Systems HILAS cockpit;FreeTrack20;V160;;;20019;00220D9C887FD88E98B300 +45;BF2 (Unsupported Demo);FreeTrack20;V160;;;9651;002DC6371D86156AEB6000 35;Battle of Britain (iENT);FreeTrack20;V170;;;1305;00230BA119195B701AED00 36;Battle of Britain II - Wings of Victory;FreeTrack20;V160;V;Normalguy;7001;002452135882CA6419E200 37;Battlecruiser;FreeTrack20;V160;;;6101;00257C822098728A442900 38;Battlefield 2;FreeTrack20;V170;;;9601;0026B1560A2A7327659200 39;Battlefield 2 Trauma Studios;FreeTrack20;V160;;;6501;002720C7529B733AE2EA00 40;Battlefield 2142;FreeTrack20;V170;;;9602;00281C739AD3817FD43300 -41;Battleground Europe : World War II Online;FreeTrack20;V160;;;3301;0029F07957792CAD3DAF00 42;Battleground Europe : WWII Online;FreeTrack20;V160;;;11201;002A985017330A844A1200 +41;Battleground Europe : World War II Online;FreeTrack20;V160;;;3301;0029F07957792CAD3DAF00 573;Beamng.drive;FreeTrack20;V160;;;4525;023D0291C9C05323AC9500 43;Beckman Institute UIUC;FreeTrack20;V160;;;20012;002BB59DEFA8322A926A00 44;Beyond The Red Line;FreeTrack20;V160;;;13301;002CE7A7FAA27424BA2A00 -45;BF2 (Unsupported Demo);FreeTrack20;V160;;;9651;002DC6371D86156AEB6000 46;Big Scale Racing;FreeTrack20;V160;;;8301;002E4655E7A24ADDB99200 47;Birds of Prey;FreeTrack20;V160;;;1601;002FBF8C4EAA57730B3200 48;Birds of Steel;FreeTrack20;V160;;;1878;0030D7690F607233A21E00 @@ -63,15 +63,17 @@ No;Game Name;Game protocol;Supported since;Verified;By;INTERNATIONAL_ID;FTN_ID 82;C-Spine;FreeTrack20;V160;;;4901;00525FD692C188FB8B2D00 54;C.A.R.S.;FreeTrack20;V170;;;2825;003698EFE2EB6EE8E11300 55;C.U.B.;FreeTrack20;V160;;;20505;0037848174F986FD85F500 -56;CameraGripTools;FreeTrack20;V160;;;20150;003870A8B761FA524A4200 -57;Caterpillar Simulators;FreeTrack20;V160;;;23080;0039F52E4221742FA63100 58;CCG Metamedia;FreeTrack20;V160;;;20009;003A6FA8A8DD86FE8BDB00 547;CDF Ghostship;FreeTrack20;V160;;;4150;02230A04C45292CC5DA400 568;CDF Starfighter;FreeTrack20;V160;;;4153;0238E7D9A14B2A1AE98900 59;CEWIT Immersive Cabin;FreeTrack20;V160;;;20370;003B90B5780C90078DEE00 +62;CNKFsoft;FreeTrack20;V160;;;20495;003ED7690F6073187B0000 +555;COMPUTERGRAFIK;FreeTrack20;V160;;;20900;022B5BB1CE1DAA0B1DEB00 +571;CS GO MOD;FreeTrack20;V160;;;12504;023BCA154A55F9587FC500 +56;CameraGripTools;FreeTrack20;V160;;;20150;003870A8B761FA524A4200 +57;Caterpillar Simulators;FreeTrack20;V160;;;23080;0039F52E4221742FA63100 60;Chopper;FreeTrack20;V160;;;3150;003CC166C8632A32EA2300 61;Clearbox;FreeTrack20;V160;;;20565;003D5C1FDE74279D1DB800 -62;CNKFsoft;FreeTrack20;V160;;;20495;003ED7690F6073187B0000 558;Code 10;FreeTrack20;V160;;;2975;022E45423D22193FF81900 487;Cognitics;FreeTrack20;V160;;;20760;01E715A96D19515BFC1500 63;Colin McRae DiRT 2;FreeTrack20;V170;V;V4Friend;8107;003F7815C5379491C73300 @@ -82,7 +84,6 @@ No;Game Name;Game protocol;Supported since;Verified;By;INTERNATIONAL_ID;FTN_ID 67;Combat Helo;FreeTrack20;V160;;;2001;004329DFA863FAE1EA7300 515;Combined Arms;FreeTrack20;V160;;;1309;0203387EDB1A5AFEADB600 68;Commandos Strike Force;FreeTrack20;V160;;;8801;0044C1BBF892DB037A7200 -555;COMPUTERGRAFIK;FreeTrack20;V160;;;20900;022B5BB1CE1DAA0B1DEB00 69;Concept RS;FreeTrack20;V160;;;10701;004537971697736A72DA00 70;Condor: The Competitive Soaring Simulator;FreeTrack20;V160;V;MicheleF;5901;004670A8B762DA623A1300 71;Conflict Taiwan;FreeTrack20;V160;;;1950;0047D7690F6073399E2000 @@ -97,16 +98,17 @@ No;Game Name;Game protocol;Supported since;Verified;By;INTERNATIONAL_ID;FTN_ID 79;Crysis Mod;FreeTrack20;V160;;;1625;004F90B57839B231A24200 80;Crystal Growth Simulation;FreeTrack20;V160;;;20029;005026F79742FB241A6200 81;Crytek;FreeTrack20;V170;;;2775;0051D5F1EBBAD81C714600 -571;CS GO MOD;FreeTrack20;V160;;;12504;023BCA154A55F9587FC500 562;Cypher City;FreeTrack20;V160;;;4250;023259070AE238A9E78100 83;D2x-XL;FreeTrack20;V160;;;16001;00532E20237BEDABEB8A00 +87;DBS WalkAndFollow;FreeTrack20;V160;;;2525;005770A8B77008BDE89200 +88;DCS: Black Shark;FreeTrack20;V170;V;EmBeES;1006;0058F688FC9B0556868F00 +89;DCS: A-10C Warthog (32 and 64 bit);FreeTrack20;V170;V;fabri91 Shadow;1003;0059B6DCD15F5A572F6500 +101;DTS;FreeTrack20;V160;;;20625;006505B37C12868B3E8500 +103;DY Demo;FreeTrack20;V160;;;20345;006727D5047A15540F9D00 84;Dark Horizons Lore;FreeTrack20;V160;;;7901;005487801A852AA7385200 85;Dawn of Aces - Gold Edition;FreeTrack20;V170;;;1304;0055A9ED7700814190DE00 86;Dawn of Aces II;FreeTrack20;V160;;;1302;00566925967C2BB0285500 513;Dawn of Aces/Red Baron;FreeTrack20;V160;;;1307;0201916C14F32918D9B800 -87;DBS WalkAndFollow;FreeTrack20;V160;;;2525;005770A8B77008BDE89200 -88;DCS: Black Shark;FreeTrack20;V170;V;EmBeES;1006;0058F688FC9B0556868F00 -89;DCS: A-10C Warthog (32 and 64 bit);FreeTrack20;V170;V;fabri91 Shadow;1003;0059B6DCD15F5A572F6500 90;Dead Reckoning;FreeTrack20;V160;;;10401;005A4C2F6752F912D66200 91;Delivery;FreeTrack20;V160;;;15901;005BF3E85B1A8534AE3400 471;Demon Core;FreeTrack20;V160;;;3225;01D7D1DC6052A165A7AC00 @@ -117,40 +119,36 @@ No;Game Name;Game protocol;Supported since;Verified;By;INTERNATIONAL_ID;FTN_ID 528;Dovetail Games;FreeTrack20;V160;;;3850;0210EE3E0DA9BC1B888100 534;Dovetail Train Simulator 2015;FreeTrack20;V160;;;3851;02160B238D555F3D389E00 95;Down In Flames;FreeTrack20;V160;;;1025;005F29DFA873FB82A66000 +98;DriveSim;FreeTrack20;V160;;;5001;0062DD7CC2B47830A14400 96;Driver Test;FreeTrack20;V160;;;20265;00609343487C3FAA429D00 97;Driver's Republic;FreeTrack20;V160;;;14001;0061D24C3F8A3F9C33AB00 -98;DriveSim;FreeTrack20;V160;;;5001;0062DD7CC2B47830A14400 99;Driving Simulator;FreeTrack20;V160;;;13001;00630AC67539AC3F9F3A00 -100;dSphere TBA;FreeTrack20;V160;;;2425;0064A2AE4981FB5389A300 -101;DTS;FreeTrack20;V160;;;20625;006505B37C12868B3E8500 102;Dungeons and Dragons Online;FreeTrack20;V170;;;1575;0066BD4D4DDC6BB6818800 -103;DY Demo;FreeTrack20;V160;;;20345;006727D5047A15540F9D00 104;EADS Testing;FreeTrack20;V160;;;20303;00680288709760D5512900 504;EAFIT;FreeTrack20;V160;;;20810;01F8D2675ABC163E99B000 +107;ECA-Sindel;FreeTrack20;V160;;;20590;006BC5BEE479FD75FB8500 +108;EMS Simulations;FreeTrack20;V160;;;20390;006CA59E687D1589DE8500 +112;EON Reality;FreeTrack20;V160;;;20410;0070B6C6142771F82EE900 +115;EVE Online;FreeTrack20;V160;;;11801;0073F47CC377C2388DC900 +550;EVE Valkyrie;FreeTrack20;V170;;;4175;104F28E121C07E6D84C200 +117;EVOC-101 Training;FreeTrack20;V160;;;20038;00756925967D2088FC6200 +122;EZCA;FreeTrack20;V160;V;dennison ;2475;007A6DBB52F7B147510601 +572;EZCamViews;FreeTrack20;V160;;;4475;023CF141A5E222B5ACE000 105;Eagle Lander 3D;FreeTrack20;V160;;;11901;00697686E5A7B209C27900 106;EasyVR;FreeTrack20;V160;;;20220;006A68292872FAC4588100 -107;ECA-Sindel;FreeTrack20;V160;;;20590;006BC5BEE479FD75FB8500 508;Elite: Dangerous;FreeTrack20;V170;;;3475;0D93A9485EECA12E18BE00 481;Embers of Caerus;FreeTrack20;V170;;;3275;0CCB4134258D7E10119E00 -108;EMS Simulations;FreeTrack20;V160;;;20390;006CA59E687D1589DE8500 109;Enemy Engaged 2;FreeTrack20;V160;;;2102;006D010873EA635AEDC800 110;Enemy Engaged: Commanche vs Hokum;FreeTrack20;V160;;;2101;006E157D789379636AED00 524;Enemy Starfighter;FreeTrack20;V160;;;3725;020C7EF3AC4F08C8787600 111;Envision TE;FreeTrack20;V160;;;20320;006FD13C2A863CAF26AB00 -112;EON Reality;FreeTrack20;V160;;;20410;0070B6C6142771F82EE900 -113;eSigma;FreeTrack20;V160;;;20700;0071950F9AA60DAD2E9F00 114;Euro Truck Simulator;FreeTrack20;V160;V;mamsa;13602;00721B4BFF8B3EA3296600 -115;EVE Online;FreeTrack20;V160;;;11801;0073F47CC377C2388DC900 -550;EVE Valkyrie;FreeTrack20;V170;;;4175;104F28E121C07E6D84C200 116;Eventology;FreeTrack20;V160;;;12201;0074849F8B469C2BAC3600 -117;EVOC-101 Training;FreeTrack20;V160;;;20038;00756925967D2088FC6200 118;Evochron Alliance 2.0;FreeTrack20;V160;;;14904;00767A32A1A8735A022900 557;Evochron Legacy;FreeTrack20;V160;;;14909;022D84A6946770E4EFD800 119;Evochron Legends;FreeTrack20;V160;;;14906;0077D6E585F8B41A12BA00 120;Evochron Mercenary;FreeTrack20;V160;V;Scavenger4711 ;14907;00783752FBC7B42B221A00 121;Evochron Renegades;FreeTrack20;V160;;;14905;0079621E7763FB421A1300 -122;EZCA;FreeTrack20;V160;V;dennison ;2475;007A6DBB52F7B147510601 -572;EZCamViews;FreeTrack20;V160;;;4475;023CF141A5E222B5ACE000 125;F-22 Total Air War;FreeTrack20;V160;;;1750;007D20C79F475F0621DB00 126;F-35 PTA;FreeTrack20;V160;;;20185;007E26F7977E96C0352100 148;F-Trainer;FreeTrack20;V160;;;20615;0094C6371D8AFB8C3E9900 @@ -158,11 +156,13 @@ No;Game Name;Game protocol;Supported since;Verified;By;INTERNATIONAL_ID;FTN_ID 531;F1 2015;FreeTrack20;V170;;;8110;1FAE39C238A4D2D6541200 124;F1 Challenge 99-02;FreeTrack20;V160;;;4401;007CA15F278FB660C9D210 127;FAAC;FreeTrack20;V160;;;20500;007F0F00F489118300C000 +132;FIFA 09;FreeTrack20;V170;;;9002;0084288979C65B0DAA0D00 +552;FSX Steam Edition;FreeTrack20;V160;;;3852;02287F45F0FFBEF6102900 +147;FTAlpha;FreeTrack20;V160;;;20270;00936C69677F1D772AA900 128;Farmer Simulator 2009;FreeTrack20;V160;;;1725;0080926ED8A1EB628AB300 129;Faros Driving Simulator;FreeTrack20;V160;;;8001;0081B1C6647A1EA839A800 130;Faubert Lab Car Simulator;FreeTrack20;V160;;;20480;00822E542A7F2DB61F9700 131;Ferrari Virtual Academy;FreeTrack20;V160;V;sosna1983 ;0;0083C0AF8C24B62D974000 -132;FIFA 09;FreeTrack20;V170;;;9002;0084288979C65B0DAA0D00 133;Fighter Ace;FreeTrack20;V160;;;8401;0085E2D1D77D259837B700 134;Fighter Ops;FreeTrack20;V160;;;9301;00860FC9FF8B23A033BA00 135;Fighter Squadron: Screamin Demons Over Europe;FreeTrack20;V160;;;1675;00872E20237D259A27A600 @@ -183,10 +183,13 @@ No;Game Name;Game protocol;Supported since;Verified;By;INTERNATIONAL_ID;FTN_ID 144;Free Falcon 4.0: Allied Force;FreeTrack20;V160;;;8901;0090656DD6793CA9325900 145;Free Falcon 5;FreeTrack20;V160;V;V4Friend;1902;00911038C3AAB32590E900 146;FreeSpace2;FreeTrack20;V160;;;13302;0092C8CDF8C2EA63496300 -552;FSX Steam Edition;FreeTrack20;V160;;;3852;02287F45F0FFBEF6102900 -147;FTAlpha;FreeTrack20;V160;;;20270;00936C69677F1D772AA900 149;Full Out;FreeTrack20;V160;;;1701;009527D5047C31A0375800 150;Future Pinball;FreeTrack20;V160;V;V4Friend;13101;00969343487E42B541AA00 +159;GRID;FreeTrack20;V160;V;LeapoEclipse ;8105;009FD8175F8D1D7C0D3800 +160;GSE Power Plant Simulation;FreeTrack20;V160;;;20044;00A0432C28C217BEF93300 +161;GT Legends;FreeTrack20;V160;V;TrickyDee ;3902;00A116BC08020581CA8200 +162;GTR;FreeTrack20;V160;;;3901;00A2FD6BFE39A881B85B00 +163;GTR2 EVO;FreeTrack20;V160;V;zild1221 ;0;00A34B0FC37B2198F96300 151;Game VR;FreeTrack20;V160;;;20325;009756BA018030B0355500 152;GameLab;FreeTrack20;V160;;;20555;00985485D891DB23092200 472;Games Farm;FreeTrack20;V160;;;3250;01D875C0981E627E5C7600 @@ -202,38 +205,34 @@ No;Game Name;Game protocol;Supported since;Verified;By;INTERNATIONAL_ID;FTN_ID 156;Gothic 3;FreeTrack20;V160;;;14401;009C37971697B36AD32A00 157;Grand Prix Legends;FreeTrack20;V160;;;6701;009D521358D3D933B96E01 158;Grand Theft Auto: San Andreas;FreeTrack20;V160;;;7808;009E5F3D95777D3BA23700 -159;GRID;FreeTrack20;V160;V;LeapoEclipse ;8105;009FD8175F8D1D7C0D3800 -160;GSE Power Plant Simulation;FreeTrack20;V160;;;20044;00A0432C28C217BEF93300 -161;GT Legends;FreeTrack20;V160;V;TrickyDee ;3902;00A116BC08020581CA8200 -162;GTR;FreeTrack20;V160;;;3901;00A2FD6BFE39A881B85B00 -163;GTR2 EVO;FreeTrack20;V160;V;zild1221 ;0;00A34B0FC37B2198F96300 164;Gun Commander;FreeTrack20;V160;;;2675;00A4E2D1D77E319FEE8600 520;H1Z1;FreeTrack20;V170;;;6004;1774F090B1BA9E782D0800 +169;HAWX;FreeTrack20;V160;V;EmBeES ;0;00A9D615A9C8B088717000 +171;HOBI;FreeTrack20;V160;;;20335;00ABB253777F1779168900 +173;HPC;FreeTrack20;V160;;;20600;00AD0FC9FF8D0A7CEF9500 +174;HPG Tracking;FreeTrack20;V160;;;20255;00AE0288A1879D98930900 +175;HTW;FreeTrack20;V160;;;20630;00AF26F797911901C22C00 165;Half Life 2;FreeTrack20;V160;;;7806;00A556BA018130AF365500 166;Halo;FreeTrack20;V160;;;3801;00A656BA018130AF3F9C00 -502;hapTEL;FreeTrack20;V160;;;20805;01F63ADE510A20446B6A00 167;Hardware Control Simulator Railway Electronics;FreeTrack20;V160;;;20705;00A7F3E85B1A8930B42F00 168;Harrier Attack II;FreeTrack20;V160;;;1175;00A8F2F27A57D20A940900 499;Harry's Hard Choices Interactive;FreeTrack20;V160;;;20800;01F33A21BAE3DB6D48A000 -169;HAWX;FreeTrack20;V160;V;EmBeES ;0;00A9D615A9C8B088717000 170;Herissons (Paris France);FreeTrack20;V160;;;20001;00AAEA1CBED8C20B430B00 -523;hiCRANE2;FreeTrack20;V160;;;20835;020BA8FC8C7DFFA1381A00 -171;HOBI;FreeTrack20;V160;;;20335;00ABB253777F1779168900 172;HoverAssault;FreeTrack20;V160;;;5303;00AC521358E3AA832A4000 -173;HPC;FreeTrack20;V160;;;20600;00AD0FC9FF8D0A7CEF9500 -174;HPG Tracking;FreeTrack20;V160;;;20255;00AE0288A1879D98930900 -175;HTW;FreeTrack20;V160;;;20630;00AF26F797911901C22C00 176;Huawei Software;FreeTrack20;V160;;;20660;00B04655E8030A733AB300 177;HueSpace;FreeTrack20;V160;;;20510;00B1231517C44960FB6300 178;Hyper Vision;FreeTrack20;V160;;;15101;00B2DB242B657D43B32300 -179;iAmFootball;FreeTrack20;V160;;;1250;00B3B59DEFAAAFDB301A00 -180;id Research;FreeTrack20;V170;;;2950;00B4E723B873D7FC87D700 181;IESA;FreeTrack20;V160;;;20037;00B5157D78D0E840AD7100 182;IL-2 Cliffs of Dover;FreeTrack20;V160;V;V4Friend;0;00B6282282095F00521000 183;IL-2 Forgotten Battles ACE Pacific Fighters;FreeTrack20;V160;V;Glenn;1001;00B722FD79137100621100 484;IL-2 Sturmovik: Battle of Stalingrad;FreeTrack20;V170;;;1008;03F04D5368D1FD2DF2AE00 -184;Illumina;FreeTrack20;V160;;;1350;00B8054E8B39A33DB02400 185;ILP;FreeTrack20;V160;;;20310;00B9F07957801789C9A600 +193;IREQ Robotic Camera Control;FreeTrack20;V160;;;20027;00C10448E0E8618521EB00 +536;ISAMM;FreeTrack20;V160;;;20860;0218303730165E681DB000 +194;ISIC;FreeTrack20;V160;;;20680;00C2DEE3582F8F217E0B00 +506;ITCL;FreeTrack20;V160;;;20820;01FAD19412681DC9CC6100 +195;IVD Online;FreeTrack20;V160;;;20535;00C390B57E1D7DDD883D00 +184;Illumina;FreeTrack20;V160;;;1350;00B8054E8B39A33DB02400 186;Imagine 3D ATC Tower Simulation;FreeTrack20;V160;;;20032;00BAEF7A8F4B8812B95300 187;In Touch Technologies Inc.;FreeTrack20;V160;;;20006;00BB84817A3A5124B23D00 188;Inglobe;FreeTrack20;V160;;;20360;00BCE7A7FAA27B2DA82700 @@ -242,19 +241,13 @@ No;Game Name;Game protocol;Supported since;Verified;By;INTERNATIONAL_ID;FTN_ID 575;Interstellar Rift;FreeTrack20;V160;;;4550;023FF83230A370CBC6AC00 191;Intific;FreeTrack20;V160;;;20655;00BF2BCA747F2AA8309D00 566;Into the Dungeon;FreeTrack20;V160;;;4375;0236B346990ACCFC047A00 -192;iRacing;FreeTrack20;V160;V;vn88holden ;14101;00C0103AF1AA730A236900 -193;IREQ Robotic Camera Control;FreeTrack20;V160;;;20027;00C10448E0E8618521EB00 -536;ISAMM;FreeTrack20;V160;;;20860;0218303730165E681DB000 -194;ISIC;FreeTrack20;V160;;;20680;00C2DEE3582F8F217E0B00 -506;ITCL;FreeTrack20;V160;;;20820;01FAD19412681DC9CC6100 -195;IVD Online;FreeTrack20;V160;;;20535;00C390B57E1D7DDD883D00 196;J.J. Keller and Associates;FreeTrack20;V160;;;20002;00C4E482F57FE77CF46300 +199;JC Demo;FreeTrack20;V160;;;20470;00C70AC67B0A630D9B3900 +202;JFIST;FreeTrack20;V160;;;20560;00CAC932727C0F8D208600 197;Janes F18;FreeTrack20;V160;;;9001;00C55F3D9577802AAF2E00 198;Javal Ent.;FreeTrack20;V160;;;2650;00C622FD7A28BA2FAEEA00 -199;JC Demo;FreeTrack20;V160;;;20470;00C70AC67B0A630D9B3900 200;Jet Thunder;FreeTrack20;V160;;;4501;00C82100801FA4EA9A3500 201;Jetfighter V;FreeTrack20;V160;;;2501;00C9F52E42217B33A63200 -202;JFIST;FreeTrack20;V160;;;20560;00CAC932727C0F8D208600 203;John Deere Vehicle Simulator;FreeTrack20;V160;;;20175;00CB29DFA8D3FA92A66000 204;Jump to Lightspeed;FreeTrack20;V160;;;6001;00CCC166C8D3FA12E52400 205;Jumpgate;FreeTrack20;V160;;;15001;00CD26F797B32A63E99200 @@ -263,70 +256,69 @@ No;Game Name;Game protocol;Supported since;Verified;By;INTERNATIONAL_ID;FTN_ID 476;KAI FLight Simulator;FreeTrack20;V160;;;20725;01DCC522132A5C01EDE500 560;Keita Head Tracking;FreeTrack20;V160;;;20385;02307E33478667072B0800 208;Key Macro View;FreeTrack20;V160;;;12001;00D016BC08431B1EF90100 -209;kiwi.vg;FreeTrack20;V160;;;20395;00D1409A430AB33633E900 521;Kongsberg GlobalSim;FreeTrack20;V160;;;20825;0209B2C573D990BF764700 210;L-3;FreeTrack20;V160;;;20465;00D2F885EFA8DE67878B00 211;L-3 Communications;FreeTrack20;V160;;;20051;00D3D6E585F92F765E7800 522;LG Electronics;FreeTrack20;V160;;;20830;020A3678F5833D513DCA00 +577;Limb;FreeTrack20;V160;;;4650;0241D999E2E247B1DFDD00 212;Lionhead MGS Game Research;FreeTrack20;V160;;;15301;00D4C1BBF9227B238AE200 213;Live For Speed;FreeTrack20;V160;V;zild1221 ;7101;00D528228526A833521300 214;Live for Speed S2;FreeTrack20;V160;;;11601;00D63752FBC8235B923500 218;Lock-On: Modern Air Combat;FreeTrack20;V160;;;1002;00DAAC156D903C993B6200 +217;LockOn: Flaming Cliffs 2;FreeTrack20;V170;V;EmBeES ;1005;00D9AFB0D279F3A6F72200 215;Lockheed Martin Littoral Combat Ship simulator;FreeTrack20;V160;;;20025;00D771ED5E802A9827A000 216;Lockheed Martin Prepar3D;SimConnect;V130;V;elelbe ;0;00D8D615A9C8F36932AA00 -217;LockOn: Flaming Cliffs 2;FreeTrack20;V170;V;EmBeES ;1005;00D9AFB0D279F3A6F72200 219;London NHS;FreeTrack20;V160;;;20640;00DB2E2023832BA123A100 220;Lore (Dark Horizons);FreeTrack20;V160;;;5302;00DCF478D27833DB62D500 221;Love;FreeTrack20;V160;;;3125;00DD71ED5E802AAB214800 222;Lucid Engine;FreeTrack20;V160;;;10501;00DE71ED5E803098259C00 514;M4 Tank Brigade;FreeTrack20;V160;;;1308;02024ED5A3A26741604300 223;M4 Tank Platoon;FreeTrack20;V160;;;1306;00DFDCC441A8E036320900 -224;Mach 1;FreeTrack20;V160;;;2575;00E0231518130942466000 549;MAG WIP;FreeTrack20;V160;;;4152;02252A1C82FD29D9FFB900 +244;MKMapper Keymapper;FreeTrack20;V160;;;2201;00F487801A8E14822EA200 +250;MS World Tour Kart 2004;FreeTrack20;V160;;;6601;00FA9F819CA27F10591600 +251;MSN Virtual Earth;FreeTrack20;V160;;;2309;00FBF47CC37842091DC900 +224;Mach 1;FreeTrack20;V160;;;2575;00E0231518130942466000 225;ManuVAR;FreeTrack20;V160;;;20455;00E153FE1E901CB0448800 226;MaqSIM4;FreeTrack20;V160;;;20026;00E28F54A207D29B611700 +233;MeVEA;FreeTrack20;V160;;;2250;00E9D24C3F933289028700 227;Mech Tactical Sim;FreeTrack20;V160;;;9501;00E3F3E85B1A8E34A53300 -228;Mechwarrior Online;FreeTrack20;V170;;;3025;00E414954226DB5D8CE200 516;MechWarrior Online;FreeTrack20;V170;;;3026;0BD2E0DCBC723836CD2400 +228;Mechwarrior Online;FreeTrack20;V170;;;3025;00E414954226DB5D8CE200 229;Medical Image Visualization;FreeTrack20;V160;;;20295;00E59343488532A5359B00 230;Meggitt Defense Systems;FreeTrack20;V160;;;20045;00E6926ED9122AB22AF300 231;MetaVR;FreeTrack20;V160;;;20545;00E7C5BEE48120A8308800 232;Meteoroid Maze;FreeTrack20;V160;;;13003;00E8F079578430AD2EB200 -233;MeVEA;FreeTrack20;V160;;;2250;00E9D24C3F933289028700 234;Micro Flight;FreeTrack20;V160;V;V4Friend;5101;00EABA89D078439932EA00 235;Microsoft ESP;FreeTrack20;V160;;;2306;00EB0AC67E30A63BA53F00 -236;Microsoft Flight;FreeTrack20;V170;V;V4Friend;2307;00ECAFBC54959539C51500 -237;Microsoft Flight Simulator 3;FreeTrack20;V160;V;V4Friend;0;00ED5909437D36963EA810 238;Microsoft FS2002/2004;FSUIPC;V130;V;V4Friend;0;00EE44958F34992CB43A00 239;Microsoft FSX;SimConnect;V130;V;V4Friend;0;00EFF478D278437A73AA00 +236;Microsoft Flight;FreeTrack20;V170;V;V4Friend;2307;00ECAFBC54959539C51500 +237;Microsoft Flight Simulator 3;FreeTrack20;V160;V;V4Friend;0;00ED5909437D36963EA810 240;Microsoft Train Simulator;FreeTrack20;V160;;;7805;00F00449225A439A13FB00 494;MiddleVR;FreeTrack20;V160;;;20785;01EE1227DF43CA90C26100 241;Mig Alley;FreeTrack20;V160;;;1501;00F17686E5A83289CDA700 242;Mimik Vehicle Simulator;FreeTrack20;V160;;;20585;00F2AB1D58A8E35A531A00 243;Miner Wars;FreeTrack20;V160;;;2550;00F3C5BEE48124A234A400 -244;MKMapper Keymapper;FreeTrack20;V160;;;2201;00F487801A8E14822EA200 245;ModelSim;FreeTrack20;V160;;;20540;00F544958F3A9A1FB11A00 246;Morgan State University;FreeTrack20;V160;;;20010;00F65909437D3CA5339A00 247;Motor Company;FreeTrack20;V160;;;11501;00F70288F37A629A7DD700 248;Motorsport Simulators;FreeTrack20;V160;;;4201;00F8F52E42217E3DA63B00 249;Mouse Emulation;FreeTrack20;V160;;;8501;00F9950F9A8E29B93A9700 -250;MS World Tour Kart 2004;FreeTrack20;V160;;;6601;00FA9F819CA27F10591600 -251;MSN Virtual Earth;FreeTrack20;V160;;;2309;00FBF47CC37842091DC900 -252;mTBI Balance;FreeTrack20;V160;;;20420;00FC72456F9E0E78145800 253;NASA Crew Exploration Vehicle;FreeTrack20;V160;;;20017;00FD028900985FA5501A00 254;NASCAR Heat;FreeTrack20;V160;;;2602;00FE311857E10880B84100 255;NASCAR Racing 2003 season;FreeTrack20;V160;;;7804;00FFDE661F6D920B87FC10 256;NASCAR SimRacing;FreeTrack20;V160;;;6201;01004098708870D761A500 +262;NVH Sound Simulator;FreeTrack20;V160;;;20695;010655A2AA93158DDE9500 535;Navi Trainer Professional;FreeTrack20;V160;;;20855;0217C0E0793305EE8D5200 257;NecroVisioN;FreeTrack20;V160;;;15601;0101621E77F2EA830A8100 258;NetKar Pro;FreeTrack20;V160;V;sosna1983 ;10901;01028C3958334A5169A300 259;Nitro Stunt Racing;FreeTrack20;V160;;;13901;0103C0AF9428B82DA5ED00 260;North Eastern University;FreeTrack20;V160;;;20003;0104A2AE4823BB7449DE00 261;Novint;FreeTrack20;V160;;;2725;01051C76F8137B823A4300 -262;NVH Sound Simulator;FreeTrack20;V160;;;20695;010655A2AA93158DDE9500 479;OHJCH;FreeTrack20;V160;;;20740;01DF992E6C0DA43A703600 -551;Omni-Directional Movement;FreeTrack20;V160;;;20870;0227088B794053785DBE00 263;OMSI Bus Simulator;FreeTrack20;V160;V;Thiago ;2225;0107F47CC37861A9606600 +551;Omni-Directional Movement;FreeTrack20;V160;;;20870;0227088B794053785DBE00 264;Onadime - Realtime Animation;FreeTrack20;V160;;;20049;010853FE1E9229A3339B00 265;Open Falcon 4.5;FreeTrack20;V160;V;muplex ;0;0109B1C664832D9B385500 266;Operation Air Assault 2;FreeTrack20;V160;;;5401;010ABB5BF72C9238973B00 @@ -340,6 +332,7 @@ No;Game Name;Game protocol;Supported since;Verified;By;INTERNATIONAL_ID;FTN_ID 274;Oryx Vehicle Simulators;FreeTrack20;V160;;;20028;0112C8CDF952EBA4763100 275;Outer Conflict: Frontiers;FreeTrack20;V160;;;1900;01136C6967883EAA23AB00 276;Over Flanders Fields;FreeTrack20;V160;V;Summelar ;2325;0114A59E68873E9B315210 +545;PULSAR: Lost Colony;FreeTrack20;V160;;;4075;02214BC732C034C3620400 277;PanoPro;FreeTrack20;V160;;;20525;0115B6C61428231A23E900 278;Paraworld;FreeTrack20;V160;;;14501;0116656DD6832BB62EB000 279;Phoenix R/C;FreeTrack20;V160;;;3075;0117B6C61428238A334B00 @@ -355,7 +348,6 @@ No;Game Name;Game protocol;Supported since;Verified;By;INTERNATIONAL_ID;FTN_ID 286;Project Torque (Invictus);FreeTrack20;V160;;;4802;011E612F28540B52797100 287;Project X;FreeTrack20;V160;;;20022;011FE9D85E4842DA439900 529;Puegeot PSA Simulator;FreeTrack20;V160;;;20840;021127A7344E7C044E9500 -545;PULSAR: Lost Colony;FreeTrack20;V160;;;4075;02214BC732C034C3620400 553;QSTP;FreeTrack20;V160;;;20875;0229A3C108BE55FFF2BC00 288;Quanser;FreeTrack20;V160;;;20435;0120950F9A922FA535A500 289;QuantaDyn;FreeTrack20;V160;;;20575;012199BB5C9433A739B600 @@ -366,30 +358,31 @@ No;Game Name;Game protocol;Supported since;Verified;By;INTERNATIONAL_ID;FTN_ID 293;R.U.D.O. Tools;FreeTrack20;V160;;;20039;0125612F287FB9BEA76E00 294;RACE (the WTCC game);FreeTrack20;V160;;;3904;01263C2C1C94FA86146300 295;RACE 07 RACE GTR 2;FreeTrack20;V160;V;zild1221 TrickyDee ;3903;0127C0AF9800870056FD00 +574;RCPlugin;FreeTrack20;V160;;;23090;023E0448BCFD48E0149D00 +312;REFLEX XTR;FreeTrack20;V160;;;2150;0138054E94127D14881300 +492;RITS;FreeTrack20;V160;;;20775;01ECEE745B83DD3A0DBE00 +327;ROV Sim;FreeTrack20;V160;;;20530;0147FA04BD27891D9ADD00 +329;RSD Demo;FreeTrack20;V160;;;2050;0149BF8C4EAA5871A85D00 +330;RTMS Crane Sim;FreeTrack20;V160;;;20400;014AC93272841D91205200 +331;RTT DeltaGen Plugin;FreeTrack20;V160;;;20195;014B90B5871B8DDD7D3400 296;RaceOn;FreeTrack20;V160;V;zild1221 ;0;0128621E7832AA82388200 +490;RaceRoom Racing Experience;FreeTrack20;V160;;;3905;01EA9124F663AF03BBC500 297;Racer;FreeTrack20;V160;;;2401;01296D2D103862E932EA00 298;Racer S;FreeTrack20;V160;;;20030;012AEA1CBED961CA52CB00 -490;RaceRoom Racing Experience;FreeTrack20;V160;;;3905;01EA9124F663AF03BBC500 299;Rail Simulator 1;FreeTrack20;V160;;;1550;012BB253778929A0395900 -300;Railway Work Simulator;FreeTrack20;V160;;;20225;012C91D998B1E9933B9100 301;RailWorks 2;FreeTrack20;V160;;;2750;012D3919C4972D9D299000 507;RailWorks 5 (TS2014);FreeTrack20;V160;;;1551;01FB8B5232CB1502C95A00 +300;Railway Work Simulator;FreeTrack20;V160;;;20225;012C91D998B1E9933B9100 302;Raydon Driving Simulator;FreeTrack20;V160;;;3701;012E5485D941DBE2FB5300 -574;RCPlugin;FreeTrack20;V160;;;23090;023E0448BCFD48E0149D00 304;Real Time Visual;FreeTrack20;V160;;;9901;0130B1C664862297365500 305;RealFlight;FreeTrack20;V160;;;4001;0131AC6E87892E993A8B00 -306;Reality Manager;FreeTrack20;V160;;;20046;0132DB242B65872FA42A00 307;RealWorld;FreeTrack20;V160;;;20215;0133B59DEFA9322A727800 +306;Reality Manager;FreeTrack20;V160;;;20046;0132DB242B65872FA42A00 308;Red Baron 3D;FreeTrack20;V160;;;1125;0134C6371D96349CEB7A00 309;Red Orchestra: Heroes of Stalingrad;FreeTrack20;V170;;;12602;013521F9121056CD997300 310;Red Orchestra: Ostfront;FreeTrack20;V170;;;12601;01369A9A2BE97252BB9000 311;Redline Monitor;FreeTrack20;V160;;;20210;01373752FBC8831A72AA00 -312;REFLEX XTR;FreeTrack20;V160;;;2150;0138054E94127D14881300 313;Remote Presence;FreeTrack20;V160;;;20710;01399BC3BDA93229D2BB00 -314;rFactor;FreeTrack20;V160;V;V4Friend;7401;013AEF7A8F4B8AA0495200 -315;rFactor Pro;FreeTrack20;V170;;;7403;013B175198D74BE8E89600 -316;rFactor2;FreeTrack20;V170;;;7402;013CBFF3A86D34DA24C000 -533;rFPro;FreeTrack20;V170;;;7404;1CEC6BE26009B31DE7BC00 317;Richard Burns Rally;FreeTrack20;V160;V;zild1221;3401;013D42868B339A31A73C10 318;RidingStar;FreeTrack20;V160;;;1475;013E3919C497359826A700 544;Rift's Cave;FreeTrack20;V160;;;4050;02209C681EAD3B06D15A00 @@ -398,41 +391,40 @@ No;Game Name;Game protocol;Supported since;Verified;By;INTERNATIONAL_ID;FTN_ID 321;Rise of Flight;FreeTrack20;V160;V;Seborgarsen ;11401;0141AA71218335A51F5100 322;Rise: The Vieneo Province;FreeTrack20;V160;;;6301;0142DEE3582F9837A82D00 323;Rising Conflicts;FreeTrack20;V160;;;12101;014384818335A439B12F00 -492;RITS;FreeTrack20;V160;;;20775;01ECEE745B83DD3A0DBE00 +530;RoRo Simulator;FreeTrack20;V160;;;20845;02123A5F2F98EF4D0F0700 324;Road Legends;FreeTrack20;V160;;;1876;0144379716986369A2E600 325;Rogue Space;FreeTrack20;V160;;;3050;014588F5872C9C30ABE900 326;Rogue Warrior;FreeTrack20;V160;;;14202;0146432C2973D9D45A8E00 -530;RoRo Simulator;FreeTrack20;V160;;;20845;02123A5F2F98EF4D0F0700 -327;ROV Sim;FreeTrack20;V160;;;20530;0147FA04BD27891D9ADD00 328;Rowan's Battle Of Britain;FreeTrack20;V160;;;1502;014821008829A72CB4F300 -329;RSD Demo;FreeTrack20;V160;;;2050;0149BF8C4EAA5871A85D00 -330;RTMS Crane Sim;FreeTrack20;V160;;;20400;014AC93272841D91205200 -331;RTT DeltaGen Plugin;FreeTrack20;V160;;;20195;014B90B5871B8DDD7D3400 540;Rust;FreeTrack20;V170;;;3950;0F6EF7CEF7DFA93405D700 +335;SCANeR Studio Plugin;FreeTrack20;V160;;;20445;014FA2AE4870F861E9A100 +336;SEGA Demo;FreeTrack20;V160;;;2075;015016BC08C117F1163000 +338;SFSPC;FreeTrack20;V160;;;2801;0152F885EFA9400981B700 +343;SIA Games;FreeTrack20;V160;;;20015;0157926ED970685DA8D200 +358;SRI;FreeTrack20;V160;;;20620;01663FD0FC9D8B218D8100 +495;STRAFT;FreeTrack20;V160;;;3375;01EF1329E014ADF98D6B00 +367;STS Driving Simulator;FreeTrack20;V160;;;20300;016FA59E688B1C89DE7600 +371;SWRI Demo;FreeTrack20;V160;;;20230;01730AC6841E9512561000 511;Sail;FreeTrack20;V160;;;3575;01FF2916D764159099F800 332;Sail Simulator 5;FreeTrack20;V160;;;1975;014CE2D1D78A1D9A3B6300 333;Sailors of the Sky;FreeTrack20;V160;;;10201;014D17BE02961FAF3AB100 334;Santa Cruz Watermill;FreeTrack20;V160;;;20290;014E88F5881EA32FA7E900 -335;SCANeR Studio Plugin;FreeTrack20;V160;;;20445;014FA2AE4870F861E9A100 -336;SEGA Demo;FreeTrack20;V160;;;2075;015016BC08C117F1163000 337;Seven-G;FreeTrack20;V160;;;2350;01510F00F49635B822A200 -338;SFSPC;FreeTrack20;V160;;;2801;0152F885EFA9400981B700 +554;ShiVa;FreeTrack20;V160;;;4225;022AA2A7DC2F7222696C00 339;Ship Simulator 2006;FreeTrack20;V160;;;5002;015329DFA9638AA2C66100 340;Ship Simulator 2008;FreeTrack20;V160;V;djj3ff ;5003;01545213599339B3D52100 341;Shiphandling Simulator;FreeTrack20;V160;;;20570;01553FD0FC9D8B37AD3700 -554;ShiVa;FreeTrack20;V160;;;4225;022AA2A7DC2F7222696C00 342;Shooting Simulator;FreeTrack20;V160;;;20047;0156F2F27A58827A63DA00 -343;SIA Games;FreeTrack20;V160;;;20015;0157926ED970685DA8D200 344;Silent Wings;FreeTrack20;V160;;;8701;0158D615A9C96309C24A00 345;SilverHat;FreeTrack20;V160;;;12401;0159D8175F99349F3F9600 -346;Simax Simulator;FreeTrack20;V160;;;20021;015AAC156D9736A331AD00 -347;Simball 4D;FreeTrack20;V160;;;20315;015BD6E585F99349F2AA00 -348;Simbionix;FreeTrack20;V160;;;20485;015CE7A7FAA28528AE1D00 518;SimCraft;FreeTrack20;V160;;;3650;02065BA013963203CB1900 349;SimCreator;FreeTrack20;V160;;;20520;015D3752FBC8935B001A00 -350;Simlog Personal Simulator;FreeTrack20;V160;;;20635;015E42868C33A435B53100 351;SimQuest immersion system;FreeTrack20;V160;;;20023;015F6C69678C32A30FAE00 352;SimSol;FreeTrack20;V160;;;20034;01602315187389E0FB5300 +346;Simax Simulator;FreeTrack20;V160;;;20021;015AAC156D9736A331AD00 +347;Simball 4D;FreeTrack20;V160;;;20315;015BD6E585F99349F2AA00 +348;Simbionix;FreeTrack20;V160;;;20485;015CE7A7FAA28528AE1D00 +350;Simlog Personal Simulator;FreeTrack20;V160;;;20635;015E42868C33A435B53100 491;Simumak;FreeTrack20;V160;;;20770;01EB119629980784DCE600 510;Sir You Are Being Hunted;FreeTrack20;V160;;;3550;01FEDAB345FA104ED4A100 353;Sirocco Racing;FreeTrack20;V160;;;5801;01612BCA748925A6369A00 @@ -442,7 +434,6 @@ No;Game Name;Game protocol;Supported since;Verified;By;INTERNATIONAL_ID;FTN_ID 356;Source Engine (Half-Life 2);FreeTrack20;V160;;;12502;0164E482F58829A739A600 357;Space Shuttle Mission 2007;FreeTrack20;V160;V;purewhitewings ;1225;0165662B03863D912F9700 517;Spaze;FreeTrack20;V160;;;3625;020573F9D3ED8C43B8DC00 -358;SRI;FreeTrack20;V160;;;20620;01663FD0FC9D8B218D8100 359;Stanford University;FreeTrack20;V160;;;20004;0167CE35BAF9933A62AA00 500;Star Citizen;FreeTrack20;V170;;;3450;0D7AF4CE4E343EC6B4A200 360;Starshatter;FreeTrack20;V160;;;6401;0168F079578A3F9A3BB600 @@ -452,38 +443,33 @@ No;Game Name;Game protocol;Supported since;Verified;By;INTERNATIONAL_ID;FTN_ID 565;Steel Beasts Professional;FreeTrack20;V160;;;4350;02356C64A9AFBB37E56E00 364;Stoked Rider;FreeTrack20;V160;;;14701;016CC166C963EA32997300 365;Storm of War: the Battle of Britain;FreeTrack20;V170;;;11001;016D8F54A68B71F25D0200 -495;STRAFT;FreeTrack20;V160;;;3375;01EF1329E014ADF98D6B00 366;Stride;FreeTrack20;V170;;;2310;016EC784B21E4B21984400 541;Strike Suit Zero;FreeTrack20;V170;;;3975;0F87E77F3BD3DB8821A200 -367;STS Driving Simulator;FreeTrack20;V160;;;20300;016FA59E688B1C89DE7600 368;Sunaerosys;FreeTrack20;V160;;;20475;01700449831AF28973EB00 -369;Superkarting;FreeTrack20;V160;;;14903;0171DE661F6D973FA41F00 370;SuperX Research;FreeTrack20;V160;;;15401;0172BA89D078A45A021A00 -371;SWRI Demo;FreeTrack20;V160;;;20230;01730AC6841E9512561000 +369;Superkarting;FreeTrack20;V160;;;14903;0171DE661F6D973FA41F00 372;Syncon Robot Control;FreeTrack20;V160;;;20415;0174C1BBF9937B12DB5200 373;Synergy Simulation;FreeTrack20;V160;;;20595;0175926ED9736B220B8200 374;T and TS Corp.;FreeTrack20;V160;;;20005;017617BE0297DDA73CA600 +379;TD Demo;FreeTrack20;V160;;;1925;017BC5BEE488FE54139700 +389;TIRF4;FreeTrack20;V160;;;2203;0185311858418870E77000 +390;TNO;FreeTrack20;V160;;;20285;01861AAF6870A853D64900 +399;TPL Testing;FreeTrack20;V160;;;20260;018F849F9A2083DC8C2C00 539;Tacview;FreeTrack20;V160;;;20865;021B1F0CFB651B91405C00 375;Take On Helicopters;FreeTrack20;V170;;;7504;0177513CB40C0623B96A00 376;Target: Korea;FreeTrack20;V160;;;1201;0178F52E4221852FA43300 377;Target: Rabaul;FreeTrack20;V160;;;1202;0179E9D85E4881CA736900 378;Targeting Demo;FreeTrack20;V160;;;13002;017AAB1D58A952DAA2F900 -379;TD Demo;FreeTrack20;V160;;;1925;017BC5BEE488FE54139700 489;TeachLive;FreeTrack20;V160;;;20765;01E905245B5AC5484FC100 380;Telepresence;FreeTrack20;V160;;;20450;017CF478D278B33B02DA00 381;Tenstar Simulator;FreeTrack20;V160;;;20605;017D318F88A2EA62DBA200 382;Test Drive Unlimited;FreeTrack20;V160;;;13201;017E6F2699559730A84000 509;Tetrahedral;FreeTrack20;V160;;;3525;01FDCFF1C56D6F757E8200 +576;The Battle of Sol;FreeTrack20;V160;;;4575;02408ED99EB5DF5D79A800 501;The Crew;FreeTrack20;V170;;;1009;03F1F534E94F4834D9B100 488;The Gallery;FreeTrack20;V160;;;3350;01E8CE152EDE5FFD267700 383;The Sky Gods;FreeTrack20;V170;;;1525;017FDFF782DCCEEA27C200 -384;theHunter;FreeTrack20;V170;;;2375;0180BFF3A86D34DA24C000 -385;thriXXX HII 3D;FreeTrack20;V160;;;13403;0181FA04BD27AB36B62700 -386;thriXXX Jenna;FreeTrack20;V160;;;13401;01829F819CA2A625AB2800 387;ThriXXX Technology;FreeTrack20;V160;;;13402;0183F47CC378B35B526900 -388;tir2joy;FreeTrack20;V160;;;2202;018487801AB532A7FE9C00 -389;TIRF4;FreeTrack20;V160;;;2203;0185311858418870E77000 -390;TNO;FreeTrack20;V160;;;20285;01861AAF6870A853D64900 391;ToCA Race Driver 2;FreeTrack20;V160;;;8102;0187FFE9E886F286297910 392;Toca Race Driver 3;FreeTrack20;V160;;;8101;01884098D36972B551A900 393;Tom Clancy's H.A.W.X.;FreeTrack20;V170;V;EmBeES ;1004;0189AA4D48E85966FBAA00 @@ -492,8 +478,6 @@ No;Game Name;Game protocol;Supported since;Verified;By;INTERNATIONAL_ID;FTN_ID 396;Total War;FreeTrack20;V160;;;1375;018C72456F8529AA2CA400 397;Tower Crane Simulator;FreeTrack20;V160;;;20670;018D03FB9929B034A7D900 398;Tower I;FreeTrack20;V160;;;1325;018E662B03873CA731A400 -399;TPL Testing;FreeTrack20;V160;;;20260;018F849F9A2083DC8C2C00 -400;trackd;FreeTrack20;V160;;;20580;019053FE1EB72DA3329D00 401;TrackMapper2;FreeTrack20;V160;;;2175;0191CE35BAF9A31A61FA00 402;TrainMaster;FreeTrack20;V160;;;20042;01925C1FDE852D9925B400 403;Trainz;FreeTrack20;V160;;;4701;0193D1C9F2862C9630A100 @@ -501,6 +485,8 @@ No;Game Name;Game protocol;Supported since;Verified;By;INTERNATIONAL_ID;FTN_ID 405;Turismo Carretera;FreeTrack20;V160;;;15801;01956F2699559740A73500 406;UK Rally Champion;FreeTrack20;V160;;;5701;019679EC0E28B196522A00 407;ULAN;FreeTrack20;V160;;;20645;01974ADE68E16780D97A00 +422;UQO;FreeTrack20;V160;;;23085;01A67C822099A187FE3600 +423;UVEG Machinery Simulator;FreeTrack20;V160;;;20024;01A73118585257A0F63100 473;Underwater Navigation;FreeTrack20;V160;;;20715;01D9FE2B94FB03772DE200 408;Unity 3D Plugin;FreeTrack20;V160;;;20430;0198D24C3F9B3B9C31BF00 525;Unity 64-bit;FreeTrack20;V160;;;3750;020DC8AB18AF3539FA5200 @@ -518,17 +504,20 @@ No;Game Name;Game protocol;Supported since;Verified;By;INTERNATIONAL_ID;FTN_ID 419;Untitled Simbin;FreeTrack20;V160;;;3902;01A36C69678E37AA27AD00 420;Untitled WorkShield;FreeTrack20;V160;;;4601;01A442868E38AB32BA3600 421;Untitled ZootFly;FreeTrack20;V160;;;12701;01A5348B1863AA527A6300 -422;UQO;FreeTrack20;V160;;;23085;01A67C822099A187FE3600 -423;UVEG Machinery Simulator;FreeTrack20;V160;;;20024;01A73118585257A0F63100 424;VAR;FreeTrack20;V160;;;20460;01A8950F9A97FA96FD2E00 425;VBS2;FreeTrack20;V160;;;7501;01A999BB5C990099FCBF00 485;VBS2 2.0;FreeTrack20;V170;;;7505;1D51EB3616B3A44F05B900 527;VCORP RBR2 MOD;FreeTrack20;V160;;;3825;020FEE9EA847F2ADB45800 +429;VIRTools Engine;FreeTrack20;V160;;;10801;01AD1AAF68905881EB5300 +564;VR Truck Simulator;FreeTrack20;V160;;;4325;02344CAEE1BC9E243D9F00 +477;VRPlayer;FreeTrack20;V160;;;20730;01DD6787E57245201D5000 +439;VT08;FreeTrack20;V160;;;1275;01B7B78B06EC9912750200 +440;VVVV Plugin;FreeTrack20;V160;;;20075;01B8B1C6648A138C205500 +441;VW Testing;FreeTrack20;V160;;;20275;01B9AC6E878D205822AA00 426;Vehicle Simulator (Quality Simulations);FreeTrack20;V160;;;5102;01AA0FC9FF9B1FA134A900 478;Vehicle Simulator Direction;FreeTrack20;V160;;;20735;01DEB88CF58E570F1CEF00 427;Vestibular Ocular Reflex;FreeTrack20;V160;;;20008;01AB3919C49B31A731A200 428;Viper Arena;FreeTrack20;V160;;;3501;01AC6F2699559934A53100 -429;VIRTools Engine;FreeTrack20;V160;;;10801;01AD1AAF68905881EB5300 430;Virtools Plugin;FreeTrack20;V160;;;20200;01AE03FB9B23AB43A42900 431;Virtual Driving;FreeTrack20;V160;;;20245;01AF99BB5C9927B83FB700 432;Virtual Heroes;FreeTrack20;V160;;;20375;01B0621E78732B732AE200 @@ -537,18 +526,14 @@ No;Game Name;Game protocol;Supported since;Verified;By;INTERNATIONAL_ID;FTN_ID 435;Virtual Shopper;FreeTrack20;V160;;;20610;01B3B78B06EC9927B73E00 436;Virtual Supermarket;FreeTrack20;V160;;;20280;01B4849F9C39A931AD2800 496;VirtualiTeach;FreeTrack20;V160;;;20790;01F062AE1CAB33B52D0700 -480;Vizard;FreeTrack20;V160;;;20745;01E0C1F20A79D7C0561300 437;VizRD;FreeTrack20;V160;;;20031;01B55485D9825BF1D8AB00 +480;Vizard;FreeTrack20;V160;;;20745;01E0C1F20A79D7C0561300 438;Void War;FreeTrack20;V160;;;10001;01B65C1FDE872AA1206600 -564;VR Truck Simulator;FreeTrack20;V160;;;4325;02344CAEE1BC9E243D9F00 -477;VRPlayer;FreeTrack20;V160;;;20730;01DD6787E57245201D5000 -439;VT08;FreeTrack20;V160;;;1275;01B7B78B06EC9912750200 -440;VVVV Plugin;FreeTrack20;V160;;;20075;01B8B1C6648A138C205500 -441;VW Testing;FreeTrack20;V160;;;20275;01B9AC6E878D205822AA00 +445;WAVES;FreeTrack20;V160;;;20515;01BD05B38FFE89008B8B00 +453;WWII Battle Tanks: T-34 vs. Tiger;FreeTrack20;V160;;;11102;01C5432C29C257F1963100 442;Walkabout3d;FreeTrack20;V160;;;20125;01BA2822901E9E39932F00 443;Wallbusters;FreeTrack20;V160;;;1450;01BB88F58C1EA127A83F00 444;War Thunder;FreeTrack20;V160;;;0;01BC17BE029A1FB8ED9600 -445;WAVES;FreeTrack20;V160;;;20515;01BD05B38FFE89008B8B00 446;Welding Simulator;FreeTrack20;V160;;;2625;01BE348B188319D229B300 447;West Racing;FreeTrack20;V160;;;1801;01BF91D999022A33B62000 448;Whirlwind of Vietnam;FreeTrack20;V160;;;11101;01C0054E9935A03AAF3200 @@ -557,9 +542,8 @@ No;Game Name;Game protocol;Supported since;Verified;By;INTERNATIONAL_ID;FTN_ID 451;Wings of War;FreeTrack20;V160;;;7807;01C34B0FC38B36B42FB610 512;Wings: Over Flanders Fields;FreeTrack20;V160;;;2326;02008AE39AAA4624B33C00 570;Wingsuit Simulator;FreeTrack20;V160;;;4450;023A472FA37FCD7427D900 -543;World of Diving;FreeTrack20;V160;;;4025;021F27B7B28D5012E1B300 452;World Racing 2;FreeTrack20;V160;;;7201;01C41AAF68A2BA836AAE00 -453;WWII Battle Tanks: T-34 vs. Tiger;FreeTrack20;V160;;;11102;01C5432C29C257F1963100 +543;World of Diving;FreeTrack20;V160;;;4025;021F27B7B28D5012E1B300 454;X Motor Racing;FreeTrack20;V160;;;1150;01C669259690E98629A900 526;X-Camera;FreeTrack20;V160;;;3775;020E1C4055DE39CBC03D00 458;X-Cockpit for X-Plane;FreeTrack20;V160;;;2901;01CA1C76F8BF4852999300 @@ -571,6 +555,24 @@ No;Game Name;Game protocol;Supported since;Verified;By;INTERNATIONAL_ID;FTN_ID 456;X2: The Threat;FreeTrack20;V160;;;5501;01C81039EF980EC8D30900 457;X3: Albion Prelude and Reunion;FreeTrack20;V170;V;V4Friend;5502;01C97E101A708F8524E300 463;Xyphoid;FreeTrack20;V160;;;14301;01CF656DD68B43B435A800 -464;zedasoft F-35 Demo;FreeTrack20;V160;;;20041;01D02100B01F942CB93C00 493;ZKT;FreeTrack20;V160;;;20780;01ED2BAA723F3C097EE800 465;Zombie AA Research;FreeTrack20;V160;;;14201;01D1AA71218B3B9F1C9A00 +100;dSphere TBA;FreeTrack20;V160;;;2425;0064A2AE4981FB5389A300 +113;eSigma;FreeTrack20;V160;;;20700;0071950F9AA60DAD2E9F00 +502;hapTEL;FreeTrack20;V160;;;20805;01F63ADE510A20446B6A00 +523;hiCRANE2;FreeTrack20;V160;;;20835;020BA8FC8C7DFFA1381A00 +179;iAmFootball;FreeTrack20;V160;;;1250;00B3B59DEFAAAFDB301A00 +192;iRacing;FreeTrack20;V160;V;vn88holden ;14101;00C0103AF1AA730A236900 +180;id Research;FreeTrack20;V170;;;2950;00B4E723B873D7FC87D700 +209;kiwi.vg;FreeTrack20;V160;;;20395;00D1409A430AB33633E900 +252;mTBI Balance;FreeTrack20;V160;;;20420;00FC72456F9E0E78145800 +533;rFPro;FreeTrack20;V170;;;7404;1CEC6BE26009B31DE7BC00 +314;rFactor;FreeTrack20;V160;V;V4Friend;7401;013AEF7A8F4B8AA0495200 +315;rFactor Pro;FreeTrack20;V170;;;7403;013B175198D74BE8E89600 +316;rFactor2;FreeTrack20;V170;;;7402;013CBFF3A86D34DA24C000 +384;theHunter;FreeTrack20;V170;;;2375;0180BFF3A86D34DA24C000 +385;thriXXX HII 3D;FreeTrack20;V160;;;13403;0181FA04BD27AB36B62700 +386;thriXXX Jenna;FreeTrack20;V160;;;13401;01829F819CA2A625AB2800 +388;tir2joy;FreeTrack20;V160;;;2202;018487801AB532A7FE9C00 +400;trackd;FreeTrack20;V160;;;20580;019053FE1EB72DA3329D00 +464;zedasoft F-35 Demo;FreeTrack20;V160;;;20041;01D02100B01F942CB93C00 diff --git a/spline-widget/CMakeLists.txt b/spline-widget/CMakeLists.txt index 03706d91..651a7874 100644 --- a/spline-widget/CMakeLists.txt +++ b/spline-widget/CMakeLists.txt @@ -1 +1,2 @@ -opentrack_boilerplate(opentrack-spline-widget NO-LINKER-SCRIPT) +opentrack_boilerplate(opentrack-spline-widget NO-LINKER-SCRIPT NO-COMPAT LINKAGE) +target_link_libraries(opentrack-spline-widget opentrack-compat) diff --git a/spline-widget/functionconfig.cpp b/spline-widget/functionconfig.cpp index dcc9ca65..777b4f6f 100644 --- a/spline-widget/functionconfig.cpp +++ b/spline-widget/functionconfig.cpp @@ -62,7 +62,7 @@ float Map::getValueInternal(int x) { return ret * sign; } -static QPointF ensureInBounds(QList<QPointF> points, int i) { +static QPointF ensureInBounds(const QList<QPointF>& points, int i) { int siz = points.size(); if (siz == 0 || i < 0) return QPointF(0, 0); @@ -219,7 +219,11 @@ void Map::loadSettings(QSettings& settings, const QString& title) { void Map::saveSettings(QSettings& settings, const QString& title) { QMutexLocker foo(&_mutex); settings.beginGroup(QString("Curves-%1").arg(title)); - int max = cur.input.size(); + + if (cur.input.size() == 0) + cur.input.push_back(QPointF(max_x, max_y)); + + const int max = cur.input.size(); settings.setValue("point-count", max); for (int i = 0; i < max; i++) { diff --git a/spline-widget/functionconfig.h b/spline-widget/functionconfig.h index 3d2fc23c..145ee14e 100644 --- a/spline-widget/functionconfig.h +++ b/spline-widget/functionconfig.h @@ -18,7 +18,7 @@ #include <limits> #include "opentrack-compat/qcopyable-mutex.hpp" -#ifdef BUILD_opentrack_spline_widget +#ifdef BUILD_spline_widget # define SPLINE_WIDGET_EXPORT Q_DECL_EXPORT #else # define SPLINE_WIDGET_EXPORT Q_DECL_IMPORT @@ -30,7 +30,7 @@ private: struct State { QList<QPointF> input; - std::vector<float> data; + std::vector<float> data; }; int precision() const; @@ -52,6 +52,8 @@ public: { setMaxInput(maxx); setMaxOutput(maxy); + if (cur.input.size() == 0) + cur.input.push_back(QPointF(maxx, maxy)); reload(); } diff --git a/spline-widget/qfunctionconfigurator.cpp b/spline-widget/qfunctionconfigurator.cpp index 7ab1e360..256bf45e 100644 --- a/spline-widget/qfunctionconfigurator.cpp +++ b/spline-widget/qfunctionconfigurator.cpp @@ -5,7 +5,7 @@ * copyright notice and this permission notice appear in all copies. */ -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; #include "spline-widget/qfunctionconfigurator.h" #include <QPainter> @@ -15,13 +15,13 @@ using namespace options; #include <cmath> #include <algorithm> -static const int pointSize = 5; - QFunctionConfigurator::QFunctionConfigurator(QWidget *parent) : QWidget(parent), _config(nullptr), moving_control_point_idx(-1), - _draw_function(true) + _draw_function(true), + snap_x(0), + snap_y(0) { update_range(); setMouseTracking(true); @@ -358,7 +358,7 @@ void QFunctionConfigurator::mouseMoveEvent(QMouseEvent *e) } if (is_on_point) { - setCursor(Qt::OpenHandCursor); + setCursor(Qt::CrossCursor); } else { setCursor(Qt::ArrowCursor); @@ -402,9 +402,8 @@ void QFunctionConfigurator::update_range() bool QFunctionConfigurator::point_within_pixel(const QPointF &pt, const QPointF &pixel) { - QPointF pixel2 = point_to_pixel(pt); - return pixel2.x() >= pixel.x() - pointSize && pixel2.x() < pixel.x() + pointSize && - pixel2.y() >= pixel.y() - pointSize && pixel2.y() < pixel.y() + pointSize; + QPointF tmp = pixel - point_to_pixel(pt); + return sqrt(QPointF::dotProduct(tmp, tmp)) < pointSize; } QPointF QFunctionConfigurator::pixel_coord_to_point(const QPointF& point) @@ -412,8 +411,13 @@ QPointF QFunctionConfigurator::pixel_coord_to_point(const QPointF& point) if (!_config) return QPointF(-1, -1); - double x = (point.x() - pixel_bounds.x()) / c.x(); - double y = (pixel_bounds.height() - point.y() + pixel_bounds.y()) / c.y(); + int x = (point.x() - pixel_bounds.x()) / c.x(); + int y = (pixel_bounds.height() - point.y() + pixel_bounds.y()) / c.y(); + + if (snap_x > 0) + x -= x % snap_x; + if (snap_y > 0) + y -= y % snap_y; if (x < 0) x = 0; diff --git a/spline-widget/qfunctionconfigurator.h b/spline-widget/qfunctionconfigurator.h index 4a9cb5f1..ce8208a8 100644 --- a/spline-widget/qfunctionconfigurator.h +++ b/spline-widget/qfunctionconfigurator.h @@ -19,6 +19,7 @@ class SPLINE_WIDGET_EXPORT QFunctionConfigurator : public QWidget { Q_OBJECT Q_PROPERTY(QColor colorBezier READ colorBezier WRITE setColorBezier) + enum { pointSize = 5 }; public: QFunctionConfigurator(QWidget *parent = 0); @@ -39,6 +40,8 @@ public: _background = QPixmap(); update(); } + void set_snap(int x, int y) { snap_x = x; snap_y = y; } + void get_snap(int& x, int& y) const { x = snap_x; y = snap_y; } protected slots: void paintEvent(QPaintEvent *e) override; void mousePressEvent(QMouseEvent *e) override; @@ -72,4 +75,5 @@ private: QPixmap _background; QPixmap _function; bool _draw_function; + int snap_x, snap_y; }; diff --git a/tracker-aruco/ftnoir_tracker_aruco.cpp b/tracker-aruco/ftnoir_tracker_aruco.cpp index 570c2e0d..316c7e13 100644 --- a/tracker-aruco/ftnoir_tracker_aruco.cpp +++ b/tracker-aruco/ftnoir_tracker_aruco.cpp @@ -16,7 +16,7 @@ #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/videoio.hpp> -#include "opentrack/camera-names.hpp" +#include "opentrack-compat/camera-names.hpp" #include "opentrack-compat/sleep.hpp" typedef struct { @@ -43,6 +43,8 @@ Tracker::~Tracker() delete videoWidget; if(layout) delete layout; + // fast start/stop causes breakage + portable::sleep(1000); camera.release(); } @@ -121,20 +123,17 @@ void Tracker::run() aruco::MarkerDetector detector; detector.setDesiredSpeed(3); + detector._thresMethod = aruco::MarkerDetector::FIXED_THRES; cv::Rect last_roi(65535, 65535, 0, 0); + // XXX change to timer.hpp auto freq = cv::getTickFrequency(); auto last_time = cv::getTickCount(); double cur_fps = 0; - std::vector<int> box_sizes { 5, 7, 9, 11 }; - int box_idx = 0; - double failed = 0; - const double max_failed = 1.25; cv::Vec3d rvec, tvec; cv::Mat intrinsics = cv::Mat::eye(3, 3, CV_32FC1); cv::Mat dist_coeffs = cv::Mat::zeros(5, 1, CV_32FC1); - bool otsu = false; while (!stop) { @@ -145,12 +144,12 @@ void Tracker::run() if (!camera.read(color)) continue; } - static constexpr int thres_param2 = 5; cv::Mat grayscale; cv::cvtColor(color, grayscale, cv::COLOR_RGB2GRAY); const int scale = grayscale.cols > 480 ? 2 : 1; - detector.setThresholdParams(box_sizes[box_idx], thres_param2); + // param 2 ignored for Otsu thresholding. it's required to use our fork of Aruco. + detector.setThresholdParams(5, -1); static constexpr double pi = 3.1415926f; const int w = grayscale.cols, h = grayscale.rows; @@ -180,7 +179,6 @@ void Tracker::run() if (last_roi.width > 0 && last_roi.height) { - detector.setThresholdParams(box_sizes[box_idx], thres_param2); detector.setMinMaxSize(std::max(0.01, size_min * grayscale.cols / last_roi.width), std::min(1.0, size_max * grayscale.cols / last_roi.width)); @@ -188,7 +186,6 @@ void Tracker::run() if (detector.detect(grayscale_, markers, cv::Mat(), cv::Mat(), -1, false), markers.size() == 1 && markers[0].size() == 4) { - failed = std::max(0., failed - dt); auto& m = markers.at(0); for (int i = 0; i < 4; i++) { @@ -202,17 +199,6 @@ void Tracker::run() if (!roi_valid) { - otsu = !otsu; - detector._thresMethod = otsu ? aruco::MarkerDetector::FIXED_THRES : aruco::MarkerDetector::ADPT_THRES; - failed += dt; - if (failed > max_failed) - { - box_idx++; - box_idx %= box_sizes.size(); - qDebug() << "aruco: box size now" << box_sizes[box_idx]; - failed = 0; - } - detector.setThresholdParams(box_sizes[box_idx], thres_param2); detector.setMinMaxSize(size_min, size_max); detector.detect(grayscale, markers, cv::Mat(), cv::Mat(), -1, false); } diff --git a/tracker-aruco/ftnoir_tracker_aruco.h b/tracker-aruco/ftnoir_tracker_aruco.h index f827da77..b9503c6e 100644 --- a/tracker-aruco/ftnoir_tracker_aruco.h +++ b/tracker-aruco/ftnoir_tracker_aruco.h @@ -15,7 +15,7 @@ #include <QHBoxLayout> #include <QDialog> #include <QTimer> -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" #include "trans_calib.h" #include "opentrack/plugin-api.hpp" #include "opentrack/opencv-camera-dialog.hpp" @@ -48,7 +48,7 @@ class Tracker : protected QThread, public ITracker { Q_OBJECT friend class TrackerControls; - static constexpr double c_search_window = 2.65; + static constexpr double c_search_window = 1.3; public: Tracker(); ~Tracker() override; diff --git a/tracker-freepie-udp/ftnoir_tracker_freepie-udp.h b/tracker-freepie-udp/ftnoir_tracker_freepie-udp.h index 7cff2ec9..9d18c7d1 100644 --- a/tracker-freepie-udp/ftnoir_tracker_freepie-udp.h +++ b/tracker-freepie-udp/ftnoir_tracker_freepie-udp.h @@ -10,7 +10,7 @@ #include <QThread> #include "ui_freepie-udp-controls.h" #include "opentrack/plugin-api.hpp" -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; struct settings : opts { diff --git a/tracker-hatire/ftnoir_tracker_hat_dialog.h b/tracker-hatire/ftnoir_tracker_hat_dialog.h index ebaffc6d..bd225b3e 100644 --- a/tracker-hatire/ftnoir_tracker_hat_dialog.h +++ b/tracker-hatire/ftnoir_tracker_hat_dialog.h @@ -29,8 +29,8 @@ public: ~TrackerControls() override; #ifdef OPENTRACK_API void Initialize(QWidget *parent) ; // unused - void register_tracker(ITracker *tracker); - void unregister_tracker(); + void register_tracker(ITracker *tracker) override; + void unregister_tracker() override; #else void Initialize(QWidget *parent) ; void registerTracker(ITracker *tracker) ; diff --git a/tracker-hatire/ftnoir_tracker_hat_settings.cpp b/tracker-hatire/ftnoir_tracker_hat_settings.cpp index e6b32047..df0480a1 100644 --- a/tracker-hatire/ftnoir_tracker_hat_settings.cpp +++ b/tracker-hatire/ftnoir_tracker_hat_settings.cpp @@ -14,7 +14,7 @@ #include "ftnoir_tracker_hat_settings.h" #ifdef OPENTRACK_API -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" #endif void TrackerSettings::load_ini() diff --git a/tracker-ht/CMakeLists.txt b/tracker-ht/CMakeLists.txt index 248a113e..cbbda108 100644 --- a/tracker-ht/CMakeLists.txt +++ b/tracker-ht/CMakeLists.txt @@ -1,3 +1,4 @@ +if(FALSE) set(SDK_HT "" CACHE FILEPATH "Path to headtracker library") set(SDK_HT_FLANDMARK "" CACHE FILEPATH "Path to flandmark library for headtracker") find_package(OpenCV 3.0 QUIET) @@ -9,3 +10,4 @@ if(OpenCV_FOUND) target_include_directories(opentrack-tracker-ht SYSTEM PUBLIC ${OpenCV_INCLUDE_DIRS}) endif() endif() +endif() diff --git a/tracker-ht/ftnoir_tracker_ht.h b/tracker-ht/ftnoir_tracker_ht.h index 1e364456..0563fe1c 100644 --- a/tracker-ht/ftnoir_tracker_ht.h +++ b/tracker-ht/ftnoir_tracker_ht.h @@ -12,7 +12,7 @@ #include "ht_video_widget.h" #include "opentrack-compat/shm.h" #include <QObject> -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" #include "opentrack/plugin-api.hpp" #include "opentrack/opencv-camera-dialog.hpp" diff --git a/tracker-hydra/ftnoir_tracker_hydra.h b/tracker-hydra/ftnoir_tracker_hydra.h index 47a1eb9a..94396b7c 100644 --- a/tracker-hydra/ftnoir_tracker_hydra.h +++ b/tracker-hydra/ftnoir_tracker_hydra.h @@ -1,6 +1,6 @@ #include "ui_ftnoir_hydra_clientcontrols.h" #include "opentrack/plugin-api.hpp" -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; struct settings : opts { diff --git a/tracker-joystick/ftnoir_tracker_joystick.cpp b/tracker-joystick/ftnoir_tracker_joystick.cpp index 77fd7241..d10b15ca 100644 --- a/tracker-joystick/ftnoir_tracker_joystick.cpp +++ b/tracker-joystick/ftnoir_tracker_joystick.cpp @@ -8,220 +8,29 @@ #include "opentrack/plugin-api.hpp" #include <QMutexLocker> -FTNoIR_Tracker::FTNoIR_Tracker() : - g_pDI(nullptr), - g_pJoystick(nullptr), - mtx(QMutex::Recursive), - iter(-1) +FTNoIR_Tracker::FTNoIR_Tracker() { -} - -void FTNoIR_Tracker::reload() -{ - s.b->reload(); - QMutexLocker foo(&mtx); - if (g_pJoystick) + if (static_cast<QString>(s.guid) == "") { - g_pJoystick->Unacquire(); - g_pJoystick->Release(); + std::vector<win32_joy_ctx::joy_info> info = joy_ctx.get_joy_info(); + if (info.size()) + { + s.guid = info[0].guid; + s.b->save(); + } } - if (g_pDI) - g_pDI->Release(); - - g_pJoystick = nullptr; - g_pDI = nullptr; - - start_tracker(frame); } FTNoIR_Tracker::~FTNoIR_Tracker() { - if (g_pJoystick) - { - g_pJoystick->Unacquire(); - g_pJoystick->Release(); - } - if (g_pDI) - { - g_pDI->Release(); - } } -#ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wmissing-field-initializers" -#endif - -static BOOL CALLBACK EnumObjectsCallback( const DIDEVICEOBJECTINSTANCE* pdidoi, - VOID* pContext ) +void FTNoIR_Tracker::start_tracker(QFrame*) { - auto self = (FTNoIR_Tracker*) pContext; - - if( pdidoi->dwType & DIDFT_AXIS ) - { - DIPROPRANGE diprg = {0}; - diprg.diph.dwSize = sizeof( DIPROPRANGE ); - diprg.diph.dwHeaderSize = sizeof( DIPROPHEADER ); - diprg.diph.dwHow = DIPH_BYID; - diprg.diph.dwObj = pdidoi->dwType; - diprg.lMax = FTNoIR_Tracker::AXIS_MAX; - diprg.lMin = -FTNoIR_Tracker::AXIS_MAX; - - if( FAILED( self->g_pJoystick->SetProperty( DIPROP_RANGE, &diprg.diph ) ) ) - return DIENUM_STOP; - - self->iter++; - } - - return self->iter == 8 ? DIENUM_STOP : DIENUM_CONTINUE; -} - -static BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance, VOID* pContext ) -{ - auto self = reinterpret_cast<FTNoIR_Tracker*>(pContext); - bool stop = QString(pdidInstance->tszInstanceName) == self->s.joyid; - - if (stop) - { - if (self->guid_to_check.size()) - { - QString guid = guid_to_string(pdidInstance->guidInstance); - if (guid != self->guid_to_check) - { - return DIENUM_CONTINUE; - } - else - qDebug() << "guid ok" << self->guid_to_check; - } - - (void) self->g_pDI->CreateDevice( pdidInstance->guidInstance, &self->g_pJoystick, NULL); - qDebug() << "device" << static_cast<QString>(self->s.joyid); - } - - return stop ? DIENUM_STOP : DIENUM_CONTINUE; -} - -void FTNoIR_Tracker::start_tracker(QFrame* frame) -{ - QMutexLocker foo(&mtx); - this->frame = frame; - iter = 0; - auto hr = CoInitialize( nullptr ); - - if( FAILED( hr = DirectInput8Create( GetModuleHandle( NULL ), DIRECTINPUT_VERSION, - IID_IDirectInput8, ( VOID** )&g_pDI, NULL ) ) ) - { - qDebug() << "create"; - goto fail; - } - - guid_to_check = s.guid; - - if( FAILED( hr = g_pDI->EnumDevices( DI8DEVCLASS_GAMECTRL, - EnumJoysticksCallback, - this, - DIEDFL_ATTACHEDONLY))) - { - qDebug() << "enum1"; - goto fail; - } - - if (!g_pJoystick && guid_to_check.size()) - { - guid_to_check = ""; - - if( FAILED( hr = g_pDI->EnumDevices( DI8DEVCLASS_GAMECTRL, - EnumJoysticksCallback, - this, - DIEDFL_ATTACHEDONLY))) - { - qDebug() << "enum2"; - goto fail; - } - } - - if (!g_pJoystick) - { - qDebug() << "ENODEV"; - goto fail; - } - - if (FAILED(g_pJoystick->SetDataFormat(&c_dfDIJoystick))) - { - qDebug() << "format"; - goto fail; - } - - if (FAILED(g_pJoystick->SetCooperativeLevel((HWND) frame->window()->winId(), DISCL_NONEXCLUSIVE | DISCL_BACKGROUND))) - { - qDebug() << "coop"; - goto fail; - } - - iter = 0; - - if( FAILED( hr = g_pJoystick->EnumObjects( EnumObjectsCallback, - ( VOID* )this, DIDFT_ALL ))) - { - qDebug() << "enum axes"; - goto fail; - } - - return; - -fail: - if (g_pJoystick) - g_pJoystick->Release(); - if (g_pDI) - g_pDI->Release(); - g_pJoystick = nullptr; - g_pDI = nullptr; - - qDebug() << "joy init failure"; } void FTNoIR_Tracker::data(double *data) { - QMutexLocker foo(&mtx); - DIJOYSTATE js = {0}; - - if( !g_pDI || !g_pJoystick) - return; - - bool ok = false; - - for (int i = 0; i < 100; i++) - { - if (!FAILED(g_pJoystick->Poll())) - { - ok = true; - break; - } - if (g_pJoystick->Acquire() != DI_OK) - continue; - else - ok = true; - break; - } - - if (!ok) - return; - - HRESULT hr = 0; - - if( FAILED( hr = g_pJoystick->GetDeviceState( sizeof( js ), &js ) ) ) - return; - - const LONG values[] = { - js.lX, - js.lY, - js.lZ, - js.lRx, - js.lRy, - js.lRz, - js.rglSlider[0], - js.rglSlider[1] - }; - int map[6] = { s.joy_1 - 1, s.joy_2 - 1, @@ -239,14 +48,21 @@ void FTNoIR_Tracker::data(double *data) 180, 180 }; - - for (int i = 0; i < 6; i++) + + const QString guid = s.guid; + int axes[8]; + const bool ret = joy_ctx.poll_axis(guid, axes); + + if (ret) { - int k = map[i] - 1; - if (k < 0 || k >= 8) - data[i] = 0; - else - data[i] = values[k] * limits[i] / AXIS_MAX; + for (int i = 0; i < 6; i++) + { + int k = map[i] - 1; + if (k < 0 || k >= 8) + data[i] = 0; + else + data[i] = axes[k] * limits[i] / AXIS_MAX; + } } } diff --git a/tracker-joystick/ftnoir_tracker_joystick.h b/tracker-joystick/ftnoir_tracker_joystick.h index 75305f07..1f940b63 100644 --- a/tracker-joystick/ftnoir_tracker_joystick.h +++ b/tracker-joystick/ftnoir_tracker_joystick.h @@ -12,30 +12,20 @@ #include <QMessageBox> #include <QSettings> #include <QList> -#include <QMutex> #include <QFrame> #include <QStringList> #include <cmath> #include "opentrack/plugin-api.hpp" -#ifndef DIRECTINPUT_VERSION -# define DIRECTINPUT_VERSION 0x800 -#endif -#include <windows.h> -#include <commctrl.h> -#include <basetsd.h> -#include <dinput.h> -#include <oleauto.h> -#include <shellapi.h> -#include "opentrack/options.hpp" +#include "opentrack/win32-joystick.hpp" +#include "opentrack-compat/options.hpp" using namespace options; struct settings : opts { - value<QString> joyid, guid; + value<QString> guid; value<int> joy_1, joy_2, joy_3, joy_4, joy_5, joy_6; settings() : opts("tracker-joystick"), - joyid(b, "joy-id", ""), guid(b, "joy-guid", ""), joy_1(b, "axis-map-1", 1), joy_2(b, "axis-map-2", 2), @@ -46,35 +36,17 @@ struct settings : opts { {} }; -template<typename = void> -QString guid_to_string(const GUID guid) -{ - char buf[40] = {0}; - wchar_t szGuidW[40] = {0}; - - StringFromGUID2(guid, szGuidW, 40); - WideCharToMultiByte(0, 0, szGuidW, -1, buf, 40, NULL, NULL); - - return QString(buf); -} - class FTNoIR_Tracker : public ITracker { public: FTNoIR_Tracker(); ~FTNoIR_Tracker(); - void start_tracker(QFrame *frame); + void start_tracker(QFrame *); void data(double *data); - void reload(); - LPDIRECTINPUT8 g_pDI; - LPDIRECTINPUTDEVICE8 g_pJoystick; - QMutex mtx; - QFrame* frame; - DIDEVICEINSTANCE def; - int iter; // XXX bad style settings s; - QString guid_to_check; - static constexpr int AXIS_MAX = 65535; + QString guid; + static constexpr int AXIS_MAX = win32_joy_ctx::joy_axis_size - 1; + win32_joy_ctx joy_ctx; }; class TrackerControls: public ITrackerDialog diff --git a/tracker-joystick/ftnoir_tracker_joystick_dialog.cpp b/tracker-joystick/ftnoir_tracker_joystick_dialog.cpp index 0463933f..a6fa6605 100644 --- a/tracker-joystick/ftnoir_tracker_joystick_dialog.cpp +++ b/tracker-joystick/ftnoir_tracker_joystick_dialog.cpp @@ -1,19 +1,6 @@ #include "ftnoir_tracker_joystick.h" #include "opentrack/plugin-api.hpp" -static BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance, VOID* pContext ) -{ - auto self = ( TrackerControls* )pContext; - auto name = QString(pdidInstance->tszInstanceName); - auto guid = guid_to_string(pdidInstance->guidInstance); - TrackerControls::joys cur { name, guid }; - self->_joys.append(cur); - - self->ui.joylist->addItem(name + " " + guid); - - return DIENUM_CONTINUE; -} - TrackerControls::TrackerControls() : tracker(nullptr) { ui.setupUi( this ); @@ -23,22 +10,25 @@ TrackerControls::TrackerControls() : tracker(nullptr) connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(doCancel())); { - auto hr = CoInitialize( nullptr ); - LPDIRECTINPUT8 g_pDI = nullptr; - - if( FAILED( hr = DirectInput8Create( GetModuleHandle( NULL ), DIRECTINPUT_VERSION, - IID_IDirectInput8, ( VOID** )&g_pDI, NULL ) ) ) - goto fin; - - if( FAILED( hr = g_pDI->EnumDevices( DI8DEVCLASS_GAMECTRL, - EnumJoysticksCallback, - this, - DIEDFL_ATTACHEDONLY ))) - goto fin; - -fin: - if (g_pDI) - g_pDI->Release(); + win32_joy_ctx joy_ctx; + + _joys = QList<joys>(); + + for (auto j : joy_ctx.get_joy_info()) + _joys.push_back(joys { j.name, j.guid }); + } + + { + const QString guid = s.guid; + int idx = 0; + for (int i = 0; i < _joys.size(); i++) + { + const joys& j = _joys[i]; + if (j.guid == guid) + idx = i; + ui.joylist->addItem(j.name + " " + j.guid); + } + ui.joylist->setCurrentIndex(idx); } tie_setting(s.joy_1, ui.joy_1); @@ -54,10 +44,7 @@ void TrackerControls::doOK() { joys def { "", "" }; auto val = _joys.value(idx, def); s.guid = val.guid; - s.joyid = val.name; s.b->save(); - if (tracker) - tracker->reload(); this->close(); } @@ -65,5 +52,3 @@ void TrackerControls::doCancel() { s.b->reload(); this->close(); } - - diff --git a/tracker-pt/camera.cpp b/tracker-pt/camera.cpp index 63b401a8..600ab26a 100644 --- a/tracker-pt/camera.cpp +++ b/tracker-pt/camera.cpp @@ -110,16 +110,14 @@ bool CVCamera::_get_frame(cv::Mat* frame) { if (cap && cap->isOpened()) { - cv::Mat img; - for (int i = 0; i < 100 && !cap->read(img); i++) + for (int i = 0; i < 100 && !cap->read(*frame); i++) ;; - if (img.empty()) + if (frame->empty()) return false; - *frame = img; - cam_info.res_x = img.cols; - cam_info.res_y = img.rows; + cam_info.res_x = frame->cols; + cam_info.res_y = frame->rows; return true; } return false; diff --git a/tracker-pt/ftnoir_tracker_pt.cpp b/tracker-pt/ftnoir_tracker_pt.cpp index 956f639e..a85e3bc0 100644 --- a/tracker-pt/ftnoir_tracker_pt.cpp +++ b/tracker-pt/ftnoir_tracker_pt.cpp @@ -12,14 +12,15 @@ #include <QDebug> #include <QFile> #include <QCoreApplication> -#include "opentrack/camera-names.hpp" +#include "opentrack-compat/camera-names.hpp" +#include "opentrack-compat/sleep.hpp" +#include <functional> //#define PT_PERF_LOG //log performance //----------------------------------------------------------------------------- Tracker_PT::Tracker_PT() - : mutex(QMutex::Recursive), - commands(0), + : commands(0), video_widget(NULL), video_frame(NULL), ever_success(false) @@ -34,6 +35,8 @@ Tracker_PT::~Tracker_PT() delete video_widget; video_widget = NULL; if (video_frame->layout()) delete video_frame->layout(); + // fast start/stop causes breakage + portable::sleep(1000); camera.stop(); } @@ -88,44 +91,40 @@ void Tracker_PT::run() #endif apply_settings(); + cv::Mat frame_; while((commands & ABORT) == 0) { const double dt = time.elapsed() * 1e-9; time.start(); - cv::Mat frame; bool new_frame; { QMutexLocker l(&camera_mtx); new_frame = camera.get_frame(dt, &frame); + if (frame.rows != frame_.rows || frame.cols != frame_.cols) + frame_ = cv::Mat(frame.rows, frame.cols, CV_8UC3); + frame.copyTo(frame_); } - if (new_frame && !frame.empty()) + if (new_frame && !frame_.empty()) { - QMutexLocker lock(&mutex); - - std::vector<cv::Vec2f> points = point_extractor.extract_points(frame); - - // blobs are sorted in order of circularity - if (points.size() > PointModel::N_POINTS) - points.resize(PointModel::N_POINTS); - - bool success = points.size() == PointModel::N_POINTS; + const auto& points = point_extractor.extract_points(frame_); float fx; if (!get_focal_length(fx)) continue; + + const bool success = points.size() >= PointModel::N_POINTS; if (success) { point_tracker.track(points, PointModel(s), fx, s.dynamic_pose, s.init_phase_timeout); + ever_success = true; } Affine X_CM = pose(); - ever_success |= success; - { Affine X_MH(cv::Matx33f::eye(), cv::Vec3f(s.t_MH_x, s.t_MH_y, s.t_MH_z)); // just copy pasted these lines from below if (X_MH.t[0] == 0 && X_MH.t[1] == 0 && X_MH.t[2] == 0) @@ -142,38 +141,39 @@ void Tracker_PT::run() case 2: X_MH.t[0] = -135; X_MH.t[1] = 0; X_MH.t[2] = 0; break; } } - Affine X_GH = X_CM * X_MH; - cv::Vec3f p = X_GH.t; // head (center?) position in global space - cv::Vec2f p_(p[0] / p[2] * fx, p[1] / p[2] * fx); // projected to screen - points.push_back(p_); } - for (unsigned i = 0; i < points.size(); i++) + + std::function<void(const cv::Vec2f&, const cv::Scalar)> fun = [&](const cv::Vec2f& p, const cv::Scalar color) { - auto& p = points[i]; - auto p2 = cv::Point(p[0] * frame.cols + frame.cols/2, -p[1] * frame.cols + frame.rows/2); - cv::Scalar color(0, 255, 0); - if (i == points.size()-1) - color = cv::Scalar(0, 0, 255); - cv::line(frame, + auto p2 = cv::Point(p[0] * frame_.cols + frame_.cols/2, -p[1] * frame_.cols + frame_.rows/2); + cv::line(frame_, cv::Point(p2.x - 20, p2.y), cv::Point(p2.x + 20, p2.y), color, 4); - cv::line(frame, + cv::line(frame_, cv::Point(p2.x, p2.y - 20), cv::Point(p2.x, p2.y + 20), color, - 4); + 4); + }; + + for (unsigned i = 0; i < points.size(); i++) + { + fun(points[i], cv::Scalar(0, 255, 0)); + } + + { + Affine X_MH(cv::Matx33f::eye(), cv::Vec3f(s.t_MH_x, s.t_MH_y, s.t_MH_z)); // just copy pasted these lines from below + Affine X_GH = X_CM * X_MH; + cv::Vec3f p = X_GH.t; // head (center?) position in global space + cv::Vec2f p_(p[0] / p[2] * fx, p[1] / p[2] * fx); // projected to screen + fun(p_, cv::Scalar(0, 0, 255)); } - video_widget->update_image(frame); + video_widget->update_image(frame_); } -#ifdef PT_PERF_LOG - log_stream<<"dt: "<<dt; - if (!frame.empty()) log_stream<<" fps: "<<camera.get_info().fps; - log_stream<<"\n"; -#endif } qDebug()<<"Tracker:: Thread stopping"; } @@ -213,6 +213,7 @@ void Tracker_PT::apply_settings() camera.set_fps(cam_fps); qDebug() << "camera start"; camera.start(); + frame = cv::Mat(); qDebug()<<"Tracker::apply ends"; } diff --git a/tracker-pt/ftnoir_tracker_pt.h b/tracker-pt/ftnoir_tracker_pt.h index f73d106b..dff0c30a 100644 --- a/tracker-pt/ftnoir_tracker_pt.h +++ b/tracker-pt/ftnoir_tracker_pt.h @@ -40,15 +40,14 @@ public: void start_tracker(QFrame* parent_window) override; void data(double* data) override; - Affine pose() { QMutexLocker lock(&mutex); return point_tracker.pose(); } - int get_n_points() { QMutexLocker lock(&mutex); return point_extractor.get_points().size(); } + Affine pose() { return point_tracker.pose(); } + int get_n_points() { return point_extractor.get_points().size(); } bool get_cam_info(CamInfo* info) { QMutexLocker lock(&camera_mtx); return camera.get_info(*info); } public slots: void apply_settings(); protected: void run() override; private: - QMutex mutex; // thread commands enum Command { ABORT = 1<<0 @@ -70,6 +69,7 @@ private: settings_pt s; Timer time; + cv::Mat frame; volatile bool ever_success; diff --git a/tracker-pt/ftnoir_tracker_pt_settings.h b/tracker-pt/ftnoir_tracker_pt_settings.h index 78626468..85f068fe 100644 --- a/tracker-pt/ftnoir_tracker_pt_settings.h +++ b/tracker-pt/ftnoir_tracker_pt_settings.h @@ -9,7 +9,7 @@ #ifndef FTNOIR_TRACKER_PT_SETTINGS_H #define FTNOIR_TRACKER_PT_SETTINGS_H -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; struct settings_pt : opts diff --git a/tracker-pt/point_extractor.cpp b/tracker-pt/point_extractor.cpp index ec37dd00..0208b11d 100644 --- a/tracker-pt/point_extractor.cpp +++ b/tracker-pt/point_extractor.cpp @@ -13,20 +13,22 @@ # include "opentrack-compat/timer.hpp" #endif -PointExtractor::PointExtractor(){ - //if (!AllocConsole()){} - //else SetConsoleTitle("debug"); - //freopen("CON", "w", stdout); - //freopen("CON", "w", stderr); +PointExtractor::PointExtractor() +{ } -// ---------------------------------------------------------------------------- -std::vector<cv::Vec2f> PointExtractor::extract_points(cv::Mat& frame) + +const std::vector<cv::Vec2f>& PointExtractor::extract_points(cv::Mat& frame) { const int W = frame.cols; const int H = frame.rows; + + if (frame_gray.rows != frame.rows || frame_gray.cols != frame.cols) + { + frame_gray = cv::Mat(frame.rows, frame.cols, CV_8U); + frame_bin = cv::Mat(frame.rows, frame.cols, CV_8U);; + } // convert to grayscale - cv::Mat frame_gray; cv::cvtColor(frame, frame_gray, cv::COLOR_RGB2GRAY); const double region_size_min = s.min_point_size; @@ -51,7 +53,6 @@ std::vector<cv::Vec2f> PointExtractor::extract_points(cv::Mat& frame) }; // mask for everything that passes the threshold (or: the upper threshold of the hysteresis) - cv::Mat frame_bin = cv::Mat::zeros(H, W, CV_8U); std::vector<blob> blobs; std::vector<std::vector<cv::Point>> contours; @@ -59,42 +60,39 @@ std::vector<cv::Vec2f> PointExtractor::extract_points(cv::Mat& frame) const int thres = s.threshold; if (!s.auto_threshold) { - cv::Mat frame_bin_; - cv::threshold(frame_gray, frame_bin_, thres, 255, cv::THRESH_BINARY); - frame_bin.setTo(170, frame_bin_); - cv::findContours(frame_bin_, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE); + cv::threshold(frame_gray, frame_bin, thres, 255, cv::THRESH_BINARY); + cv::findContours(frame_bin, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE); } else { - cv::Mat hist; cv::calcHist(std::vector<cv::Mat> { frame_gray }, std::vector<int> { 0 }, cv::Mat(), hist, - std::vector<int> { 256 }, - std::vector<float> { 0, 256 }, + std::vector<int> { 256/hist_c }, + std::vector<float> { 0, 256/hist_c }, false); - const int sz = hist.rows*hist.cols; + const int sz = hist.cols * hist.rows; int val = 0; int cnt = 0; constexpr int min_pixels = 250; const auto pixels_to_include = std::max<int>(0, min_pixels * s.threshold/100.); + auto ptr = reinterpret_cast<const float*>(hist.ptr(0)); for (int i = sz-1; i >= 0; i--) { - cnt += hist.at<float>(i); + cnt += ptr[i]; if (cnt >= pixels_to_include) { val = i; break; } } + val *= hist_c; val *= 240./256.; //qDebug() << "val" << val; - cv::Mat frame_bin_; - cv::threshold(frame_gray, frame_bin_, val, 255, CV_THRESH_BINARY); - frame_bin.setTo(170, frame_bin_); - cv::findContours(frame_bin_, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE); + cv::threshold(frame_gray, frame_bin, val, 255, CV_THRESH_BINARY); + cv::findContours(frame_bin, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE); } int cnt = 0; @@ -150,31 +148,27 @@ std::vector<cv::Vec2f> PointExtractor::extract_points(cv::Mat& frame) } blobs.push_back(blob(radius, pos, confid, area)); + + enum { max_blobs = 16 }; + + if (blobs.size() == max_blobs) + break; } - // clear old points - points.clear(); - using b = const blob; std::sort(blobs.begin(), blobs.end(), [](b& b1, b& b2) {return b1.confid > b2.confid;}); + points.reserve(blobs.size()); + + QMutexLocker l(&mtx); + + points.clear(); + for (auto& b : blobs) { cv::Vec2f p((b.pos[0] - W/2)/W, -(b.pos[1] - H/2)/W); points.push_back(p); } - // draw output image - std::vector<cv::Mat> channels_; - cv::split(frame, channels_); - std::vector<cv::Mat> channels; - { - cv::Mat frame_bin__ = frame_bin * .5; - channels.push_back(channels_[0] + frame_bin__); - channels.push_back(channels_[1] - frame_bin__); - channels.push_back(channels_[2] - frame_bin__); - cv::merge(channels, frame); - } - return points; } diff --git a/tracker-pt/point_extractor.h b/tracker-pt/point_extractor.h index b9368ab6..030251ff 100644 --- a/tracker-pt/point_extractor.h +++ b/tracker-pt/point_extractor.h @@ -13,21 +13,26 @@ #include "ftnoir_tracker_pt_settings.h" -// ---------------------------------------------------------------------------- -// Extracts points from an opencv image +#include <QMutex> + class PointExtractor { public: // extracts points from frame and draws some processing info into frame, if draw_output is set // dt: time since last call in seconds // WARNING: returned reference is valid as long as object - std::vector<cv::Vec2f> extract_points(cv::Mat &frame); - const std::vector<cv::Vec2f>& get_points() { return points; } + const std::vector<cv::Vec2f> &extract_points(cv::Mat &frame); + const std::vector<cv::Vec2f>& get_points() { QMutexLocker l(&mtx); return points; } PointExtractor(); settings_pt s; private: + enum { hist_c = 2 }; std::vector<cv::Vec2f> points; + QMutex mtx; + cv::Mat frame_gray; + cv::Mat frame_bin; + cv::Mat hist; }; #endif //POINTEXTRACTOR_H diff --git a/tracker-pt/point_tracker.cpp b/tracker-pt/point_tracker.cpp index 924b75de..aa6feb5b 100644 --- a/tracker-pt/point_tracker.cpp +++ b/tracker-pt/point_tracker.cpp @@ -249,6 +249,7 @@ int PointTracker::POSIT(const PointModel& model, const PointOrder& order_, float old_epsilon_2 = epsilon_2; } + QMutexLocker l(&mtx); // apply results X_CM.R = *R_current; X_CM.t[0] = order[0][0] * Z0/focal_length; diff --git a/tracker-pt/point_tracker.h b/tracker-pt/point_tracker.h index 8c754718..48c7617e 100644 --- a/tracker-pt/point_tracker.h +++ b/tracker-pt/point_tracker.h @@ -15,9 +15,8 @@ #include "ftnoir_tracker_pt_settings.h" #include <QObject> +#include <QMutex> -// ---------------------------------------------------------------------------- -// Affine frame trafo class Affine { public: @@ -120,12 +119,8 @@ public: // f : (focal length)/(sensor width) // dt : time since last call void track(const std::vector<cv::Vec2f>& projected_points, const PointModel& model, float f, bool dynamic_pose, int init_phase_timeout); - Affine pose() const { return X_CM; } + Affine pose() { QMutexLocker l(&mtx); return X_CM; } cv::Vec2f project(const cv::Vec3f& v_M, float f); - void reset(const Affine& pose) - { - X_CM = pose; - } private: // the points in model order struct PointOrder @@ -146,6 +141,7 @@ private: Timer t; bool init_phase; + QMutex mtx; }; #endif //POINTTRACKER_H diff --git a/tracker-pt/pt_video_widget.cpp b/tracker-pt/pt_video_widget.cpp index cbb7c268..99f86eb2 100644 --- a/tracker-pt/pt_video_widget.cpp +++ b/tracker-pt/pt_video_widget.cpp @@ -9,6 +9,7 @@ */ #include "pt_video_widget.h" +#include <opencv2/imgproc.hpp> void PTVideoWidget::update_image(const cv::Mat& frame) { @@ -16,40 +17,32 @@ void PTVideoWidget::update_image(const cv::Mat& frame) if (!freshp) { - _frame = frame.clone(); + if (_frame.cols != frame.cols || _frame.rows != frame.rows) + { + _frame = cv::Mat(frame.rows, frame.cols, CV_8U); + _frame2 = cv::Mat(frame.rows, frame.cols, CV_8U); + } + frame.copyTo(_frame); freshp = true; } } void PTVideoWidget::update_and_repaint() { - QImage qframe; + if (static_cast<QWidget*>(parent())->isEnabled()) { QMutexLocker foo(&mtx); if (_frame.empty() || !freshp) return; - qframe = QImage(_frame.cols, _frame.rows, QImage::Format_RGB888); + cv::cvtColor(_frame, _frame2, cv::COLOR_RGB2BGR); + + if (_frame3.cols != width() || _frame3.rows != height()) + _frame3 = cv::Mat(height(), width(), CV_8U); + + cv::resize(_frame2, _frame3, cv::Size(width(), height()), 0, 0, cv::INTER_NEAREST); + + texture = QImage((const unsigned char*) _frame3.data, _frame3.cols, _frame3.rows, QImage::Format_RGB888); freshp = false; - uchar* data = qframe.bits(); - const int pitch = qframe.bytesPerLine(); - unsigned char *input = (unsigned char*) _frame.data; - const int chans = _frame.channels(); - for (int y = 0; y < _frame.rows; y++) - { - const int step = y * _frame.step; - const int pitch_ = y * pitch; - for (int x = 0; x < _frame.cols; x++) - { - data[pitch_ + x * 3 + 0] = input[step + x * chans + 2]; - data[pitch_ + x * 3 + 1] = input[step + x * chans + 1]; - data[pitch_ + x * 3 + 2] = input[step + x * chans + 0]; - } - } - } - qframe = qframe.scaled(size(), Qt::IgnoreAspectRatio, Qt::FastTransformation); - { - QMutexLocker foo(&mtx); - texture = qframe; + update(); } - update(); } diff --git a/tracker-pt/pt_video_widget.h b/tracker-pt/pt_video_widget.h index af1d60fd..d9144ac0 100644 --- a/tracker-pt/pt_video_widget.h +++ b/tracker-pt/pt_video_widget.h @@ -17,6 +17,7 @@ #include <QTimer> #include <QMutex> #include <QMutexLocker> +#include <QDebug> class PTVideoWidget : public QWidget { @@ -28,7 +29,7 @@ public: freshp(false) { connect(&timer, SIGNAL(timeout()), this, SLOT(update_and_repaint())); - timer.start(40); + timer.start(50); } void update_image(const cv::Mat &frame); protected slots: @@ -42,6 +43,6 @@ private: QMutex mtx; QImage texture; QTimer timer; - cv::Mat _frame; + cv::Mat _frame, _frame2, _frame3; bool freshp; }; diff --git a/tracker-rift-025/ftnoir_tracker_rift_025.h b/tracker-rift-025/ftnoir_tracker_rift_025.h index 2bd5024b..8333e092 100644 --- a/tracker-rift-025/ftnoir_tracker_rift_025.h +++ b/tracker-rift-025/ftnoir_tracker_rift_025.h @@ -6,7 +6,7 @@ #include "opentrack/plugin-api.hpp" #include "OVR.h" #include <memory> -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; struct settings : opts { diff --git a/tracker-rift-042/ftnoir_tracker_rift_042.h b/tracker-rift-042/ftnoir_tracker_rift_042.h index 437a2a39..77e7ffa6 100644 --- a/tracker-rift-042/ftnoir_tracker_rift_042.h +++ b/tracker-rift-042/ftnoir_tracker_rift_042.h @@ -6,7 +6,7 @@ #include "opentrack/plugin-api.hpp" #include "OVR.h" #include <memory> -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; struct settings : opts { diff --git a/tracker-rift-080/ftnoir_tracker_rift_080.cpp b/tracker-rift-080/ftnoir_tracker_rift_080.cpp index 889ac8c3..ea77b6d1 100644 --- a/tracker-rift-080/ftnoir_tracker_rift_080.cpp +++ b/tracker-rift-080/ftnoir_tracker_rift_080.cpp @@ -21,11 +21,8 @@ Rift_Tracker::~Rift_Tracker() void Rift_Tracker::start_tracker(QFrame*) { - { - ovrInitParams args = {0}; - if (!OVR_SUCCESS(ovr_Initialize(&args))) - goto error; - } + if (!OVR_SUCCESS(ovr_Initialize(nullptr))) + goto error; { ovrGraphicsLuid luid = {0}; ovrResult res = ovr_Create(&hmd, &luid); diff --git a/tracker-rift-080/ftnoir_tracker_rift_080.h b/tracker-rift-080/ftnoir_tracker_rift_080.h index 08684dd2..879d31d2 100644 --- a/tracker-rift-080/ftnoir_tracker_rift_080.h +++ b/tracker-rift-080/ftnoir_tracker_rift_080.h @@ -6,7 +6,7 @@ #include "opentrack/plugin-api.hpp" #include "OVR.h" #include <memory> -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; struct settings : opts { diff --git a/tracker-rs/CMakeLists.txt b/tracker-rs/CMakeLists.txt index f4f6d4b9..901d68bb 100644 --- a/tracker-rs/CMakeLists.txt +++ b/tracker-rs/CMakeLists.txt @@ -1,5 +1,5 @@ if(WIN32) opentrack_boilerplate(opentrack-tracker-rs) install(FILES "${CMAKE_SOURCE_DIR}/tracker-rs/rs_impl/bin/opentrack-tracker-rs-impl.exe" DESTINATION . ${opentrack-perms}) - install(FILES "${CMAKE_SOURCE_DIR}/tracker-rs/redist/intel_rs_sdk_runtime_websetup_6.0.21.6598.exe" DESTINATION ./contrib/ ${opentrack-perms}) + install(FILES "${CMAKE_SOURCE_DIR}/tracker-rs/redist/intel_rs_sdk_runtime_websetup_7.0.23.8048.exe" DESTINATION ./contrib/ ${opentrack-perms}) endif() diff --git a/tracker-rs/ftnoir_tracker_rs.cpp b/tracker-rs/ftnoir_tracker_rs.cpp index 3e9b23c8..e073fa3f 100644 --- a/tracker-rs/ftnoir_tracker_rs.cpp +++ b/tracker-rs/ftnoir_tracker_rs.cpp @@ -71,17 +71,17 @@ void RSTracker::rsImplProcessFinished(int exitCode){ msgBox.setIcon(QMessageBox::Critical); msgBox.setText("RealSense Tracking Error"); if(exitCode==-101){ //The implementation got an invalid handle from the RealSense SDK session/modules - msgBox.setInformativeText("Couldn't initialize RealSense tracking. Please install SDK Runtime R4."); + msgBox.setInformativeText("Couldn't initialize RealSense tracking. Please install SDK Runtime R5."); } else { - msgBox.setInformativeText("Status code: " + QString::number(exitCode) + ".\n\nNote that you need the latest camera drivers and the SDK runtime R4 to be installed."); + msgBox.setInformativeText("Status code: " + QString::number(exitCode) + ".\n\nNote that you need the latest camera drivers and the SDK runtime R5 to be installed."); } QPushButton* triggerSdkInstallation = msgBox.addButton("Install Runtime", QMessageBox::ActionRole); msgBox.addButton(QMessageBox::Ok); msgBox.exec(); if(msgBox.clickedButton() == triggerSdkInstallation){ - bool pStarted = QProcess::startDetached("contrib\\intel_rs_sdk_runtime_websetup_6.0.21.6598.exe --finstall=core,face3d --fnone=all"); + bool pStarted = QProcess::startDetached("contrib\\intel_rs_sdk_runtime_websetup_7.0.23.8048.exe --finstall=core,face3d --fnone=all"); if(!pStarted){ QMessageBox::warning(0, "Intel® RealSense™ Runtime Installation", "Installation process failed to start.", QMessageBox::Ok); } diff --git a/tracker-rs/ftnoir_tracker_rs_controls.cpp b/tracker-rs/ftnoir_tracker_rs_controls.cpp index 6c71d58f..be18b3f8 100644 --- a/tracker-rs/ftnoir_tracker_rs_controls.cpp +++ b/tracker-rs/ftnoir_tracker_rs_controls.cpp @@ -20,7 +20,7 @@ RSTrackerControls::RSTrackerControls() void RSTrackerControls::doInstallRSRuntime() { - bool processStarted = QProcess::startDetached("contrib\\intel_rs_sdk_runtime_websetup_6.0.21.6598.exe --finstall=core,face3d --fnone=all"); + bool processStarted = QProcess::startDetached("contrib\\intel_rs_sdk_runtime_websetup_7.0.23.8048.exe --finstall=core,face3d --fnone=all"); if(processStarted){ this->close(); } diff --git a/tracker-rs/ftnoir_tracker_rs_controls.ui b/tracker-rs/ftnoir_tracker_rs_controls.ui index 834803d1..023e14d3 100644 --- a/tracker-rs/ftnoir_tracker_rs_controls.ui +++ b/tracker-rs/ftnoir_tracker_rs_controls.ui @@ -37,14 +37,14 @@ Intel® RealSense™ SDK. By design, the application has no direct access to any camera images. In order to use this tracker, you need a PC equipped with -an Intel® RealSense™ R200 camera and the RealSense™ SDK R4 runtime.</string> +an Intel® RealSense™ R200 camera and the RealSense™ SDK R5 runtime.</string> </property> </widget> </item> <item alignment="Qt::AlignHCenter|Qt::AlignVCenter"> <widget class="QPushButton" name="triggerSDKInstallButton"> <property name="text"> - <string>Install SDK Runtime R4</string> + <string>Install SDK Runtime R5</string> </property> </widget> </item> diff --git a/tracker-rs/redist/intel_rs_sdk_runtime_websetup_6.0.21.6598.exe b/tracker-rs/redist/intel_rs_sdk_runtime_websetup_6.0.21.6598.exe Binary files differdeleted file mode 100644 index 34ecc9df..00000000 --- a/tracker-rs/redist/intel_rs_sdk_runtime_websetup_6.0.21.6598.exe +++ /dev/null diff --git a/tracker-rs/redist/intel_rs_sdk_runtime_websetup_7.0.23.8048.exe b/tracker-rs/redist/intel_rs_sdk_runtime_websetup_7.0.23.8048.exe Binary files differnew file mode 100644 index 00000000..2e2b365c --- /dev/null +++ b/tracker-rs/redist/intel_rs_sdk_runtime_websetup_7.0.23.8048.exe diff --git a/tracker-rs/rs_impl/bin/opentrack-tracker-rs-impl.exe b/tracker-rs/rs_impl/bin/opentrack-tracker-rs-impl.exe Binary files differindex 1e2a57f1..e00ed69c 100644 --- a/tracker-rs/rs_impl/bin/opentrack-tracker-rs-impl.exe +++ b/tracker-rs/rs_impl/bin/opentrack-tracker-rs-impl.exe diff --git a/tracker-rs/rs_impl/build.bat b/tracker-rs/rs_impl/build.bat index 15206431..3a44fed5 100644 --- a/tracker-rs/rs_impl/build.bat +++ b/tracker-rs/rs_impl/build.bat @@ -1,2 +1,6 @@ -cd "%VS120COMNTOOLS%\..\..\VC" +IF DEFINED %VS120COMNTOOLS%] ( + cd "%VS120COMNTOOLS%\..\..\VC" + ) ELSE ( + cd "%VS140COMNTOOLS%\..\..\VC" + ) vcvarsall x64 && cd %~dp0 && CL /nologo /Ox /DUNICODE /D_UNICODE /MT /I"%RSSDK_DIR%\opensource\include" ftnoir_tracker_rs_impl.cpp udp_sender.cpp "%RSSDK_DIR%\opensource\src\libpxc\libpxc.cpp" /link ADVAPI32.LIB Ws2_32.lib /SUBSYSTEM:CONSOLE /OUT:bin\opentrack-tracker-rs-impl.exe
\ No newline at end of file diff --git a/tracker-udp/ftnoir_tracker_udp.h b/tracker-udp/ftnoir_tracker_udp.h index 6de5b295..3f0e6d8c 100644 --- a/tracker-udp/ftnoir_tracker_udp.h +++ b/tracker-udp/ftnoir_tracker_udp.h @@ -4,7 +4,7 @@ #include <QThread> #include <cmath> #include "opentrack/plugin-api.hpp" -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; struct settings : opts { |