diff options
61 files changed, 1492 insertions, 262 deletions
| diff --git a/.clang-tidy b/.clang-tidy index 28fe3584..a29d0ffd 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -19,6 +19,8 @@ clang-analyzer-core.CallAndMessage,  clang-analyzer-deadcode.DeadStores,  -clang-diagnostic-nonportable-include-path,  -cppcoreguidelines-avoid-c-arrays, +-cppcoreguidelines-avoid-capture-default-when-capturing-this, +-cppcoreguidelines-avoid-do-while,  -cppcoreguidelines-avoid-goto,  -cppcoreguidelines-avoid-magic-numbers,  -cppcoreguidelines-c-copy-assignment-signature, @@ -61,6 +63,7 @@ clang-analyzer-deadcode.DeadStores,  -hicpp-use-override,  -hicpp-vararg,  -misc-non-private-member-variables-in-classes, +-misc-use-anonymous-namespace,  -modernize-avoid-c-arrays,  -modernize-loop-convert,  -modernize-pass-by-value, diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index ce47a3db..c24e9c99 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -36,7 +36,7 @@ jobs:      - uses: seanmiddleditch/gha-setup-ninja@master      - name: Install Linux Dependencies -      run: sudo apt update && sudo apt install libprocps-dev libopencv-dev libopencv-dev +      run: sudo apt update && sudo apt install libprocps-dev libopencv-dev libopencv-dev wine64-tools        if: matrix.os == 'ubuntu-latest'      - name: Cache Qt diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c6613bd..bb1cfff2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,24 +110,24 @@ otr_merge_translations()  include(opentrack-install)  string(TOUPPER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE) -message(STATUS "-- Compile flags:") +message("Compile flags:")  #foreach(j C CXX)  foreach(j CXX)      foreach(i "" "_${CMAKE_BUILD_TYPE}") -        message(STATUS " ${j}${i}: ${CMAKE_${j}_FLAGS${i}}") +        message("   ${j}${i}: ${CMAKE_${j}_FLAGS${i}}")      endforeach()  endforeach() -message(STATUS "-- Link flags:") +message("Link flags:")  foreach(j "" "_${CMAKE_BUILD_TYPE}")      #foreach(i EXE SHARED)      foreach(i SHARED) -        message(STATUS " LINK_${i}${j}: ${CMAKE_${i}_LINKER_FLAGS${j}}") +        message("   LINK_${i}${j}: ${CMAKE_${i}_LINKER_FLAGS${j}}")      endforeach()  endforeach() -message(STATUS "-- Static archive flags:") +message("Static archive flags:")  foreach(k "" "_${CMAKE_BUILD_TYPE}") -    message(STATUS " STATIC${k}: ${CMAKE_STATIC_LINKER_FLAGS${k}}") +    message("   STATIC${k}: ${CMAKE_STATIC_LINKER_FLAGS${k}}")  endforeach() -message(STATUS "--") +message("--") @@ -1,6 +1,6 @@  ## Intro -[<img src="https://ci.appveyor.com/api/projects/status/n0j9h38jnif5qbe9/branch/unstable?svg=true"/>](https://ci.appveyor.com/project/sthalik/opentrack/branch/unstable) +[<img src="https://github.com/opentrack/opentrack/actions/workflows/cmake.yml/badge.svg">](https://github.com/opentrack/opentrack/actions/workflows/cmake.yml)  opentrack project home is located at <<http://github.com/opentrack/opentrack>>. @@ -40,6 +40,7 @@ Don't be afraid to submit an **issue/feature request** if you have any problems!  - BBC micro:bit, LEGO, sensortag support via Smalltalk<sup>[(1)](https://en.wikipedia.org/wiki/Smalltalk)[(2)](https://en.wikipedia.org/wiki/Alan_Kay)</sup>    [S2Bot](http://www.picaxe.com/Teaching/Other-Software/Scratch-Helper-Apps/)  - Wiimote (Windows) +- Eyeware Beam<sup>[[1](https://beam.eyeware.tech/)]</sup>  ## Output protocols @@ -69,6 +70,7 @@ Don't be afraid to submit an **issue/feature request** if you have any problems!  - Wei Shuai (Wiimote tracker)  - Stéphane Lenclud (Kinect Face Tracker, Easy Tracker)  - GO63-samara (Hamilton Filter, Pose-widget improvement) +- Davide Mameli (Eyeware Beam tracker)  ## Thanks diff --git a/api/plugin-api.cpp b/api/plugin-api.cpp index 6a43b55d..4d8d90e9 100644 --- a/api/plugin-api.cpp +++ b/api/plugin-api.cpp @@ -21,7 +21,7 @@ void BaseDialog::done(int)  bool BaseDialog::embeddable() noexcept { return false; }  void BaseDialog::save() {}  void BaseDialog::reload() {} -void BaseDialog::set_buttons_visible(bool x) {} +void BaseDialog::set_buttons_visible(bool) {}  } // ns plugin_api::detail @@ -36,13 +36,13 @@ IFilter::IFilter() = default;  IFilter::~IFilter() = default;  IFilterDialog::IFilterDialog() = default;  IFilterDialog::~IFilterDialog() = default; -void IFilterDialog::register_filter(IFilter* filter) {} +void IFilterDialog::register_filter(IFilter*) {}  void IFilterDialog::unregister_filter() {}  IProtocol::IProtocol() = default;  IProtocol::~IProtocol() = default;  IProtocolDialog::IProtocolDialog() = default;  IProtocolDialog::~IProtocolDialog() = default; -void IProtocolDialog::register_protocol(IProtocol* protocol){} +void IProtocolDialog::register_protocol(IProtocol*){}  void IProtocolDialog::unregister_protocol() {}  ITracker::ITracker() = default;  ITracker::~ITracker() = default; diff --git a/cmake/msvc.cmake b/cmake/msvc.cmake index 12470eef..cf3bb0cb 100644 --- a/cmake/msvc.cmake +++ b/cmake/msvc.cmake @@ -37,7 +37,7 @@ add_definitions(-D_HAS_EXCEPTIONS=0)  if(DEFINED CMAKE_TOOLCHAIN_FILE)      # ignore cmake warning: Manually-specified variable not used by the project -    set(CMAKE_TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}}") +    set(CMAKE_TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}")  endif()  include("${CMAKE_CURRENT_LIST_DIR}/opentrack-policy.cmake" NO_POLICY_SCOPE) @@ -106,29 +106,42 @@ if(CMAKE_PROJECT_NAME STREQUAL "OpenCV")      set(BUILD_opencv_gapi   OFF)  endif() +if(CMAKE_PROJECT_NAME STREQUAL "TestOscpack") +    add_compile_definitions(OSC_HOST_LITTLE_ENDIAN) +endif() +  set(opentrack-simd "SSE2")  if(CMAKE_PROJECT_NAME STREQUAL "onnxruntime")      set(opentrack-simd "AVX") +    if(opentrack-no-static-crt) +        sets(BOOL +        ONNX_USE_MSVC_STATIC_RUNTIME            OFF +        protobuf_MSVC_STATIC_RUNTIME            OFF +        ) +    else() +        sets(BOOL +        ONNX_USE_MSVC_STATIC_RUNTIME            ON +        protobuf_MSVC_STATIC_RUNTIME            ON +        ) +    endif()      sets(BOOL -         onnxruntime_USE_AVX ON -         onnxruntime_USE_AVX2 OFF -         onnxruntime_USE_AVX512 OFF -         ONNX_USE_MSVC_STATIC_RUNTIME ON -         protobuf_MSVC_STATIC_RUNTIME ON -         onnxruntime_BUILD_BENCHMARKS OFF -         onnxruntime_BUILD_FOR_NATIVE_MACHINE OFF -         onnxruntime_BUILD_SHARED_LIB ON -         onnxruntime_BUILD_UNIT_TESTS OFF -         protobuf_BUILD_EXAMPLES OFF -         protobuf_BUILD_SHARED_LIBS OFF -         ONNX_BUILD_BENCHMARKS OFF -         ONNX_BUILD_TESTS OFF -         ONNX_DISABLE_EXCEPTIONS OFF # important! -         ONNX_GEN_PB_TYPE_STUBS OFF -         onnxruntime_DISABLE_CONTRIB_OPS ON -         BUILD_TESTING OFF +         onnxruntime_USE_AVX                    ON +         onnxruntime_USE_AVX2                   OFF +         onnxruntime_USE_AVX512                 OFF +         onnxruntime_BUILD_BENCHMARKS           OFF +         onnxruntime_BUILD_FOR_NATIVE_MACHINE   OFF +         onnxruntime_BUILD_SHARED_LIB           ON +         onnxruntime_BUILD_UNIT_TESTS           OFF +         protobuf_BUILD_EXAMPLES                OFF +         protobuf_BUILD_SHARED_LIBS             OFF +         ONNX_BUILD_BENCHMARKS                  OFF +         ONNX_BUILD_TESTS                       OFF +         ONNX_DISABLE_EXCEPTIONS                OFF # important! +         ONNX_GEN_PB_TYPE_STUBS                 OFF +         onnxruntime_DISABLE_CONTRIB_OPS        ON +         BUILD_TESTING                          OFF      )  elseif(opentrack-64bit)      set(opentrack-simd "AVX") diff --git a/cmake/opentrack-load-user-settings.cmake b/cmake/opentrack-load-user-settings.cmake index 1baf3702..fdb63936 100644 --- a/cmake/opentrack-load-user-settings.cmake +++ b/cmake/opentrack-load-user-settings.cmake @@ -26,12 +26,11 @@ else()      set(__sdk_host_os "")  endif() -set(__sdk_paths_basename "sdk-paths-${__sdk_username}@${CMAKE_CXX_COMPILER_ID}-${__sdk_host_os}${__sdk_target_os}.cmake") -set(__sdk_paths_filename "${CMAKE_SOURCE_DIR}/${__sdk_paths_basename}") +set(__sdk_paths_filename "${CMAKE_CURRENT_SOURCE_DIR}/sdk-paths-${__sdk_username}@${CMAKE_CXX_COMPILER_ID}-${__sdk_host_os}${__sdk_target_os}.cmake")  if(EXISTS "${__sdk_paths_filename}") -    message(STATUS "Loading user settings '${__sdk_paths_basename}'") +    message(STATUS "Loading user settings '${__sdk_paths_filename}'")      include("${__sdk_paths_filename}")  else() -    message(STATUS "User settings file '${__sdk_paths_basename}' doesn't exist") +    message(STATUS "User settings file '${__sdk_paths_filename}' doesn't exist")  endif() diff --git a/cmake/opentrack-platform.cmake b/cmake/opentrack-platform.cmake index fd82c1b5..7aceb17a 100644 --- a/cmake/opentrack-platform.cmake +++ b/cmake/opentrack-platform.cmake @@ -34,8 +34,6 @@ set(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" CACHE STRING "" FORCE)  include_directories("${CMAKE_SOURCE_DIR}") -set(opentrack_maintainer-mode FALSE CACHE INTERNAL "Select if developing core code (not modules)") -  set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)  set(CMAKE_CXX_STANDARD 20) diff --git a/cmake/opentrack-qt.cmake b/cmake/opentrack-qt.cmake index 800e9096..1735e836 100644 --- a/cmake/opentrack-qt.cmake +++ b/cmake/opentrack-qt.cmake @@ -51,7 +51,7 @@ function(otr_qt n)  endfunction()  function(otr_qt2 n) -    target_include_directories("${n}" PRIVATE SYSTEM +    target_include_directories("${n}" SYSTEM PRIVATE          ${Qt5Core_INCLUDE_DIRS} ${Qt5Gui_INCLUDE_DIRS} ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Network_INCLUDE_DIRS}      )      target_compile_definitions("${n}" PRIVATE diff --git a/gui/options-dialog.cpp b/gui/options-dialog.cpp index ac4117bc..9cd416ee 100644 --- a/gui/options-dialog.cpp +++ b/gui/options-dialog.cpp @@ -172,7 +172,7 @@ options_dialog::options_dialog(std::unique_ptr<ITrackerDialog>& tracker_dialog_,                  val.label,                  [=](const QString&) { val.label->setText(kopts_to_string(val.opt)); });          { -            connect(val.button, &QPushButton::clicked, this, [=] { bind_key(val.opt, val.label); }); +            connect(val.button, &QPushButton::clicked, this, [=, this] { bind_key(val.opt, val.label); });          }      } diff --git a/opentrack/main-window.cpp b/opentrack/main-window.cpp index 754d7e7c..f449845b 100644 --- a/opentrack/main-window.cpp +++ b/opentrack/main-window.cpp @@ -18,7 +18,6 @@  #include "compat/math.hpp"  #include "compat/sysexits.hpp"  #include "opentrack/defs.hpp" -#include "software-update-dialog.hpp"  #include <cstring>  #include <utility> @@ -34,7 +33,6 @@  #include <QDateTime>  extern "C" const char* const opentrack_version; -extern "C" OTR_GENERIC_IMPORT bool opentrack_using_dark_theme;  using namespace options::globals;  using namespace options; @@ -60,8 +58,6 @@ main_window::main_window() : State(OPENTRACK_BASE_PATH + OPENTRACK_LIBRARY_PATH)      setVisible(!start_in_tray());      ensure_tray(); -    ui.pose_display->set_grid_background(opentrack_using_dark_theme); -      connect(&pose_update_timer, &QTimer::timeout,              this, &main_window::show_pose, Qt::DirectConnection);      connect(&det_timer, &QTimer::timeout, @@ -74,13 +70,7 @@ main_window::main_window() : State(OPENTRACK_BASE_PATH + OPENTRACK_LIBRARY_PATH)  #ifdef UI_NO_VIDEO_FEED      fake_video_frame.resize(640, 480);      fake_video_frame_parent.setVisible(false); -#elif defined UI_COMPACT_VIDEO_FEED -    connect(ui.preview_checkbox, &QCheckBox::toggled, this, &main_window::toggle_video_preview);  #endif - -    updater = std::make_unique<update_query>(this); -    updater->maybe_show_dialog(); -  }  void main_window::init_shortcuts() @@ -429,12 +419,7 @@ void main_window::update_button_state(bool running, bool inertialp)      ui.iconcomboTrackerSource->setEnabled(not_running);  #endif      ui.profile_button->setEnabled(not_running); -#ifdef UI_COMPACT_VIDEO_FEED -    ui.preview_checkbox->setChecked(false); -    ui.preview_checkbox->raise(); -    ui.preview_checkbox->setVisible(running && !inertialp); -    toggle_video_preview(false); -#elif !defined UI_NO_VIDEO_FEED +#ifndef UI_NO_VIDEO_FEED      ui.video_frame_label->setVisible(not_running || inertialp);      if(not_running)      { @@ -446,22 +431,6 @@ void main_window::update_button_state(bool running, bool inertialp)  #endif  } -#ifdef UI_COMPACT_VIDEO_FEED -void main_window::toggle_video_preview(bool value) -{ -    value &= ui.video_frame->layout() != nullptr; -    ui.video_frame_parent->setVisible(value); -    ui.video_frame_parent->raise(); -    ui.video_frame->raise(); -    ui.pose_display->setVisible(!value); -    ui.preview_checkbox->raise(); -    if (value) -        ui.preview_checkbox->setStyleSheet("QCheckBox { color: #32CD32 }"); -    else -        ui.preview_checkbox->setStyleSheet(""); -} -#endif -  void main_window::start_tracker_()  {      if (work) @@ -502,7 +471,7 @@ void main_window::start_tracker_()              options_widget->register_filter(&*work->libs.pFilter);      } -    pose_update_timer.start((int)(1000./30)); +    pose_update_timer.start(1000/30);      // NB check valid since SelectedLibraries ctor called      // trackers take care of layout state updates @@ -714,7 +683,6 @@ static void show_module_settings(std::shared_ptr<Instance> instance,                                   void(Dialog::*register_fun)(Instance*),                                   void(options_dialog::*switch_tab_fun)())  { -    using BaseDialog = plugin_api::detail::BaseDialog;      if (!lib || !lib->Dialog)          return; diff --git a/options/base-value.cpp b/options/base-value.cpp index 9ccbbdf8..950629d0 100644 --- a/options/base-value.cpp +++ b/options/base-value.cpp @@ -29,5 +29,5 @@ value_::~value_()  void value_::maybe_trace(const char* str) const  {      if (TRACE_NOTIFY) -        qDebug().noquote() << str << QThread::currentThreadId() << b->name() << self_name; +        qDebug().noquote() << str << QThread::currentThreadId() << b->name() << self_name << get_variant();  } diff --git a/options/tie.cpp b/options/tie.cpp index c2976217..adf26b53 100644 --- a/options/tie.cpp +++ b/options/tie.cpp @@ -28,8 +28,12 @@ void tie_setting(value<QString>& v, QComboBox* cb)  {      cb->setCurrentText(v);      v = cb->currentText(); -    value_::connect(cb, SIGNAL(currentTextChanged(QString)), &v, SLOT(setValue(const QString&)), v.DIRECT_CONNTYPE); -    value_::connect(&v, SIGNAL(valueChanged(const QString&)), cb, SLOT(setCurrentText(const QString&)), v.SAFE_CONNTYPE); +    auto set_current_text = [cb, &v](const QString& str) { +        cb->setCurrentText(str); +        v = cb->currentText(); +    }; +    value_::connect(cb, &QComboBox::currentTextChanged, &v, v.value_changed<QString>(), v.DIRECT_CONNTYPE); +    value_::connect(&v, v.value_changed<QString>(), cb, set_current_text, v.SAFE_CONNTYPE);  }  void tie_setting(value<QVariant>& v, QComboBox* cb) diff --git a/options/value.hpp b/options/value.hpp index dacd0ea9..9a7487b8 100644 --- a/options/value.hpp +++ b/options/value.hpp @@ -137,6 +137,7 @@ public:              return *this;          store_variant(traits::qvariant_from_value(traits::pass_value(datum))); +        maybe_trace("set-value");          return *this;      } diff --git a/proto-osc/CMakeLists.txt b/proto-osc/CMakeLists.txt new file mode 100644 index 00000000..eeaf206c --- /dev/null +++ b/proto-osc/CMakeLists.txt @@ -0,0 +1,15 @@ +set(SDK_OSCPACK "" CACHE PATH "oscpack build directory") +if(SDK_OSCPACK) +    if(WIN32) +        if(NOT EXISTS "${SDK_OSCPACK}/include/.") +            message(FATAL_ERROR "SDK_OSCPACK should have 'include' subdirectory (or symlink) to src dir") +        endif() +        link_directories("${SDK_OSCPACK}") +        include_directories("${SDK_OSCPACK}/include" "${SDK_OSCPACK}/include/oscpack") +    else() +        link_directories("${SDK_OSCPACK}/lib" "${SDK_OSCPACK}/lib32") +        include_directories("${SDK_OSCPACK}/include/oscpack") +    endif() +    link_libraries(oscpack) +    otr_module(proto-osc) +endif() diff --git a/proto-osc/dialog.cpp b/proto-osc/dialog.cpp new file mode 100644 index 00000000..54bf6885 --- /dev/null +++ b/proto-osc/dialog.cpp @@ -0,0 +1,38 @@ +#include "dialog.hpp" +#include <QHostAddress> +#include <QPalette> + +void osc_dialog::host_address_edited(const QString& str) +{ +    bool bad = QHostAddress{str}.isNull(); +    auto pal = pal_; +    for (auto role : { QPalette::Highlight, QPalette::Window }) +        if (bad) +            pal.setColor(role, Qt::red); +    ui.address->setPalette(pal); +} + +osc_dialog::osc_dialog() : +    pal_{palette()} +{ +    ui.setupUi( this ); + +    tie_setting(s.address, ui.address); +    tie_setting(s.port, ui.port); +    connect(ui.buttonBox, &QDialogButtonBox::accepted, this, &osc_dialog::doOK); +    connect(ui.buttonBox, &QDialogButtonBox::rejected, this, &osc_dialog::doCancel); +    connect(ui.address, &QLineEdit::textChanged, this, &osc_dialog::host_address_edited); +    host_address_edited(ui.address->text()); +} + +void osc_dialog::save() { s.b->save(); } +void osc_dialog::reload() { s.b->reload(); } + +void osc_dialog::doOK() { s.b->save(); close(); } +void osc_dialog::doCancel() { close(); } + +void osc_dialog::register_protocol(IProtocol*) {} +void osc_dialog::unregister_protocol() {} + +bool osc_dialog::embeddable() noexcept { return true; } +void osc_dialog::set_buttons_visible(bool x) noexcept { ui.buttonBox->setVisible(x); } diff --git a/proto-osc/dialog.hpp b/proto-osc/dialog.hpp new file mode 100644 index 00000000..29682843 --- /dev/null +++ b/proto-osc/dialog.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include "settings.hpp" +#include "ui_dialog.h" +#include "api/plugin-api.hpp" + +class osc_dialog: public IProtocolDialog +{ +    Q_OBJECT + +public: +    osc_dialog(); +    void register_protocol(IProtocol*) override; +    void unregister_protocol() override; +private: +    void set_buttons_visible(bool x) noexcept override; +    bool embeddable() noexcept override; +    void save() override; +    void reload() override; + +    Ui_OSC_Dialog ui; +    osc_settings s; +    const QPalette pal_; + +private slots: +    void doOK(); +    void doCancel(); +    void host_address_edited(const QString& str); +}; diff --git a/proto-osc/dialog.ui b/proto-osc/dialog.ui new file mode 100644 index 00000000..5a078bbd --- /dev/null +++ b/proto-osc/dialog.ui @@ -0,0 +1,131 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>OSC_Dialog</class> + <widget class="QWidget" name="OSC_Dialog"> +  <property name="windowModality"> +   <enum>Qt::NonModal</enum> +  </property> +  <property name="geometry"> +   <rect> +    <x>0</x> +    <y>0</y> +    <width>284</width> +    <height>102</height> +   </rect> +  </property> +  <property name="sizePolicy"> +   <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> +    <horstretch>0</horstretch> +    <verstretch>0</verstretch> +   </sizepolicy> +  </property> +  <property name="minimumSize"> +   <size> +    <width>284</width> +    <height>102</height> +   </size> +  </property> +  <property name="windowTitle"> +   <string>OSC protocol settings</string> +  </property> +  <property name="windowIcon"> +   <iconset resource="osc-res.qrc"> +    <normaloff>:/images/osc-icon.png</normaloff>:/images/osc-icon.png</iconset> +  </property> +  <property name="layoutDirection"> +   <enum>Qt::LeftToRight</enum> +  </property> +  <property name="autoFillBackground"> +   <bool>false</bool> +  </property> +  <layout class="QVBoxLayout" name="verticalLayout"> +   <item> +    <layout class="QFormLayout" name="formLayout_2"> +     <item row="0" column="0"> +      <widget class="QLabel" name="label"> +       <property name="text"> +        <string>Destination address</string> +       </property> +      </widget> +     </item> +     <item row="0" column="1"> +      <widget class="QLineEdit" name="address"> +       <property name="sizePolicy"> +        <sizepolicy hsizetype="Expanding" vsizetype="Maximum"> +         <horstretch>0</horstretch> +         <verstretch>0</verstretch> +        </sizepolicy> +       </property> +       <property name="text"> +        <string/> +       </property> +       <property name="maxLength"> +        <number>256</number> +       </property> +      </widget> +     </item> +     <item row="1" column="0"> +      <widget class="QLabel" name="label_2"> +       <property name="text"> +        <string>Port</string> +       </property> +      </widget> +     </item> +     <item row="1" column="1"> +      <widget class="QSpinBox" name="port"> +       <property name="sizePolicy"> +        <sizepolicy hsizetype="Minimum" vsizetype="Maximum"> +         <horstretch>0</horstretch> +         <verstretch>0</verstretch> +        </sizepolicy> +       </property> +       <property name="maximum"> +        <number>65535</number> +       </property> +      </widget> +     </item> +    </layout> +   </item> +   <item> +    <widget class="QDialogButtonBox" name="buttonBox"> +     <property name="sizePolicy"> +      <sizepolicy hsizetype="Minimum" vsizetype="Maximum"> +       <horstretch>0</horstretch> +       <verstretch>0</verstretch> +      </sizepolicy> +     </property> +     <property name="standardButtons"> +      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> +     </property> +    </widget> +   </item> +  </layout> + </widget> + <resources> +  <include location="../gui/opentrack-res.qrc"/> +  <include location="osc-res.qrc"/> + </resources> + <connections/> + <designerdata> +  <property name="gridDeltaX"> +   <number>5</number> +  </property> +  <property name="gridDeltaY"> +   <number>5</number> +  </property> +  <property name="gridSnapX"> +   <bool>true</bool> +  </property> +  <property name="gridSnapY"> +   <bool>true</bool> +  </property> +  <property name="gridVisible"> +   <bool>false</bool> +  </property> + </designerdata> + <slots> +  <slot>startEngineClicked()</slot> +  <slot>stopEngineClicked()</slot> +  <slot>cameraSettingsClicked()</slot> + </slots> +</ui> diff --git a/proto-osc/images/osc-icon.png b/proto-osc/images/osc-icon.pngBinary files differ new file mode 100644 index 00000000..3ef546e9 --- /dev/null +++ b/proto-osc/images/osc-icon.png diff --git a/proto-osc/lang/nl_NL.ts b/proto-osc/lang/nl_NL.ts new file mode 100644 index 00000000..260b7adc --- /dev/null +++ b/proto-osc/lang/nl_NL.ts @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1" language="nl_NL"> +<context> +    <name>OSC_Dialog</name> +    <message> +        <source>OSC protocol settings</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>Port</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>Destination address</source> +        <translation type="unfinished"></translation> +    </message> +</context> +<context> +    <name>osc_metadata</name> +    <message> +        <source>Open Sound Control</source> +        <translation type="unfinished"></translation> +    </message> +</context> +<context> +    <name>osc_proto</name> +    <message> +        <source>Open Sound Control</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>Error binding socket to INADDR_ANY</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>%1: %2</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>Invalid destination address '%1'</source> +        <translation type="unfinished"></translation> +    </message> +</context> +</TS> diff --git a/proto-osc/lang/ru_RU.ts b/proto-osc/lang/ru_RU.ts new file mode 100644 index 00000000..498d68d6 --- /dev/null +++ b/proto-osc/lang/ru_RU.ts @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1" language="ru_RU"> +<context> +    <name>OSC_Dialog</name> +    <message> +        <source>OSC protocol settings</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>Port</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>Destination address</source> +        <translation type="unfinished"></translation> +    </message> +</context> +<context> +    <name>osc_metadata</name> +    <message> +        <source>Open Sound Control</source> +        <translation type="unfinished"></translation> +    </message> +</context> +<context> +    <name>osc_proto</name> +    <message> +        <source>Open Sound Control</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>Error binding socket to INADDR_ANY</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>%1: %2</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>Invalid destination address '%1'</source> +        <translation type="unfinished"></translation> +    </message> +</context> +</TS> diff --git a/proto-osc/lang/stub.ts b/proto-osc/lang/stub.ts new file mode 100644 index 00000000..20828cbd --- /dev/null +++ b/proto-osc/lang/stub.ts @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1"> +<context> +    <name>OSC_Dialog</name> +    <message> +        <source>OSC protocol settings</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>Port</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>Destination address</source> +        <translation type="unfinished"></translation> +    </message> +</context> +<context> +    <name>osc_metadata</name> +    <message> +        <source>Open Sound Control</source> +        <translation type="unfinished"></translation> +    </message> +</context> +<context> +    <name>osc_proto</name> +    <message> +        <source>Open Sound Control</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>Error binding socket to INADDR_ANY</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>%1: %2</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>Invalid destination address '%1'</source> +        <translation type="unfinished"></translation> +    </message> +</context> +</TS> diff --git a/proto-osc/lang/zh_CN.ts b/proto-osc/lang/zh_CN.ts new file mode 100644 index 00000000..e0d49844 --- /dev/null +++ b/proto-osc/lang/zh_CN.ts @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1" language="zh_CN"> +<context> +    <name>OSC_Dialog</name> +    <message> +        <source>OSC protocol settings</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>Port</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>Destination address</source> +        <translation type="unfinished"></translation> +    </message> +</context> +<context> +    <name>osc_metadata</name> +    <message> +        <source>Open Sound Control</source> +        <translation type="unfinished"></translation> +    </message> +</context> +<context> +    <name>osc_proto</name> +    <message> +        <source>Open Sound Control</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>Error binding socket to INADDR_ANY</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>%1: %2</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>Invalid destination address '%1'</source> +        <translation type="unfinished"></translation> +    </message> +</context> +</TS> diff --git a/proto-osc/metadata.cpp b/proto-osc/metadata.cpp new file mode 100644 index 00000000..9d69347d --- /dev/null +++ b/proto-osc/metadata.cpp @@ -0,0 +1,8 @@ +#include "metadata.hpp" +#include "proto.hpp" +#include "dialog.hpp" + +QString osc_metadata::name() { return tr("Open Sound Control"); } +QIcon osc_metadata::icon() { return QIcon(":/images/osc-icon.png"); } + +OPENTRACK_DECLARE_PROTOCOL(osc_proto, osc_dialog, osc_metadata) diff --git a/proto-osc/metadata.hpp b/proto-osc/metadata.hpp new file mode 100644 index 00000000..c0a947aa --- /dev/null +++ b/proto-osc/metadata.hpp @@ -0,0 +1,10 @@ +#pragma once +#include "api/plugin-api.hpp" + +class osc_metadata : public Metadata +{ +    Q_OBJECT + +    QString name() override; +    QIcon icon() override; +}; diff --git a/proto-osc/osc-res.qrc b/proto-osc/osc-res.qrc new file mode 100644 index 00000000..ade4c629 --- /dev/null +++ b/proto-osc/osc-res.qrc @@ -0,0 +1,5 @@ +<RCC> +  <qresource prefix="/"> +    <file>images/osc-icon.png</file> +  </qresource> +</RCC> diff --git a/proto-osc/proto.cpp b/proto-osc/proto.cpp new file mode 100644 index 00000000..2f90957c --- /dev/null +++ b/proto-osc/proto.cpp @@ -0,0 +1,54 @@ +#include "proto.hpp" +#include "ui_dialog.h" +#include "api/plugin-api.hpp" +#include <QQuaternion> +#include <QHostAddress> +#include "osc/OscOutboundPacketStream.h" + +osc_proto::osc_proto() +{ +    auto reload_fn = [this] { +        dest = QHostAddress{s.address }; +        port = (unsigned short)s.port; +    }; +    connect(&*s.b, &bundle_::changed, this, reload_fn); +    connect(&*s.b, &bundle_::reloading, this, reload_fn); +} + +void osc_proto::pose(const double* data, const double*) +{ +    if (dest.isNull()) +        return; + +    static constexpr unsigned buffer_size = 1024; +    char buffer[buffer_size] = {}; +    osc::OutboundPacketStream p{buffer, buffer_size}; +    auto q = QQuaternion::fromEulerAngles((float)data[Pitch], (float)data[Yaw], (float)-data[Roll]).normalized(); +    p << osc::BeginMessage("/bridge/quat") << q.scalar() << q.x() << q.y() << q.z() << osc::EndMessage; +    sock.writeDatagram(p.Data(), (int)p.Size(), dest, port); +} + +module_status osc_proto::initialize() +{ +    QString error; + +    dest = QHostAddress{s.address }; +    port = (unsigned short)s.port; + +    if (dest.isNull()) +    { +        error = tr("Invalid destination address '%1'").arg(s.address); +        goto fail; +    } + +    if (!sock.bind()) +    { +        error = tr("Error binding socket to INADDR_ANY"); +        goto fail; +    } + +    return status_ok(); + +fail: +    return { tr("%1: %2").arg(error, sock.errorString()) }; +} diff --git a/proto-osc/proto.hpp b/proto-osc/proto.hpp new file mode 100644 index 00000000..53a5dee4 --- /dev/null +++ b/proto-osc/proto.hpp @@ -0,0 +1,29 @@ +#pragma once + +/* Copyright (c) 2023 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. + */ + +#include "settings.hpp" +#include "api/plugin-api.hpp" +#include <QUdpSocket> +#include <QHostAddress> + +class osc_proto : public QObject, public IProtocol +{ +    Q_OBJECT + +    osc_settings s; +    QUdpSocket sock; +    QHostAddress dest; +    unsigned short port = 0; + +public: +    osc_proto(); +    module_status initialize() override; +    void pose(const double *headpose, const double*) override; +    QString game_name() override { return tr("Open Sound Control"); } +}; diff --git a/proto-osc/settings.hpp b/proto-osc/settings.hpp new file mode 100644 index 00000000..edeb45c6 --- /dev/null +++ b/proto-osc/settings.hpp @@ -0,0 +1,14 @@ +#pragma once +#include <QString> +#include "options/options.hpp" + +using namespace options; + +struct osc_settings : opts +{ +    value<QString> address; +    value<int> port; +    osc_settings() : opts("proto-osc"), address{b, "address", "127.0.0.1"}, +        port(b, "port", 53101) +    {} +}; diff --git a/proto-wine/CMakeLists.txt b/proto-wine/CMakeLists.txt index 0beb50e1..ff4932cc 100644 --- a/proto-wine/CMakeLists.txt +++ b/proto-wine/CMakeLists.txt @@ -17,10 +17,14 @@ if(NOT WIN32)              endif()              file(GLOB wine-deps "${CMAKE_CURRENT_SOURCE_DIR}/*.cxx")              #install(FILES ${wine-deps} DESTINATION "${opentrack-src}/proto-wine") +            set(winegxx-multilib "-m32") +            if (NOT OPENTRACK_WINE_ARCH STREQUAL "") +                set(winegxx-multilib "${OPENTRACK_WINE_ARCH}") +            endif()              add_custom_command(                OUTPUT opentrack-wrapper-wine.exe.so                DEPENDS ${wine-deps} -              COMMAND wineg++ -mconsole -g -DNOMINMAX -O2 -m32 -std=c++17 -fPIC -o +              COMMAND wineg++ -mconsole -g -DNOMINMAX -O2 ${winegxx-multilib} -std=c++17 -fPIC -o                        opentrack-wrapper-wine.exe -I "${CMAKE_SOURCE_DIR}" -I "${CMAKE_BINARY_DIR}"                        ${wine-deps} -Wall -Wextra -Wpedantic                        ${my-rt}) diff --git a/proto-wine/ftnoir_protocol_wine.cpp b/proto-wine/ftnoir_protocol_wine.cpp index af53ff1f..75526c54 100644 --- a/proto-wine/ftnoir_protocol_wine.cpp +++ b/proto-wine/ftnoir_protocol_wine.cpp @@ -44,6 +44,7 @@ void wine::pose(const double *headpose, const double*)  #ifndef OTR_WINE_NO_WRAPPER          if (shm->gameid != gameid)          { +            //qDebug() << "proto/wine: looking up gameData";              QString gamename;              QMutexLocker foo(&game_name_mutex);              /* only EZCA for FSX requires dummy process, and FSX doesn't work on Linux */ @@ -63,6 +64,22 @@ module_status wine::initialize()      static const QString library_path(OPENTRACK_BASE_PATH + OPENTRACK_LIBRARY_PATH);      QString wine_path = "wine"; +    if (s.wine_select_path().toString() != "WINE") { +        // if we are not supposed to use system wine then: +        if (s.wine_select_path().toString() != "CUSTOM") { +            // if we don't have a custom path then change the wine_path to the path corresponding to the selected version +            wine_path = s.wine_select_path().toString(); +        } +        else if (!s.wine_custom_path->isEmpty()) { +            // if we do have a custom path and it is not empty then +            wine_path = s.wine_custom_path; +        } +    } +    if (wine_path[0] == '~') +        wine_path = qgetenv("HOME") + wine_path.mid(1); + +    qDebug() << "proto/wine: wine_path:" << wine_path; +      auto env = QProcessEnvironment::systemEnvironment();      if (s.variant_proton) @@ -91,6 +108,8 @@ module_status wine::initialize()          if (wineprefix[0] != '/')              return error(tr("Wine prefix must be an absolute path (given '%1')").arg(wineprefix)); +        qDebug() << "proto/wine: wineprefix:" << wineprefix; +          env.insert("WINEPREFIX", wineprefix);      } @@ -104,12 +123,24 @@ module_status wine::initialize()      wrapper.setProcessEnvironment(env);      wrapper.setWorkingDirectory(OPENTRACK_BASE_PATH);      wrapper.start(wine_path, { library_path + "opentrack-wrapper-wine.exe.so" }); +    wrapper.waitForStarted(); +    if (wrapper.state() == QProcess::ProcessState::NotRunning) { +        return error(tr("Failed to start Wine! Make sure the binary is set correctly.")); +    }  #endif      if (lck_shm.success())      {          shm = (WineSHM*) lck_shm.ptr();          memset(shm, 0, sizeof(*shm)); + +        qDebug() << "proto/wine: shm success"; + +        // display "waiting for game message" (overwritten once a game is detected) +        connected_game = "waiting for game..."; +    } +    else { +        qDebug() << "proto/wine: shm no success";      }      if (lck_shm.success()) diff --git a/proto-wine/ftnoir_protocol_wine.h b/proto-wine/ftnoir_protocol_wine.h index f7346be9..f79f65dc 100644 --- a/proto-wine/ftnoir_protocol_wine.h +++ b/proto-wine/ftnoir_protocol_wine.h @@ -26,7 +26,9 @@ struct settings : opts      value<int>     proton_appid{b, "proton-appid", 0};      value<QVariant> proton_path{b, "proton-version", {} }; -    value<QString> wineprefix{b, "wineprefix", "~/.wine"}; +    value<QVariant> wine_select_path{b, "wine-select-version", {"WINE"}}; +    value<QString> wine_custom_path{b, "wine-custom-version", ""}; +    value<QString> wineprefix{b, "wineprefix", "~/.wine/"};      value<int>     protocol{b, "protocol", 2};  }; @@ -77,6 +79,11 @@ private:      settings s;  private slots: +    void onWinePathComboUpdated(QString selection); + +    void doBrowseWine(); +    void doBrowsePrefix(); +      void doOK();      void doCancel();  }; diff --git a/proto-wine/ftnoir_protocol_wine_dialog.cpp b/proto-wine/ftnoir_protocol_wine_dialog.cpp index a954a752..07dc1469 100644 --- a/proto-wine/ftnoir_protocol_wine_dialog.cpp +++ b/proto-wine/ftnoir_protocol_wine_dialog.cpp @@ -1,9 +1,20 @@  #include "ftnoir_protocol_wine.h"  #include <QDebug> +#include <QFileDialog>  #include <QDir>  #include "api/plugin-api.hpp" +/* + * 0: path to the directory with wine versions + * 1: path from a wine version to the exectuable + * 2: name of the application using the wine versions + */ +static const char* wine_paths[][3] = { +    {"/.local/share/lutris/runners/wine/", "/bin/wine", "Lutris"}, +    {"/.var/app/net.lutris.Lutris/data/lutris/runners/wine/", "/bin/wine", "Flatpak Lutris"} +}; +  static const char* proton_paths[] = {      "/.steam/steam/steamapps/common",      "/.steam/root/compatibilitytools.d", @@ -14,6 +25,23 @@ FTControls::FTControls()  {      ui.setupUi(this); +    //populate wine select +    ui.wine_path_combo->addItem("System Wine", QVariant{"WINE"}); +    for (const char** path : wine_paths) { +        QDir dir(QDir::homePath() + path[0]); +        dir.setFilter(QDir::Dirs); +        QFileInfoList list = dir.entryInfoList(); +        for (int i = 0; i < list.size(); ++i) { +            QFileInfo fileInfo = list.at(i); +            if (fileInfo.fileName() == "." || fileInfo.fileName() == "..") continue; + +            QString name = fileInfo.fileName() + " (" + path[2] + ")"; +            ui.wine_path_combo->addItem(name, QVariant{fileInfo.filePath() + path[1]}); +        } +    } +    ui.wine_path_combo->addItem("Custom path to Wine executable", QVariant{"CUSTOM"}); + +    //populate proton select      for (const char* path : proton_paths) {          QDir dir(QDir::homePath() + path);          dir.setFilter(QDir::Dirs); @@ -24,17 +52,62 @@ FTControls::FTControls()              ui.proton_version->addItem(fileInfo.fileName(), QVariant{fileInfo.filePath()});          }      } +      tie_setting(s.proton_path, ui.proton_version);      tie_setting(s.variant_wine, ui.variant_wine);      tie_setting(s.variant_proton, ui.variant_proton);      tie_setting(s.esync, ui.esync);      tie_setting(s.fsync, ui.fsync);      tie_setting(s.proton_appid, ui.proton_appid); +    tie_setting(s.wine_select_path, ui.wine_path_combo); +    tie_setting(s.wine_custom_path, ui.wine_path);      tie_setting(s.wineprefix, ui.wineprefix);      tie_setting(s.protocol, ui.protocol_selection); +    connect(ui.wine_path_combo, &QComboBox::currentTextChanged, this, &FTControls::onWinePathComboUpdated); +    connect(ui.browse_wine_path_button, &QPushButton::clicked, this, &FTControls::doBrowseWine); +    connect(ui.browse_wine_prefix_button, &QPushButton::clicked, this, &FTControls::doBrowsePrefix);      connect(ui.buttonBox, &QDialogButtonBox::accepted, this, &FTControls::doOK);      connect(ui.buttonBox, &QDialogButtonBox::rejected, this, &FTControls::doCancel); + +    // update state of the combo box and associated ui elements +    onWinePathComboUpdated(ui.wine_path_combo->currentText()); +} + +void FTControls::onWinePathComboUpdated(QString selection) { +    // enable the custom text field if required +    if (selection == "Custom path to Wine executable") { +        ui.wine_path->setEnabled(true); +        ui.browse_wine_path_button->setEnabled(true); +    } +    else { +        ui.wine_path->setEnabled(false); +        ui.browse_wine_path_button->setEnabled(false); +    } +} + +void FTControls::doBrowseWine() { +    QFileDialog d(this); +    d.setFileMode(QFileDialog::FileMode::ExistingFile); +    d.setWindowTitle(tr("Select path to Wine Binary")); +    if (s.wine_custom_path->startsWith("~/.local/share/lutris/runners")) { +        d.selectFile(s.wine_custom_path); +    } +    if (d.exec()) { +        s.wine_custom_path = d.selectedFiles()[0]; +    } +} +void FTControls::doBrowsePrefix() { +    QFileDialog d(this); +    d.setFileMode(QFileDialog::FileMode::Directory); +    d.setOption(QFileDialog::Option::ShowDirsOnly, true); +    d.setWindowTitle(tr("Select Wine Prefix")); +    if (s.wineprefix->startsWith("/") || s.wineprefix->startsWith("~")) { +        d.selectFile(s.wineprefix); +    } +    if (d.exec()) { +        s.wineprefix = d.selectedFiles()[0]; +    }  }  void FTControls::doOK() diff --git a/proto-wine/ftnoir_winecontrols.ui b/proto-wine/ftnoir_winecontrols.ui index e9541447..365922ca 100644 --- a/proto-wine/ftnoir_winecontrols.ui +++ b/proto-wine/ftnoir_winecontrols.ui @@ -9,7 +9,7 @@     <rect>      <x>0</x>      <y>0</y> -    <width>528</width> +    <width>951</width>      <height>424</height>     </rect>    </property> @@ -33,8 +33,8 @@        <string>Wine variant</string>       </property>       <layout class="QGridLayout" name="gridLayout"> -      <item row="0" column="0"> -       <widget class="QRadioButton" name="variant_wine"> +      <item row="10" column="0"> +       <widget class="QRadioButton" name="variant_proton">          <property name="sizePolicy">           <sizepolicy hsizetype="Minimum" vsizetype="Preferred">            <horstretch>0</horstretch> @@ -42,55 +42,120 @@           </sizepolicy>          </property>          <property name="text"> -         <string>Wine (system)</string> +         <string>Proton (Steam Play)</string>          </property>         </widget>        </item> -      <item row="2" column="1" alignment="Qt::AlignRight"> -       <widget class="QComboBox" name="proton_version"> +      <item row="0" column="0"> +       <widget class="QRadioButton" name="variant_wine">          <property name="sizePolicy"> -         <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> +         <sizepolicy hsizetype="Minimum" vsizetype="Preferred">            <horstretch>0</horstretch>            <verstretch>0</verstretch>           </sizepolicy>          </property> -        <property name="minimumSize"> -         <size> -          <width>120</width> -          <height>0</height> -         </size> +        <property name="text"> +         <string>Wine (select path and prefix)</string>          </property>         </widget>        </item> -      <item row="0" column="1"> -       <widget class="QLineEdit" name="wineprefix"> +      <item row="10" column="1"> +       <widget class="QComboBox" name="proton_version">          <property name="sizePolicy"> -         <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> +         <sizepolicy hsizetype="Maximum" vsizetype="Preferred">            <horstretch>0</horstretch>            <verstretch>0</verstretch>           </sizepolicy>          </property>          <property name="minimumSize">           <size> -          <width>286</width> +          <width>120</width>            <height>0</height>           </size>          </property> -       </widget> -      </item> -      <item row="2" column="0"> -       <widget class="QRadioButton" name="variant_proton"> -        <property name="sizePolicy"> -         <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> -          <horstretch>0</horstretch> -          <verstretch>0</verstretch> -         </sizepolicy> -        </property> -        <property name="text"> -         <string>Proton (Steam Play)</string> +        <property name="layoutDirection"> +         <enum>Qt::LeftToRight</enum>          </property>         </widget>        </item> +      <item row="9" column="1"> +       <layout class="QHBoxLayout" name="horizontalLayout_4"> +        <item> +         <widget class="QLineEdit" name="wineprefix"> +          <property name="sizePolicy"> +           <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> +            <horstretch>0</horstretch> +            <verstretch>0</verstretch> +           </sizepolicy> +          </property> +          <property name="minimumSize"> +           <size> +            <width>450</width> +            <height>0</height> +           </size> +          </property> +          <property name="toolTip"> +           <string><html><head/><body><p>prefix</p></body></html></string> +          </property> +          <property name="placeholderText"> +           <string>/path_to_the_prefix/</string> +          </property> +         </widget> +        </item> +        <item> +         <widget class="QPushButton" name="browse_wine_prefix_button"> +          <property name="text"> +           <string>Browse Prefix</string> +          </property> +         </widget> +        </item> +       </layout> +      </item> +      <item row="8" column="1"> +       <layout class="QHBoxLayout" name="horizontalLayout_3"> +        <item> +         <widget class="QLineEdit" name="wine_path"> +          <property name="enabled"> +           <bool>false</bool> +          </property> +          <property name="sizePolicy"> +           <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> +            <horstretch>0</horstretch> +            <verstretch>0</verstretch> +           </sizepolicy> +          </property> +          <property name="minimumSize"> +           <size> +            <width>450</width> +            <height>0</height> +           </size> +          </property> +          <property name="toolTip"> +           <string><html><head/><body><p>wine/runner exectuable path</p></body></html></string> +          </property> +          <property name="inputMask"> +           <string/> +          </property> +          <property name="placeholderText"> +           <string/> +          </property> +         </widget> +        </item> +        <item> +         <widget class="QPushButton" name="browse_wine_path_button"> +          <property name="enabled"> +           <bool>false</bool> +          </property> +          <property name="text"> +           <string>Browse Wine Path</string> +          </property> +         </widget> +        </item> +       </layout> +      </item> +      <item row="0" column="1"> +       <widget class="QComboBox" name="wine_path_combo"/> +      </item>       </layout>      </widget>     </item> diff --git a/proto-wine/lang/nl_NL.ts b/proto-wine/lang/nl_NL.ts index e2183cc8..0298092b 100644 --- a/proto-wine/lang/nl_NL.ts +++ b/proto-wine/lang/nl_NL.ts @@ -2,17 +2,24 @@  <!DOCTYPE TS>  <TS version="2.1" language="nl_NL">  <context> -    <name>UICFTControls</name> +    <name>FTControls</name>      <message> -        <source>Wine settings</source> +        <source>Select path to Wine Binary</source>          <translation type="unfinished"></translation>      </message>      <message> -        <source>Wine variant</source> +        <source>Select Wine Prefix</source> +        <translation type="unfinished"></translation> +    </message> +</context> +<context> +    <name>UICFTControls</name> +    <message> +        <source>Wine settings</source>          <translation type="unfinished"></translation>      </message>      <message> -        <source>Wine (system)</source> +        <source>Wine variant</source>          <translation type="unfinished"></translation>      </message>      <message> @@ -55,6 +62,30 @@          <source>Both</source>          <translation type="unfinished"></translation>      </message> +    <message> +        <source>Wine (select path and prefix)</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source><html><head/><body><p>prefix</p></body></html></source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>/path_to_the_prefix/</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>Browse Prefix</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source><html><head/><body><p>wine/runner exectuable path</p></body></html></source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>Browse Wine Path</source> +        <translation type="unfinished"></translation> +    </message>  </context>  <context>      <name>wine</name> @@ -70,6 +101,10 @@          <source>Wine prefix must be an absolute path (given '%1')</source>          <translation type="unfinished"></translation>      </message> +    <message> +        <source>Failed to start Wine! Make sure the binary is set correctly.</source> +        <translation type="unfinished"></translation> +    </message>  </context>  <context>      <name>wine_metadata</name> diff --git a/proto-wine/lang/ru_RU.ts b/proto-wine/lang/ru_RU.ts index f3b44bd2..c7e9c52e 100644 --- a/proto-wine/lang/ru_RU.ts +++ b/proto-wine/lang/ru_RU.ts @@ -2,17 +2,24 @@  <!DOCTYPE TS>  <TS version="2.1" language="ru_RU">  <context> -    <name>UICFTControls</name> +    <name>FTControls</name>      <message> -        <source>Wine settings</source> +        <source>Select path to Wine Binary</source>          <translation type="unfinished"></translation>      </message>      <message> -        <source>Wine variant</source> +        <source>Select Wine Prefix</source> +        <translation type="unfinished"></translation> +    </message> +</context> +<context> +    <name>UICFTControls</name> +    <message> +        <source>Wine settings</source>          <translation type="unfinished"></translation>      </message>      <message> -        <source>Wine (system)</source> +        <source>Wine variant</source>          <translation type="unfinished"></translation>      </message>      <message> @@ -55,6 +62,30 @@          <source>Both</source>          <translation type="unfinished"></translation>      </message> +    <message> +        <source>Wine (select path and prefix)</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source><html><head/><body><p>prefix</p></body></html></source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>/path_to_the_prefix/</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>Browse Prefix</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source><html><head/><body><p>wine/runner exectuable path</p></body></html></source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>Browse Wine Path</source> +        <translation type="unfinished"></translation> +    </message>  </context>  <context>      <name>wine</name> @@ -70,6 +101,10 @@          <source>Wine prefix must be an absolute path (given '%1')</source>          <translation type="unfinished"></translation>      </message> +    <message> +        <source>Failed to start Wine! Make sure the binary is set correctly.</source> +        <translation type="unfinished"></translation> +    </message>  </context>  <context>      <name>wine_metadata</name> diff --git a/proto-wine/lang/stub.ts b/proto-wine/lang/stub.ts index dd4f946f..3366b44b 100644 --- a/proto-wine/lang/stub.ts +++ b/proto-wine/lang/stub.ts @@ -2,17 +2,24 @@  <!DOCTYPE TS>  <TS version="2.1">  <context> -    <name>UICFTControls</name> +    <name>FTControls</name>      <message> -        <source>Wine settings</source> +        <source>Select path to Wine Binary</source>          <translation type="unfinished"></translation>      </message>      <message> -        <source>Wine variant</source> +        <source>Select Wine Prefix</source> +        <translation type="unfinished"></translation> +    </message> +</context> +<context> +    <name>UICFTControls</name> +    <message> +        <source>Wine settings</source>          <translation type="unfinished"></translation>      </message>      <message> -        <source>Wine (system)</source> +        <source>Wine variant</source>          <translation type="unfinished"></translation>      </message>      <message> @@ -55,6 +62,30 @@          <source>Both</source>          <translation type="unfinished"></translation>      </message> +    <message> +        <source>Wine (select path and prefix)</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source><html><head/><body><p>prefix</p></body></html></source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>/path_to_the_prefix/</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>Browse Prefix</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source><html><head/><body><p>wine/runner exectuable path</p></body></html></source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>Browse Wine Path</source> +        <translation type="unfinished"></translation> +    </message>  </context>  <context>      <name>wine</name> @@ -70,6 +101,10 @@          <source>Wine prefix must be an absolute path (given '%1')</source>          <translation type="unfinished"></translation>      </message> +    <message> +        <source>Failed to start Wine! Make sure the binary is set correctly.</source> +        <translation type="unfinished"></translation> +    </message>  </context>  <context>      <name>wine_metadata</name> diff --git a/proto-wine/lang/zh_CN.ts b/proto-wine/lang/zh_CN.ts index b7c9ea7d..0d285c7c 100644 --- a/proto-wine/lang/zh_CN.ts +++ b/proto-wine/lang/zh_CN.ts @@ -2,17 +2,24 @@  <!DOCTYPE TS>  <TS version="2.1" language="zh_CN">  <context> -    <name>UICFTControls</name> +    <name>FTControls</name>      <message> -        <source>Wine settings</source> +        <source>Select path to Wine Binary</source>          <translation type="unfinished"></translation>      </message>      <message> -        <source>Wine variant</source> +        <source>Select Wine Prefix</source> +        <translation type="unfinished"></translation> +    </message> +</context> +<context> +    <name>UICFTControls</name> +    <message> +        <source>Wine settings</source>          <translation type="unfinished"></translation>      </message>      <message> -        <source>Wine (system)</source> +        <source>Wine variant</source>          <translation type="unfinished"></translation>      </message>      <message> @@ -55,6 +62,30 @@          <source>Both</source>          <translation type="unfinished"></translation>      </message> +    <message> +        <source>Wine (select path and prefix)</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source><html><head/><body><p>prefix</p></body></html></source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>/path_to_the_prefix/</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>Browse Prefix</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source><html><head/><body><p>wine/runner exectuable path</p></body></html></source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source>Browse Wine Path</source> +        <translation type="unfinished"></translation> +    </message>  </context>  <context>      <name>wine</name> @@ -70,6 +101,10 @@          <source>Wine prefix must be an absolute path (given '%1')</source>          <translation type="unfinished"></translation>      </message> +    <message> +        <source>Failed to start Wine! Make sure the binary is set correctly.</source> +        <translation type="unfinished"></translation> +    </message>  </context>  <context>      <name>wine_metadata</name> diff --git a/sdk-paths-runner@GNU-Linux.cmake b/sdk-paths-runner@GNU-Linux.cmake new file mode 100644 index 00000000..03c87ce4 --- /dev/null +++ b/sdk-paths-runner@GNU-Linux.cmake @@ -0,0 +1,3 @@ +set(SDK_WINE ON CACHE BOOL "" FORCE) +set(OPENTRACK_WINE_ARCH -m64 CACHE STRING "" FORCE) +set(ENV{PATH} "/usr/lib/wine:$ENV{PATH}") diff --git a/sdk-paths-sthalik@MSVC-windows.cmake b/sdk-paths-sthalik@MSVC-windows.cmake index 7df31152..340b78ad 100644 --- a/sdk-paths-sthalik@MSVC-windows.cmake +++ b/sdk-paths-sthalik@MSVC-windows.cmake @@ -18,27 +18,39 @@ function(setq name value)  endfunction()  set(opentrack_install-debug-info TRUE CACHE INTERNAL "" FORCE) -set(opentrack_maintainer-mode TRUE CACHE INTERNAL "" FORCE)  setq(EIGEN3_INCLUDE_DIR "eigen") -setq(OpenCV_DIR "opencv/build/install") -setq(SDL2_DIR "SDL2-win32") -setq(SDK_ARUCO_LIBPATH "aruco/build/src/aruco.lib") -setq(SDK_FSUIPC "fsuipc") -setq(SDK_HYDRA "SixenseSDK") +setq(SDK_RIFT_140 "ovr_sdk_win_23.0.0/LibOVR")  setq(SDK_KINECT20 "Kinect-v2.0") -setq(SDK_LIBUSB "libusb-msvc-x86") +setq(SDK_VJOYSTICK "vjoystick")  setq(SDK_PS3EYEDRIVER "PS3EYEDriver")  setq(SDK_REALSENSE "RSSDK-R2") -setq(SDK_RIFT_140 "ovr_sdk_win_23.0.0/LibOVR")  setq(SDK_VALVE_STEAMVR "steamvr") -setq(SDK_VJOYSTICK "vjoystick") -setq(ONNXRuntime_DIR "onnxruntime-1.12.1") -setq(SDK_TRACKHAT_SENSOR "../trackhat/trackhat-c-library-driver/build/install") +setq(SDK_FSUIPC "fsuipc") +setq(SDK_HYDRA "SixenseSDK") +setq(SDK_EYEWARE_BEAM "eyeware-beam-sdk") +if(CMAKE_SIZEOF_VOID_P EQUAL 8) +setq(Qt5_DIR "../qt-5.15-kde-amd64/lib/cmake/Qt5") +setq(OpenCV_DIR "opencv/build-amd64/install") +setq(SDK_ARUCO_LIBPATH "aruco/build-amd64/src/aruco.lib") +setq(SDK_LIBUSB "libusb-msvc-amd64") +setq(ONNXRuntime_DIR "onnxruntime-1.14.1-amd64") +setq(SDK_TRACKHAT_SENSOR "trackhat-c-library-driver/build-amd64/install") +setq(SDK_OSCPACK "oscpack/build-amd64") +elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) +setq(Qt5_DIR "../qt-5.15-kde/lib/cmake/Qt5") +setq(OpenCV_DIR "opencv/build/install") +setq(SDK_ARUCO_LIBPATH "aruco/build/src/aruco.lib") +setq(SDK_LIBUSB "libusb-msvc-x86") +setq(ONNXRuntime_DIR "onnxruntime-1.14.1") +setq(SDK_TRACKHAT_SENSOR "trackhat-c-library-driver/build/install") +setq(SDK_OSCPACK "oscpack/build") +else() +    message(FATAL_ERROR "unknown word size ${CMAKE_SIZEOF_VOID_P}b") +endif()  set(CMAKE_ASM_NASM_COMPILER nasm.exe CACHE FILEPATH "" FORCE) -setq(Qt5_DIR "../qt-5.15-kde/lib/cmake/Qt5")  set(Qt5Core_DIR "${Qt5_DIR}Core" CACHE PATH "" FORCE)  set(Qt5Gui_DIR "${Qt5_DIR}Gui" CACHE PATH "" FORCE) diff --git a/tracker-eyeware-beam/CMakeLists.txt b/tracker-eyeware-beam/CMakeLists.txt new file mode 100644 index 00000000..e041c131 --- /dev/null +++ b/tracker-eyeware-beam/CMakeLists.txt @@ -0,0 +1,27 @@ +# The Eyeware Beam SDK can be found at https://beam.eyeware.tech/developers/ +# The latest version can be downloaded at https://eyewarecistorage.blob.core.windows.net/beam-sdk/BeamSDK-Windows64-1.1.0.zip +set(SDK_EYEWARE_BEAM "" CACHE PATH "Eyeware Beam SDK path") +if(WIN32 AND SDK_EYEWARE_BEAM) +    if(MSVC) +        add_compile_options(-EHsc) +    endif() +    otr_module(tracker-eyeware-beam) + +    if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") +        set(arch "x86") +    else() +        set(arch "x64") +    endif() + +    target_include_directories(${self} SYSTEM PRIVATE "${SDK_EYEWARE_BEAM}/API/cpp/include") +    target_link_directories(${self} PRIVATE "${SDK_EYEWARE_BEAM}/API/cpp/lib/${arch}") +    set(dll "${SDK_EYEWARE_BEAM}/API/cpp/lib/${arch}/tracker_client.dll") +    set(lib tracker_client.lib) + +    #message(${self}) +    #message(${dll}) +    #message(${lib}) + +    target_link_libraries(${self} ${lib}) +    install(FILES ${dll} DESTINATION ${opentrack-libexec}) +endif() diff --git a/tracker-eyeware-beam/eyeware_beam.cpp b/tracker-eyeware-beam/eyeware_beam.cpp new file mode 100644 index 00000000..f48b5d4d --- /dev/null +++ b/tracker-eyeware-beam/eyeware_beam.cpp @@ -0,0 +1,116 @@ +/* Copyright (c) 2023 Eyeware Tech SA https://www.eyeware.tech + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#include "eyeware_beam.h" + +#include <QMutexLocker> + +static constexpr double rad_to_deg = 180.0 / M_PI; +static constexpr double m_to_cm = 100.0; +static constexpr double epsilon = 0.000001; + +eyeware_beam_tracker::eyeware_beam_tracker() +{ +} + +eyeware_beam_tracker::~eyeware_beam_tracker() +{ +    QMutexLocker lck(&mtx); +    release_tracker_instance(tracker_client); +    tracker_client = nullptr; +} + +module_status eyeware_beam_tracker::start_tracker(QFrame* videoframe) +{ +    QMutexLocker lck(&mtx); +    try +    { +        tracker_client = create_tracker_instance("127.0.0.1", 12010); +    } +    catch (...) +    { +        return error("Eyeware Beam initialization has failed"); +    } + +    return status_ok(); +} + +void eyeware_beam_tracker::extract_translation(const eyeware::Vector3D& t, +                                               double& translation_x_cm, +                                               double& translation_y_cm, +                                               double& translation_z_cm) +{ +    translation_x_cm = +t.x * m_to_cm; +    translation_y_cm = -t.y * m_to_cm; +    translation_z_cm = +t.z * m_to_cm; +} + +void eyeware_beam_tracker::extract_rotation_angles(const eyeware::Matrix3x3& R, +                                                   double& pitch_deg, +                                                   double& roll_deg, +                                                   double& yaw_deg) +{ +    double r00 = static_cast<double>(R[0][0]); +    double r01 = static_cast<double>(R[0][1]); +    double r02 = static_cast<double>(R[0][2]); +    double r10 = static_cast<double>(R[1][0]); +    double r11 = static_cast<double>(R[1][1]); +    double r12 = static_cast<double>(R[1][2]); +    double r20 = static_cast<double>(R[2][0]); +    double r21 = static_cast<double>(R[2][1]); +    double r22 = static_cast<double>(R[2][2]); + +    double dy = std::sqrt(r00 * r00 + r10 * r10); +    last_yaw_deg = -std::atan2(-r20, dy) * rad_to_deg; +    last_roll_deg = 0.0; +    if (dy > epsilon) +    { +        last_pitch_deg = -std::atan2(r21, r22) * rad_to_deg; +        last_roll_deg = +std::atan2(r10, r00) * rad_to_deg; +    } +    else +    { +        last_pitch_deg = -std::atan2(-r12, r11) * rad_to_deg; +    } +} + +void eyeware_beam_tracker::data(double *data) +{ +     QMutexLocker lck(&mtx); + +     if (connected(tracker_client)) +     { +         eyeware::HeadPoseInfo head_pose_info = get_head_pose_info(tracker_client); +         if (!head_pose_info.is_lost) +         { +             extract_translation(head_pose_info.transform.translation, last_translation_x_cm, +                                 last_translation_y_cm, last_translation_z_cm); +             extract_rotation_angles(head_pose_info.transform.rotation, last_pitch_deg, last_roll_deg, last_yaw_deg); +         } +     } + +     data[TX] = last_translation_x_cm; +     data[TY] = last_translation_y_cm; +     data[TZ] = last_translation_z_cm; +     data[Yaw] = last_yaw_deg; +     data[Pitch] = last_pitch_deg; +     data[Roll] = last_roll_deg; +} + +eyeware_beam_dialog::eyeware_beam_dialog() +{ +    ui.setupUi(this); + +    connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(doOK())); +} + +void eyeware_beam_dialog::doOK() +{ +    close(); +} + +OPENTRACK_DECLARE_TRACKER(eyeware_beam_tracker, eyeware_beam_dialog, eyeware_beam_metadata) diff --git a/tracker-eyeware-beam/eyeware_beam.h b/tracker-eyeware-beam/eyeware_beam.h new file mode 100644 index 00000000..9ebf1f3c --- /dev/null +++ b/tracker-eyeware-beam/eyeware_beam.h @@ -0,0 +1,70 @@ +/* Copyright (c) 2023 Eyeware Tech SA https://www.eyeware.tech + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#pragma once + +#include "api/plugin-api.hpp" + +#include "ui_eyeware_beam.h" + +#include "eyeware/tracker_client.h" + +#include <QObject> +#include <QMutex> + +class eyeware_beam_tracker : public QObject, public ITracker +{ +    Q_OBJECT + +public: +    eyeware_beam_tracker(); +    ~eyeware_beam_tracker() override; +    module_status start_tracker(QFrame* frame) override; +    void data(double *data) override; + +private: +    void extract_translation(const eyeware::Vector3D& t, +                             double& translation_x_cm, +                             double& translation_y_cm, +                             double& translation_z_cm); +    void extract_rotation_angles(const eyeware::Matrix3x3& R, double& pitch_deg, double& roll_deg, double& yaw_deg); + +    eyeware::TrackerClient* tracker_client = nullptr; + +    QMutex mtx; + +    double last_pitch_deg = 0.0; +    double last_roll_deg = 0.0; +    double last_yaw_deg = 0.0; +    double last_translation_x_cm = 0.0; +    double last_translation_y_cm = 0.0; +    double last_translation_z_cm = 0.0; +}; + +class eyeware_beam_dialog : public ITrackerDialog +{ +    Q_OBJECT + +public: +    eyeware_beam_dialog(); +    void register_tracker(ITracker * x) override { tracker = static_cast<eyeware_beam_tracker*>(x); } +    void unregister_tracker() override { tracker = nullptr; } + +private: +    Ui::eyeware_beam_ui ui; +    eyeware_beam_tracker* tracker = nullptr; + +private Q_SLOTS: +    void doOK(); +}; + +class eyeware_beam_metadata : public Metadata +{ +    Q_OBJECT +    QString name() override { return QString("Eyeware Beam"); } +    QIcon icon() override { return QIcon(":/images/eyeware_beam_logo.png"); } +}; diff --git a/tracker-eyeware-beam/eyeware_beam.qrc b/tracker-eyeware-beam/eyeware_beam.qrc new file mode 100644 index 00000000..ae20865e --- /dev/null +++ b/tracker-eyeware-beam/eyeware_beam.qrc @@ -0,0 +1,5 @@ +<RCC> +    <qresource prefix="/images"> +        <file>eyeware_beam_logo.png</file> +    </qresource> +</RCC> diff --git a/tracker-eyeware-beam/eyeware_beam.ui b/tracker-eyeware-beam/eyeware_beam.ui new file mode 100644 index 00000000..475db6a0 --- /dev/null +++ b/tracker-eyeware-beam/eyeware_beam.ui @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>eyeware_beam_ui</class> + <widget class="QWidget" name="eyeware_beam_ui"> +  <property name="windowModality"> +   <enum>Qt::NonModal</enum> +  </property> +  <property name="geometry"> +   <rect> +    <x>0</x> +    <y>0</y> +    <width>433</width> +    <height>180</height> +   </rect> +  </property> +  <property name="sizePolicy"> +   <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> +    <horstretch>0</horstretch> +    <verstretch>0</verstretch> +   </sizepolicy> +  </property> +  <property name="windowTitle"> +   <string>Eyeware Beam</string> +  </property> +  <property name="windowIcon"> +   <iconset resource="eyeware_beam.qrc"> +    <normaloff>:/images/eyeware_beam_logo.png</normaloff>:/images/eyeware_beam_logo.png</iconset> +  </property> +  <property name="layoutDirection"> +   <enum>Qt::LeftToRight</enum> +  </property> +  <property name="autoFillBackground"> +   <bool>false</bool> +  </property> +  <layout class="QVBoxLayout" name="verticalLayout"> +   <item> +    <widget class="QFrame" name="frame_2"> +     <property name="frameShadow"> +      <enum>QFrame::Raised</enum> +     </property> +     <layout class="QVBoxLayout" name="verticalLayout_2"> +      <item> +       <widget class="QLabel" name="label"> +        <property name="sizePolicy"> +         <sizepolicy hsizetype="Minimum" vsizetype="Maximum"> +          <horstretch>0</horstretch> +          <verstretch>0</verstretch> +         </sizepolicy> +        </property> +        <property name="text"> +         <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Please make sure the Eyeware Beam application is running and tracking is active.</p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To download, visit <a href="https://beam.eyeware.tech/opentrack"><span style=" text-decoration: underline; color:#0000ff;">https://beam.eyeware.tech/opentrack</span></a>.</p></body></html></string> +        </property> +        <property name="openExternalLinks"> +         <bool>true</bool> +        </property> +       </widget> +      </item> +     </layout> +    </widget> +   </item> +   <item> +    <widget class="QDialogButtonBox" name="buttonBox"> +     <property name="sizePolicy"> +      <sizepolicy hsizetype="Minimum" vsizetype="Maximum"> +       <horstretch>0</horstretch> +       <verstretch>0</verstretch> +      </sizepolicy> +     </property> +     <property name="standardButtons"> +      <set>QDialogButtonBox::Ok</set> +     </property> +    </widget> +   </item> +  </layout> + </widget> + <resources> +  <include location="eyeware_beam.qrc"/> + </resources> + <connections/> + <slots> +  <slot>startEngineClicked()</slot> +  <slot>stopEngineClicked()</slot> +  <slot>cameraSettingsClicked()</slot> + </slots> +</ui> diff --git a/tracker-eyeware-beam/eyeware_beam_logo.png b/tracker-eyeware-beam/eyeware_beam_logo.pngBinary files differ new file mode 100644 index 00000000..6a611cac --- /dev/null +++ b/tracker-eyeware-beam/eyeware_beam_logo.png diff --git a/tracker-eyeware-beam/lang/nl_NL.ts b/tracker-eyeware-beam/lang/nl_NL.ts new file mode 100644 index 00000000..d70f58ed --- /dev/null +++ b/tracker-eyeware-beam/lang/nl_NL.ts @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1" language="nl_NL"> +<context> +    <name>eyeware_beam_ui</name> +    <message> +        <source>Eyeware Beam</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Please make sure the Eyeware Beam application is running and tracking is active.</p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To download, visit <a href="https://beam.eyeware.tech/opentrack"><span style=" text-decoration: underline; color:#0000ff;">https://beam.eyeware.tech/opentrack</span></a>.</p></body></html></source> +        <translation type="unfinished"></translation> +    </message> +</context> +</TS> diff --git a/tracker-eyeware-beam/lang/ru_RU.ts b/tracker-eyeware-beam/lang/ru_RU.ts new file mode 100644 index 00000000..0bff47ae --- /dev/null +++ b/tracker-eyeware-beam/lang/ru_RU.ts @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1" language="ru_RU"> +<context> +    <name>eyeware_beam_ui</name> +    <message> +        <source>Eyeware Beam</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Please make sure the Eyeware Beam application is running and tracking is active.</p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To download, visit <a href="https://beam.eyeware.tech/opentrack"><span style=" text-decoration: underline; color:#0000ff;">https://beam.eyeware.tech/opentrack</span></a>.</p></body></html></source> +        <translation type="unfinished"></translation> +    </message> +</context> +</TS> diff --git a/tracker-eyeware-beam/lang/stub.ts b/tracker-eyeware-beam/lang/stub.ts new file mode 100644 index 00000000..c64ff83e --- /dev/null +++ b/tracker-eyeware-beam/lang/stub.ts @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1"> +<context> +    <name>eyeware_beam_ui</name> +    <message> +        <source>Eyeware Beam</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Please make sure the Eyeware Beam application is running and tracking is active.</p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To download, visit <a href="https://beam.eyeware.tech/opentrack"><span style=" text-decoration: underline; color:#0000ff;">https://beam.eyeware.tech/opentrack</span></a>.</p></body></html></source> +        <translation type="unfinished"></translation> +    </message> +</context> +</TS> diff --git a/tracker-eyeware-beam/lang/zh_CN.ts b/tracker-eyeware-beam/lang/zh_CN.ts new file mode 100644 index 00000000..aed44317 --- /dev/null +++ b/tracker-eyeware-beam/lang/zh_CN.ts @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1" language="zh_CN"> +<context> +    <name>eyeware_beam_ui</name> +    <message> +        <source>Eyeware Beam</source> +        <translation type="unfinished"></translation> +    </message> +    <message> +        <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Please make sure the Eyeware Beam application is running and tracking is active.</p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To download, visit <a href="https://beam.eyeware.tech/opentrack"><span style=" text-decoration: underline; color:#0000ff;">https://beam.eyeware.tech/opentrack</span></a>.</p></body></html></source> +        <translation type="unfinished"></translation> +    </message> +</context> +</TS> diff --git a/tracker-neuralnet/CMakeLists.txt b/tracker-neuralnet/CMakeLists.txt index f414c920..db568fae 100644 --- a/tracker-neuralnet/CMakeLists.txt +++ b/tracker-neuralnet/CMakeLists.txt @@ -1,4 +1,9 @@  include(opentrack-opencv) +set(host-spec "${CMAKE_SYSTEM_NAME} ${CMAKE_SYSTEM_PROCESSOR} ${CMAKE_SIZEOF_VOID_P}") +if(host-spec MATCHES "^Linux i[3-6]86 4$") +    return() +endif() +  find_package(OpenCV QUIET)  find_package(OpenMP QUIET) # Used to control number of onnx threads.  find_package(ONNXRuntime QUIET) @@ -11,16 +16,21 @@ if(OpenCV_FOUND AND ONNXRuntime_FOUND AND OpenMP_FOUND)      otr_module(tracker-neuralnet) -    target_link_libraries(${self}  +    target_link_libraries(${self}          opentrack-cv          onnxruntime::onnxruntime          opencv_calib3d          opencv_imgproc          opencv_imgcodecs          opencv_core -        OpenMP::OpenMP_C +        OpenMP::OpenMP_CXX          ) +    # OpenMP::OpenMP_CXX doesn't set up the -fopenmp linking option, so set it up ourselves. +    if(NOT MSVC) +        target_link_options(${self} PUBLIC ${OpenMP_CXX_FLAGS}) +    endif() +      install(          FILES "models/head-localizer.onnx"                 "models/head-pose.onnx" diff --git a/tracker-neuralnet/ftnoir_tracker_neuralnet.cpp b/tracker-neuralnet/ftnoir_tracker_neuralnet.cpp index a1a3526b..59e17063 100644 --- a/tracker-neuralnet/ftnoir_tracker_neuralnet.cpp +++ b/tracker-neuralnet/ftnoir_tracker_neuralnet.cpp @@ -13,7 +13,6 @@  #include "compat/math-imports.hpp"  #include "compat/timer.hpp"  #include "compat/check-visible.hpp" -#include "compat/camera-names.hpp"  #include "cv/init.hpp"  #include <omp.h> @@ -84,8 +83,7 @@ struct OnScopeExit  CamIntrinsics make_intrinsics(const cv::Mat& img, const Settings& settings)  {      const int w = img.cols, h = img.rows; -    //const double diag_fov = settings.fov * M_PI / 180.; -    const double diag_fov = 60 * M_PI / 180.; (void)settings; +    const double diag_fov = settings.fov * M_PI / 180.;      const double fov_w = 2.*atan(tan(diag_fov/2.)/sqrt(1. + h/(double)w * h/(double)w));      const double fov_h = 2.*atan(tan(diag_fov/2.)/sqrt(1. + w/(double)h * w/(double)h));      const double focal_length_w = 1. / tan(.5 * fov_w); @@ -353,7 +351,7 @@ bool NeuralNetTracker::detect()          last_pose_affine_ = pose_affine;      } -    draw_gizmos(*face, pose_affine); +    draw_gizmos(*face, last_pose_affine_);      return true;  } @@ -503,38 +501,17 @@ bool NeuralNetTracker::load_and_initialize_model()  bool NeuralNetTracker::open_camera()  { -#if 0      int rint = std::clamp(*settings_.resolution, 0, (int)std::size(resolution_choices)-1);      resolution_tuple res = resolution_choices[rint];      int fps = enum_to_fps(settings_.force_fps); -#endif - -    video::impl::camera::info args {}; -    args.width = 640; -    args.height = 480; -    args.fps = 60; -    args.use_mjpeg = true;      QMutexLocker l(&camera_mtx_); -    camera_ = nullptr; -    const QString name = settings_.camera_name; - -    if (name.isEmpty() || name == "TrackHat sensor") -    { -        camera_ = video::make_camera_("TrackHat sensor"); -        if (camera_ && camera_->start(args)) -            return true; -        if (!name.isEmpty()) -            return false; -    } - -    camera_ = video::make_camera(name); +    camera_ = video::make_camera(settings_.camera_name);      if (!camera_)          return false; -#if 0      video::impl::camera::info args {};      if (res.width) @@ -546,7 +523,6 @@ bool NeuralNetTracker::open_camera()          args.fps = fps;      args.use_mjpeg = settings_.use_mjpeg; -#endif      if (!camera_->start(args))      { @@ -624,8 +600,6 @@ void NeuralNetTracker::run()              std::chrono::duration_cast<std::chrono::milliseconds>(                  clk.now() - t).count()*1.e-3);      } - -    camera_ = nullptr;  } @@ -670,23 +644,19 @@ void NeuralNetTracker::update_fps(double dt)  void NeuralNetTracker::data(double *data)  { -    auto tmp2 = [&]() +    Affine tmp = [&]()      {          QMutexLocker lck(&mtx_);          return last_pose_affine_;      }(); -    if (!tmp2) -        return; -    const auto& tmp = *tmp2; -      const auto& mx = tmp.R.col(0);      const auto& my = tmp.R.col(1);      const auto& mz = -tmp.R.col(2);      const float yaw = std::atan2(mx(2), mx(0));      const float pitch = -std::atan2(-mx(1), std::sqrt(mx(2)*mx(2)+mx(0)*mx(0))); -    const float roll = -std::atan2(-my(2), mz(2)); +    const float roll = std::atan2(-my(2), mz(2));      {          constexpr double rad2deg = 180/M_PI;          data[Yaw]   = rad2deg * yaw; @@ -704,7 +674,7 @@ void NeuralNetTracker::data(double *data)  Affine NeuralNetTracker::pose()  {      QMutexLocker lck(&mtx_); -    return last_pose_affine_ ? *last_pose_affine_ : Affine{}; +    return last_pose_affine_;  }  std::tuple<cv::Size,double, double> NeuralNetTracker::stats() const @@ -715,19 +685,16 @@ std::tuple<cv::Size,double, double> NeuralNetTracker::stats() const  void NeuralNetDialog::make_fps_combobox()  { -#if 0      for (int k = 0; k < fps_MAX; k++)      {          const int hz = enum_to_fps(k);          const QString name = (hz == 0) ? tr("Default") : QString::number(hz);          ui_.cameraFPS->addItem(name, k);      } -#endif  }  void NeuralNetDialog::make_resolution_combobox()  { -#if 0      int k=0;      for (const auto [w, h] : resolution_choices)      { @@ -736,7 +703,6 @@ void NeuralNetDialog::make_resolution_combobox()              : QString::number(w) + " x " + QString::number(h);          ui_.resolution->addItem(s, k++);      } -#endif  } @@ -748,44 +714,21 @@ NeuralNetDialog::NeuralNetDialog() :      make_fps_combobox();      make_resolution_combobox(); -    ui_.cameraName->addItem(QString{});      for (const auto& str : video::camera_names())          ui_.cameraName->addItem(str);      tie_setting(settings_.camera_name, ui_.cameraName); -#if 0      tie_setting(settings_.fov, ui_.cameraFOV); -#endif      tie_setting(settings_.offset_fwd, ui_.tx_spin);      tie_setting(settings_.offset_up, ui_.ty_spin);      tie_setting(settings_.offset_right, ui_.tz_spin);      tie_setting(settings_.show_network_input, ui_.showNetworkInput);      tie_setting(settings_.roi_filter_alpha, ui_.roiFilterAlpha); -#if 0      tie_setting(settings_.use_mjpeg, ui_.use_mjpeg); -#endif  	tie_setting(settings_.roi_zoom, ui_.roiZoom);      tie_setting(settings_.num_threads, ui_.threadCount); -#if 0      tie_setting(settings_.resolution, ui_.resolution);      tie_setting(settings_.force_fps, ui_.cameraFPS); -#endif - -    { -        const struct { -            QString label; -            exposure_preset preset; -        } presets[] = { -            { QStringLiteral("Near (1-4ft)"), exposure_preset::near     }, -            { QStringLiteral("Far (4-8ft)"),  exposure_preset::far      }, -            { QStringLiteral("Custom"),       exposure_preset::ignored  }, -        }; - -        for (const auto& [label, preset] : presets) -            ui_.exposure_preset->addItem(label, int(preset)); - -        tie_setting(cs_.exposure, ui_.exposure_preset); -    }      connect(ui_.buttonBox, SIGNAL(accepted()), this, SLOT(doOK()));      connect(ui_.buttonBox, SIGNAL(rejected()), this, SLOT(doCancel())); @@ -807,13 +750,11 @@ NeuralNetDialog::NeuralNetDialog() :  void NeuralNetDialog::save()  {      settings_.b->save(); -    cs_.b->save();  }  void NeuralNetDialog::reload()  {      settings_.b->reload(); -    cs_.b->reload();  }  void NeuralNetDialog::doOK() diff --git a/tracker-neuralnet/lang/ru_RU.ts b/tracker-neuralnet/lang/ru_RU.ts index 4c9cec04..b191e769 100644 --- a/tracker-neuralnet/lang/ru_RU.ts +++ b/tracker-neuralnet/lang/ru_RU.ts @@ -5,123 +5,150 @@      <name>Form</name>      <message>          <source>Tracker settings</source> -        <translation type="unfinished"></translation> +        <translation>Настройки трекера</translation> +    </message> +    <message> +        <source>Diagonal FOV</source> +        <translation>Угол обзора</translation>      </message>      <message>          <source>Camera settings</source> -        <translation type="unfinished"></translation> +        <translation>Настройки камеры</translation> +    </message> +    <message> +        <source>Frames per second</source> +        <translation>Кадры в секунду</translation> +    </message> +    <message> +        <source>Camera name</source> +        <translation>Камера</translation> +    </message> +    <message> +        <source>Camera Configuration</source> +        <translation>Конфигурация камеры</translation>      </message>      <message>          <source>Head Center Offset</source> -        <translation type="unfinished"></translation> +        <translation>Смещение центра головы</translation>      </message>      <message>          <source> mm</source> -        <translation type="unfinished"></translation> +        <translation> мм</translation>      </message>      <message>          <source>Use only yaw and pitch while calibrating.  Don't roll or change position.</source> -        <translation type="unfinished"></translation> +        <translation>Поворачивайте голову влево-вправо и наклоняйте вверх-вниз. +Не наклоняйте набок и не смещайте голову в сторону.</translation>      </message>      <message>          <source>Start calibration</source> -        <translation type="unfinished"></translation> +        <translation>Начать калибровку</translation>      </message>      <message>          <source>Right</source> -        <translation type="unfinished"></translation> +        <translation>Вправо</translation>      </message>      <message>          <source>Forward</source> -        <translation type="unfinished"></translation> +        <translation>Вперед</translation>      </message>      <message>          <source>Up</source> -        <translation type="unfinished"></translation> +        <translation>Вверх</translation>      </message>      <message> -        <source>Exposure preset</source> -        <translation type="unfinished"></translation> +        <source>Show Network Input</source> +        <translation>Показать входные данные</translation>      </message>      <message> -        <source>Camera Configuration</source> -        <translation type="unfinished"></translation> +        <source>MJPEG</source> +        <translation>Использовать MJPEG</translation>      </message>      <message>          <source>Tuning / Debug</source> -        <translation type="unfinished"></translation> -    </message> -    <message> -        <source>Number of threads. Can be used to balance the CPU load between the game and the tracker.</source> -        <translation type="unfinished"></translation> +        <translation>Тонкая настройка</translation>      </message>      <message>          <source>ROI Smoothing Alpha</source> -        <translation type="unfinished"></translation> +        <translation>Сглаживание ROI</translation>      </message>      <message>          <source>ROI Zoom</source> -        <translation type="unfinished"></translation> +        <translation>Масштабирование ROI</translation>      </message>      <message> -        <source>Show the image patch that the pose estimation model sees.</source> -        <translation type="unfinished"></translation> +        <source>Thread Count</source> +        <translation>Количество потоков</translation>      </message>      <message> -        <source>Show Network Input</source> -        <translation type="unfinished"></translation> +        <source>Resolution</source> +        <translation>Разрешение</translation>      </message>      <message> -        <source>Amount of smoothing of the face region coordinates. Can help stabilize the pose.</source> -        <translation type="unfinished"></translation> +        <source>Field of view. Needed to transform the pose to world coordinates.</source> +        <translation>Угол обзора камеры. Требуется для преобразования положения головы в глобальные координаты</translation>      </message>      <message> -        <source>Thread Count</source> -        <translation type="unfinished"></translation> +        <source>Requested video frame rate. Actual setting may not be supported by the camera.</source> +        <translation>Частота кадров. Реальные значения могут не поддерживаться камерой.</translation>      </message>      <message> -        <source>Zoom factor for the face region. Applied before the patch is fed into the pose estimation model. There is a sweet spot near 1.</source> -        <translation type="unfinished"></translation> +        <source>The requested resolution for cases where the camera delivers maximum frame rate only for a particular resolution. The image may still be downscaled to the internal resolution.</source> +        <translation>Разрешение камеры, для тех случаев, когда быстродействие камеры максимально в определенном разрешении. Может быть масштабировано до внутреннего разрешения.</translation> +    </message> +    <message> +        <source>Number of threads. Can be used to balance the CPU load between the game and the tracker.</source> +        <translation>Количество потоков. Используется для балансировки нагрузки на процессор между игрой и трекером.</translation>      </message>      <message> -        <source>Camera override</source> -        <translation type="unfinished"></translation> +        <source>Show the image patch that the pose estimation model sees.</source> +        <translation>Показать изображение, используемое моделью определения позиции</translation> +    </message> +    <message> +        <source>Amount of smoothing of the face region coordinates. Can help stabilize the pose.</source> +        <translation>Сглаживание координат области лица. Может помочь стабилизировать позицию.</translation> +    </message> +    <message> +        <source>Zoom factor for the face region. Applied before the patch is fed into the pose estimation model. There is a sweet spot near 1.</source> +        <translation>Фактор масштабирования области лица. Применяется перед передачей кадра в модель определения позиции. Наилучшие результаты близки к 1</translation>      </message>  </context>  <context>      <name>neuralnet_tracker_ns::NeuralNetDialog</name>      <message>          <source>Default</source> -        <translation type="unfinished"></translation> +        <translation>По умолчанию</translation>      </message>      <message>          <source>Tracker Offline</source> -        <translation type="unfinished"></translation> +        <translation>Трекер выключен</translation>      </message>      <message>          <source>%1x%2 @ %3 FPS / Inference: %4 ms</source> -        <translation type="unfinished"></translation> +        <translation>%1x%2 @ %3 FPS; Время оценки: %4 мс</translation>      </message>      <message>          <source>%1 yaw samples. Yaw more to %2 samples for stable calibration.</source> -        <translation type="unfinished"></translation> +        <translation>Сэмплов поворота: %1. +Поворачивайте голову в стороны до %2 сэмплов для стабильной калибрации.</translation>      </message>      <message>          <source>%1 pitch samples. Pitch more to %2 samples for stable calibration.</source> -        <translation type="unfinished"></translation> +        <translation>Сэмплов наклона: %1. +Наклоняйте голову вниз/вверх до %2 сэмплов для стабильной калибрации.</translation>      </message>      <message>          <source>%1 samples. Over %2, good!</source> -        <translation type="unfinished"></translation> +        <translation>%1 сэмплов. Более %2, достаточно.</translation>      </message>      <message>          <source>Stop calibration</source> -        <translation type="unfinished"></translation> +        <translation>Остановить калибровку</translation>      </message>      <message>          <source>Start calibration</source> -        <translation type="unfinished"></translation> +        <translation>Начать калибровку</translation>      </message>  </context>  </TS> diff --git a/tracker-neuralnet/model_adapters.cpp b/tracker-neuralnet/model_adapters.cpp index af599321..a8580a89 100644 --- a/tracker-neuralnet/model_adapters.cpp +++ b/tracker-neuralnet/model_adapters.cpp @@ -8,7 +8,6 @@  #include <QDebug> -  namespace neuralnet_tracker_ns  { @@ -165,6 +164,24 @@ double Localizer::last_inference_time_millis() const  } +std::string PoseEstimator::get_network_input_name(size_t i) const +{ +#if ORT_API_VERSION >= 12 +    return std::string(&*session_.GetInputNameAllocated(i, allocator_)); +#else +    return std::string(session_.GetInputName(i, allocator_)); +#endif +} + +std::string PoseEstimator::get_network_output_name(size_t i) const +{ +#if ORT_API_VERSION >= 12 +    return std::string(&*session_.GetOutputNameAllocated(i, allocator_)); +#else +    return std::string(session_.GetOutputName(i, allocator_)); +#endif +} +  PoseEstimator::PoseEstimator(Ort::MemoryInfo &allocator_info, Ort::Session &&session)       : model_version_{session.GetModelMetadata().GetVersion()}      , session_{std::move(session)} @@ -215,14 +232,16 @@ PoseEstimator::PoseEstimator(Ort::MemoryInfo &allocator_info, Ort::Session &&ses      qDebug() << "Pose model inputs (" << session_.GetInputCount() << ")";      qDebug() << "Pose model outputs (" << session_.GetOutputCount() << "):"; +    output_names_.resize(session_.GetOutputCount()); +    output_c_names_.resize(session_.GetOutputCount());      for (size_t i=0; i<session_.GetOutputCount(); ++i)      { -        const char* name = session_.GetOutputName(i, allocator_); +        std::string name = get_network_output_name(i);          const auto& output_info = session_.GetOutputTypeInfo(i);          const auto& onnx_tensor_spec = output_info.GetTensorTypeAndShapeInfo();          auto my_tensor_spec = understood_outputs.find(name); -        qDebug() << "\t" << name << " (" << onnx_tensor_spec.GetShape() << ") dtype: " <<  onnx_tensor_spec.GetElementType() << " " << +        qDebug() << "\t" << name.c_str() << " (" << onnx_tensor_spec.GetShape() << ") dtype: " <<  onnx_tensor_spec.GetElementType() << " " <<              (my_tensor_spec != understood_outputs.end() ? "ok" : "unknown");          if (my_tensor_spec != understood_outputs.end()) @@ -240,7 +259,8 @@ PoseEstimator::PoseEstimator(Ort::MemoryInfo &allocator_info, Ort::Session &&ses              // Create tensor regardless and ignore output              output_val_.push_back(create_tensor(output_info, allocator_));          } -        output_names_.push_back(name); +        output_names_[i] = name; +        output_c_names_[i] = output_names_[i].c_str();      }      has_uncertainty_ = understood_outputs.at("rotaxis_scales_tril").available || @@ -270,9 +290,12 @@ PoseEstimator::PoseEstimator(Ort::MemoryInfo &allocator_info, Ort::Session &&ses      //     output_val_.push_back(create_tensor(output_info, allocator_));      // } +    input_names_.resize(session_.GetInputCount()); +    input_c_names_.resize(session_.GetInputCount());      for (size_t i = 0; i < session_.GetInputCount(); ++i)      { -        input_names_.push_back(session_.GetInputName(i, allocator_)); +        input_names_[i] = get_network_input_name(i); +        input_c_names_[i] = input_names_[i].c_str();      }      assert (input_names_.size() == input_val_.size()); @@ -312,11 +335,11 @@ std::optional<PoseEstimator::Face> PoseEstimator::run(      {          session_.Run(              Ort::RunOptions{ nullptr },  -            input_names_.data(),  +            input_c_names_.data(),              input_val_.data(),               input_val_.size(),  -            output_names_.data(),  -            output_val_.data(),  +            output_c_names_.data(), +            output_val_.data(),              output_val_.size());      }      catch (const Ort::Exception &e) @@ -430,4 +453,4 @@ double PoseEstimator::last_inference_time_millis() const -} // namespace neuralnet_tracker_ns
\ No newline at end of file +} // namespace neuralnet_tracker_ns diff --git a/tracker-neuralnet/model_adapters.h b/tracker-neuralnet/model_adapters.h index 3fbfb861..820330cf 100644 --- a/tracker-neuralnet/model_adapters.h +++ b/tracker-neuralnet/model_adapters.h @@ -3,6 +3,7 @@  #include <optional>  #include <array>  #include <vector> +#include <string>  #include <onnxruntime_cxx_api.h>  #include <opencv2/core.hpp> @@ -21,7 +22,7 @@ class Localizer      public:          Localizer(Ort::MemoryInfo &allocator_info,                      Ort::Session &&session); -         +          // Returns bounding wrt image coordinate of the input image          // The preceeding float is the score for being a face normalized to [0,1].          std::pair<float, cv::Rect2f> run( @@ -68,13 +69,16 @@ class PoseEstimator          bool has_uncertainty() const { return has_uncertainty_; }      private: +        std::string get_network_input_name(size_t i) const; +        std::string get_network_output_name(size_t i) const;          int64_t model_version_ = 0;  // Queried meta data from the ONNX file          Ort::Session session_{nullptr};  // ONNX's runtime context for running the model          Ort::Allocator allocator_;   // Memory allocator for tensors          // Inputs          cv::Mat scaled_frame_{}, input_mat_{};  // Input. One is the original crop, the other is rescaled (?)          std::vector<Ort::Value> input_val_;    // Tensors to put into the model -        std::vector<const char*> input_names_; // Refers to the names in the onnx model.  +        std::vector<std::string> input_names_; // Refers to the names in the onnx model. +        std::vector<const char *> input_c_names_; // Refers to the C names in the onnx model.          // Outputs          cv::Vec<float, 3> output_coord_{};  // 2d Coordinate and head size output.          cv::Vec<float, 4> output_quat_{};   //  Quaternion output @@ -83,7 +87,8 @@ class PoseEstimator          cv::Vec<float, 2> output_eyes_{};          cv::Vec<float, 3> output_coord_scales_{};          std::vector<Ort::Value> output_val_; // Tensors to put the model outputs in. -        std::vector<const char*> output_names_; // Refers to the names in the onnx model. +        std::vector<std::string> output_names_; // Refers to the names in the onnx model. +        std::vector<const char *> output_c_names_; // Refers to the C names in the onnx model.          // More bookkeeping          size_t num_recurrent_states_ = 0;          double last_inference_time_ = 0; @@ -99,4 +104,4 @@ int find_input_intensity_quantile(const cv::Mat& frame, float percentage);  void normalize_brightness(const cv::Mat& frame, cv::Mat& out); -} // namespace neuralnet_tracker_ns
\ No newline at end of file +} // namespace neuralnet_tracker_ns diff --git a/tracker-trackhat/lang/nl_NL.ts b/tracker-trackhat/lang/nl_NL.ts index 9cc67677..ebc53a27 100644 --- a/tracker-trackhat/lang/nl_NL.ts +++ b/tracker-trackhat/lang/nl_NL.ts @@ -147,7 +147,7 @@  <context>      <name>trackhat_module</name>      <message> -        <source>TrackHat Point Tracker</source> +        <source>TrackHat v1 Sensor</source>          <translation type="unfinished"></translation>      </message>  </context> diff --git a/tracker-trackhat/lang/ru_RU.ts b/tracker-trackhat/lang/ru_RU.ts index 844c5519..49d247be 100644 --- a/tracker-trackhat/lang/ru_RU.ts +++ b/tracker-trackhat/lang/ru_RU.ts @@ -147,7 +147,7 @@  <context>      <name>trackhat_module</name>      <message> -        <source>TrackHat Point Tracker</source> +        <source>TrackHat v1 Sensor</source>          <translation type="unfinished"></translation>      </message>  </context> diff --git a/tracker-trackhat/lang/stub.ts b/tracker-trackhat/lang/stub.ts index 127d0691..adb23557 100644 --- a/tracker-trackhat/lang/stub.ts +++ b/tracker-trackhat/lang/stub.ts @@ -147,7 +147,7 @@  <context>      <name>trackhat_module</name>      <message> -        <source>TrackHat Point Tracker</source> +        <source>TrackHat v1 Sensor</source>          <translation type="unfinished"></translation>      </message>  </context> diff --git a/tracker-trackhat/lang/zh_CN.ts b/tracker-trackhat/lang/zh_CN.ts index 179d4261..5837eeb1 100644 --- a/tracker-trackhat/lang/zh_CN.ts +++ b/tracker-trackhat/lang/zh_CN.ts @@ -147,7 +147,7 @@  <context>      <name>trackhat_module</name>      <message> -        <source>TrackHat Point Tracker</source> +        <source>TrackHat v1 Sensor</source>          <translation type="unfinished"></translation>      </message>  </context> diff --git a/video-ps3eye/shm-layout.hpp b/video-ps3eye/shm-layout.hpp index 9eee6db4..0b6c132e 100644 --- a/video-ps3eye/shm-layout.hpp +++ b/video-ps3eye/shm-layout.hpp @@ -31,12 +31,8 @@ struct shm_out  };  struct shm { -    static constexpr unsigned _cacheline_len = 64; -    static constexpr unsigned _padding_len = -        (_cacheline_len - (sizeof(shm_in) & (_cacheline_len - 1))) & (_cacheline_len - 1); -      shm_out out; -    const char* _padding[_padding_len]; +    [[maybe_unused]] const char _padding[128 - sizeof(shm_out) % 128]; // NOLINT      shm_in in;  }; diff --git a/x-plane-plugin/plugin.c b/x-plane-plugin/plugin.c index ed72e50e..e43ee0ef 100644 --- a/x-plane-plugin/plugin.c +++ b/x-plane-plugin/plugin.c @@ -134,6 +134,8 @@ static int TrackToggleHandler(XPLMCommandRef inCommand,                                XPLMCommandPhase inPhase,                                void* inRefCon)  { +    if (inPhase != xplm_CommandBegin) return 0; +      if (track_disabled)      {          //Enable @@ -156,6 +158,8 @@ static int TranslationToggleHandler(XPLMCommandRef inCommand,                                      XPLMCommandPhase inPhase,                                      void* inRefCon)  { +    if (inPhase != xplm_CommandBegin) return 0; +          translation_disabled = !translation_disabled;      if (!translation_disabled)      { | 
