summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--api/plugin-support.hpp128
-rw-r--r--bin/drmemory-suppressions.txt43
-rw-r--r--cmake/msvc.cmake2
-rw-r--r--cmake/opentrack-boilerplate.cmake17
-rw-r--r--cmake/opentrack-platform.cmake1
-rw-r--r--cmake/opentrack-policy.cmake32
-rw-r--r--cmake/opentrack-qt.cmake6
-rw-r--r--cmake/opentrack-version.cmake2
-rw-r--r--compat/CMakeLists.txt2
-rw-r--r--compat/functional.hpp86
-rw-r--r--compat/meta.hpp22
-rw-r--r--compat/time.hpp25
-rw-r--r--compat/timer-resolution.cpp55
-rw-r--r--compat/timer-resolution.hpp45
-rw-r--r--compat/timer.cpp32
-rw-r--r--compat/timer.hpp18
-rw-r--r--compat/util.hpp33
-rw-r--r--csv/CMakeLists.txt1
-rw-r--r--dinput/keybinding-worker.cpp5
-rw-r--r--filter-accela/ftnoir_filter_accela.cpp7
-rw-r--r--filter-ewma2/ftnoir_ewma_filtercontrols.ui18
-rw-r--r--filter-ewma2/ftnoir_filter_ewma2.h2
-rw-r--r--filter-ewma2/ftnoir_filter_ewma2_dialog.cpp26
-rw-r--r--gui/main-window.cpp16
-rw-r--r--gui/main-window.hpp8
-rw-r--r--gui/main.cpp4
-rw-r--r--gui/mapping-window.cpp11
-rw-r--r--logic/mappings.cpp6
-rw-r--r--logic/mappings.hpp2
-rw-r--r--logic/selected-libraries.hpp11
-rw-r--r--logic/state.hpp2
-rw-r--r--logic/tracker.cpp22
-rw-r--r--logic/tracker.h2
-rw-r--r--logic/work.cpp2
-rw-r--r--logic/work.hpp2
-rw-r--r--migration/20160906_00-mappings.cpp40
-rw-r--r--migration/migration.cpp25
-rw-r--r--options/CMakeLists.txt1
-rw-r--r--options/base-value.cpp27
-rw-r--r--options/base-value.hpp85
-rw-r--r--options/bundle.cpp28
-rw-r--r--options/bundle.hpp3
-rw-r--r--options/connector.cpp7
-rw-r--r--options/group.cpp99
-rw-r--r--options/group.hpp35
-rw-r--r--options/scoped.cpp2
-rw-r--r--options/tie.hpp17
-rw-r--r--options/value-traits.hpp50
-rw-r--r--options/value.cpp35
-rw-r--r--options/value.hpp166
-rw-r--r--pose-widget/pose-widget.cpp39
-rw-r--r--pose-widget/pose-widget.hpp4
-rw-r--r--proto-fsuipc/CMakeLists.txt2
-rw-r--r--proto-libevdev/CMakeLists.txt2
-rw-r--r--qxt-mini/CMakeLists.txt2
-rw-r--r--spline/spline-widget.cpp2
-rw-r--r--spline/spline.cpp129
-rw-r--r--spline/spline.hpp13
-rw-r--r--tracker-hatire/thread.cpp60
-rw-r--r--tracker-rs/rs_impl/CMakeLists.txt8
-rw-r--r--tracker-steamvr/steamvr.cpp13
-rw-r--r--tracker-steamvr/steamvr.hpp2
-rw-r--r--tracker-test/test.cpp6
-rw-r--r--tracker-test/test.ui25
64 files changed, 1030 insertions, 593 deletions
diff --git a/api/plugin-support.hpp b/api/plugin-support.hpp
index 2ec55f0e..1bafd6ff 100644
--- a/api/plugin-support.hpp
+++ b/api/plugin-support.hpp
@@ -8,25 +8,17 @@
#pragma once
#include "plugin-api.hpp"
-#include "options/options.hpp"
-#include <QWidget>
+#include <memory>
+#include <algorithm>
+
#include <QDebug>
#include <QString>
#include <QLibrary>
-#include <QFrame>
#include <QList>
-
-#include <cstdio>
-#include <cinttypes>
-#include <iostream>
-#include <algorithm>
-
-#include <QCoreApplication>
-#include <QFile>
#include <QDir>
#include <QList>
-#include <QStringList>
+#include <QIcon>
#if defined(__APPLE__)
# define OPENTRACK_SOLIB_EXT "dylib"
@@ -36,27 +28,25 @@
# define OPENTRACK_SOLIB_EXT "so"
#endif
-#include <iostream>
-
#ifdef _MSC_VER
# define OPENTRACK_SOLIB_PREFIX ""
#else
-# define OPENTRACK_SOLIB_PREFIX ""
+# define OPENTRACK_SOLIB_PREFIX "lib"
#endif
extern "C" typedef void* (*OPENTRACK_CTOR_FUNPTR)(void);
extern "C" typedef Metadata* (*OPENTRACK_METADATA_FUNPTR)(void);
-struct dylib final {
- enum Type : unsigned { Filter, Tracker, Protocol, Invalid = 0xcafebabeU };
+struct dylib final
+{
+ enum Type { Filter = 0xdeadbabe, Tracker = 0xcafebeef, Protocol = 0xdeadf00d, Invalid = 0xcafebabe };
dylib(const QString& filename, Type t) :
type(Invalid),
filename(filename),
Dialog(nullptr),
Constructor(nullptr),
- Meta(nullptr),
- handle(nullptr)
+ Meta(nullptr)
{
// otherwise dlopen opens the calling executable
if (filename.size() == 0)
@@ -77,7 +67,7 @@ struct dylib final {
if (check((Meta = (OPENTRACK_METADATA_FUNPTR) handle.resolve("GetMetadata"), !Meta)))
return;
- auto m = mem<Metadata>(Meta());
+ auto m = std::unique_ptr<Metadata>(Meta());
icon = m->icon();
name = m->name();
@@ -94,38 +84,42 @@ struct dylib final {
}
}
- static QList<mem<dylib>> enum_libraries(const QString& library_path)
+ static QList<std::shared_ptr<dylib>> enum_libraries(const QString& library_path)
{
- const char* filters_n[] = { OPENTRACK_SOLIB_PREFIX "opentrack-filter-*." OPENTRACK_SOLIB_EXT,
- OPENTRACK_SOLIB_PREFIX "opentrack-tracker-*." OPENTRACK_SOLIB_EXT,
- OPENTRACK_SOLIB_PREFIX "opentrack-proto-*." OPENTRACK_SOLIB_EXT,
- };
- const Type filters_t[] = { Filter, Tracker, Protocol };
-
- QDir settingsDir(library_path);
-
- QList<mem<dylib>> ret;
-
- for (int i = 0; i < 3; i++)
+ QDir module_directory(library_path);
+ QList<std::shared_ptr<dylib>> ret;
+
+ static const struct filter_ {
+ Type type;
+ QString glob;
+ } filters[] = {
+ { Filter, OPENTRACK_SOLIB_PREFIX "opentrack-filter-*." OPENTRACK_SOLIB_EXT, },
+ { Tracker, OPENTRACK_SOLIB_PREFIX "opentrack-tracker-*." OPENTRACK_SOLIB_EXT, },
+ { Protocol, OPENTRACK_SOLIB_PREFIX "opentrack-proto-*." OPENTRACK_SOLIB_EXT, },
+ };
+
+ for (const filter_& filter : filters)
{
- QString glob = filters_n[i];
- Type t = filters_t[i];
- QStringList filenames = settingsDir.entryList(QStringList { glob }, QDir::Files, QDir::Name);
-
- for (const QString& filename : filenames)
+ for (const QString& filename : module_directory.entryList({ filter.glob }, QDir::Files, QDir::Name))
{
- QIcon icon;
- QString longName;
- auto lib = std::make_shared<dylib>(library_path + filename, t);
- if (!get_metadata(lib, longName, icon))
+ std::shared_ptr<dylib> lib = std::make_shared<dylib>(QStringLiteral("%1/%2").arg(library_path).arg(filename), filter.type);
+
+ if (lib->type == Invalid)
+ {
+ qDebug() << "can't load dylib" << filename;
continue;
+ }
+
if (std::any_of(ret.cbegin(),
ret.cend(),
- [&](mem<dylib> a) {return a->type == lib->type && a->name == lib->name;}))
+ [&lib](const std::shared_ptr<dylib>& a) {
+ return a->type == lib->type && a->name == lib->name;
+ }))
{
- qDebug() << "Duplicate lib" << lib->filename;
+ qDebug() << "duplicate lib" << filename << "ident" << lib->name;
continue;
}
+
ret.push_back(lib);
}
}
@@ -161,60 +155,50 @@ private:
return fail;
}
-
- static bool get_metadata(mem<dylib> lib, QString& name, QIcon& icon)
- {
- Metadata* meta;
- if (!lib->Meta || ((meta = lib->Meta()), !meta))
- return false;
- name = meta->name();
- icon = meta->icon();
- delete meta;
- return true;
- }
};
struct Modules final
{
+ using dylib_ptr = std::shared_ptr<dylib>;
+ using dylib_list = QList<dylib_ptr>;
+
Modules(const QString& library_path) :
module_list(dylib::enum_libraries(library_path)),
filter_modules(filter(dylib::Filter)),
tracker_modules(filter(dylib::Tracker)),
protocol_modules(filter(dylib::Protocol))
{}
- QList<mem<dylib>>& filters() { return filter_modules; }
- QList<mem<dylib>>& trackers() { return tracker_modules; }
- QList<mem<dylib>>& protocols() { return protocol_modules; }
+ dylib_list& filters() { return filter_modules; }
+ dylib_list& trackers() { return tracker_modules; }
+ dylib_list& protocols() { return protocol_modules; }
private:
- QList<mem<dylib>> module_list;
- QList<mem<dylib>> filter_modules;
- QList<mem<dylib>> tracker_modules;
- QList<mem<dylib>> protocol_modules;
+ dylib_list module_list;
+ dylib_list filter_modules;
+ dylib_list tracker_modules;
+ dylib_list protocol_modules;
- template<typename t>
- static void sort(QList<t>& xs)
+ static dylib_list& sorted(dylib_list& xs)
{
- std::sort(xs.begin(), xs.end(), [&](const t& a, const t& b) { return a->name.toLower() < b->name.toLower(); });
+ std::sort(xs.begin(), xs.end(), [&](const dylib_ptr& a, const dylib_ptr& b) { return a->name.toLower() < b->name.toLower(); });
+ return xs;
}
- QList<mem<dylib>> filter(dylib::Type t)
+ dylib_list filter(dylib::Type t)
{
- QList<mem<dylib>> ret;
+ QList<std::shared_ptr<dylib>> ret;
for (auto x : module_list)
if (x->type == t)
ret.push_back(x);
- sort(ret);
-
- return ret;
+ return sorted(ret);
}
};
template<typename t>
-mem<t> make_dylib_instance(mem<dylib> lib)
+static inline std::shared_ptr<t> make_dylib_instance(const std::shared_ptr<dylib>& lib)
{
- mem<t> ret;
+ std::shared_ptr<t> ret;
if (lib != nullptr && lib->Constructor)
- ret = mem<t>(reinterpret_cast<t*>(reinterpret_cast<OPENTRACK_CTOR_FUNPTR>(lib->Constructor)()));
+ ret = std::shared_ptr<t>(reinterpret_cast<t*>(reinterpret_cast<OPENTRACK_CTOR_FUNPTR>(lib->Constructor)()));
return ret;
}
diff --git a/bin/drmemory-suppressions.txt b/bin/drmemory-suppressions.txt
new file mode 100644
index 00000000..1f94c108
--- /dev/null
+++ b/bin/drmemory-suppressions.txt
@@ -0,0 +1,43 @@
+UNADDRESSABLE ACCESS
+name=false positive 1
+Qt5Gui.dll!qt_blend_argb32_on_argb32_ssse3
+
+INVALID HEAP ARGUMENT
+name=stfu qtcore
+Qt5Core.dll!*
+
+INVALID HEAP ARGUMENT
+name=stfu qwindows 1
+qwindows.dll!*
+
+LEAK
+name=stfu qwindows 2
+qwindows.dll!*
+
+INVALID HEAP ARGUMENT
+name=stfu qtgui
+Qt5Gui.dll!*
+
+INVALID HEAP ARGUMENT
+name=stfu sixense 1
+sixense.dll!*
+
+UNADDRESSABLE ACCESS
+name=stfu sixense 2
+sixense.dll!*
+
+UNINITIALIZED READ
+name=dinput
+system call NtUserGetRawInputDeviceInfo parameter value #2
+
+LEAK
+name=stfu leak qtcore 1
+Qt5Core.dll!*
+
+LEAK
+name=cv 1
+opentrack-tracker-pt.dll!cv::`dynamic initializer for '__initialization_mutex_initializer''
+
+LEAK
+name=cv 2
+opentrack-tracker-aruco.dll!cv::`dynamic initializer for '__initialization_mutex_initializer'' \ No newline at end of file
diff --git a/cmake/msvc.cmake b/cmake/msvc.cmake
index bab3f3df..c0aee783 100644
--- a/cmake/msvc.cmake
+++ b/cmake/msvc.cmake
@@ -43,7 +43,7 @@ if(CMAKE_PROJECT_NAME STREQUAL "opentrack")
set(cc "${cc} /GR- /arch:SSE2")
endif()
-set(silly "${warns_} /MT /Gm")
+set(silly "${warns_} -MT -Gm -Zi")
set(_CFLAGS "${silly}")
set(_CXXFLAGS "${silly}")
diff --git a/cmake/opentrack-boilerplate.cmake b/cmake/opentrack-boilerplate.cmake
index 58f80573..3c5bd90a 100644
--- a/cmake/opentrack-boilerplate.cmake
+++ b/cmake/opentrack-boilerplate.cmake
@@ -75,7 +75,7 @@ endfunction()
function(otr_compat target)
if(NOT MSVC)
- set_property(SOURCE ${${target}-moc} APPEND_STRING PROPERTY COMPILE_FLAGS "-w -Wno-error")
+ set_property(SOURCE ${${target}-moc} APPEND_STRING PROPERTY COMPILE_FLAGS " -w -Wno-error")
endif()
if(WIN32)
target_link_libraries(${target} dinput8 dxguid strmiids)
@@ -84,6 +84,8 @@ function(otr_compat target)
set(c-props)
set(l-props)
+ get_property(linker-lang TARGET ${target} PROPERTY LINKER_LANGUAGE)
+
if(CMAKE_COMPILER_IS_GNUCXX)
set(c-props " -fvisibility=hidden")
if(NOT is-c-only)
@@ -95,8 +97,8 @@ function(otr_compat target)
set(l-props "-Wl,--as-needed")
endif()
- set_property(TARGET ${target} APPEND_STRING PROPERTY COMPILE_FLAGS "${c-props} ${arg_COMPILE}")
- set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS "${l-props} ${arg_LINK}")
+ set_property(TARGET ${target} APPEND_STRING PROPERTY COMPILE_FLAGS " ${c-props} ${arg_COMPILE}")
+ set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS " ${l-props} ${arg_LINK}")
endfunction()
include(CMakeParseArguments)
@@ -126,11 +128,12 @@ endfunction()
function(otr_module n_)
message(STATUS "module ${n_}")
cmake_parse_arguments(arg
- "STATIC;NO-COMPAT;BIN;EXECUTABLE;NO-QT;WIN32-CONSOLE;NO-INSTALL"
+ "STATIC;NO-COMPAT;BIN;EXECUTABLE;NO-QT;WIN32-CONSOLE;NO-INSTALL;RELINK"
"LINK;COMPILE"
"SOURCES"
${ARGN}
)
+
if(NOT "${arg_UNPARSED_ARGUMENTS}" STREQUAL "")
message(FATAL_ERROR "otr_module bad formals: ${arg_UNPARSED_ARGUMENTS}")
endif()
@@ -164,6 +167,12 @@ function(otr_module n_)
add_library(${n} ${link-mode} "${${n}-all}")
endif()
+ if(NOT arg_RELINK)
+ set_property(TARGET ${n} PROPERTY LINK_DEPENDS_NO_SHARED TRUE)
+ else()
+ set_property(TARGET ${n} PROPERTY LINK_DEPENDS_NO_SHARED FALSE)
+ endif()
+
if(NOT arg_NO-QT)
target_link_libraries(${n} ${MY_QT_LIBS})
endif()
diff --git a/cmake/opentrack-platform.cmake b/cmake/opentrack-platform.cmake
index 5bb7581a..3e0319ac 100644
--- a/cmake/opentrack-platform.cmake
+++ b/cmake/opentrack-platform.cmake
@@ -43,6 +43,7 @@ endif()
if(MSVC)
add_definitions(-DNOMINMAX -D_CRT_SECURE_NO_WARNINGS)
add_definitions(-D_ITERATOR_DEBUG_LEVEL=0 -D_HAS_ITERATOR_DEBUGGING=0 -D_SECURE_SCL=0)
+ add_definitions(-DHAS_EXCEPTIONS=0)
set(CMAKE_CXX_FLAGS "-std:c++14 ${CMAKE_CXX_FLAGS}")
if(SDK_INSTALL_DEBUG_INFO)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Zi")
diff --git a/cmake/opentrack-policy.cmake b/cmake/opentrack-policy.cmake
index 2d88e218..7ded20f7 100644
--- a/cmake/opentrack-policy.cmake
+++ b/cmake/opentrack-policy.cmake
@@ -1,27 +1,5 @@
-if(POLICY CMP0020)
- cmake_policy(SET CMP0020 NEW)
-endif()
-
-if(POLICY CMP0058)
- cmake_policy(SET CMP0058 NEW)
-endif()
-
-if(POLICY CMP0028)
- cmake_policy(SET CMP0028 NEW)
-endif()
-
-if(POLICY CMP0042)
- cmake_policy(SET CMP0042 NEW)
-endif()
-
-if(POLICY CMP0063)
- cmake_policy(SET CMP0063 NEW)
-endif()
-
-if(POLICY CMP0053)
- cmake_policy(SET CMP0053 OLD)
-endif()
-
-if(POLICY CMP0011)
- cmake_policy(SET CMP0011 NEW)
-endif()
+foreach(k CMP0020 CMP0058 CMP0028 CMP0042 CMP0063 CMP0053 CMP0011 CMP0054)
+ if(POLICY ${k})
+ cmake_policy(SET ${k} NEW)
+ endif()
+endforeach()
diff --git a/cmake/opentrack-qt.cmake b/cmake/opentrack-qt.cmake
index d6c8315b..21bc42e1 100644
--- a/cmake/opentrack-qt.cmake
+++ b/cmake/opentrack-qt.cmake
@@ -6,7 +6,11 @@ set(MY_QT_LIBS ${Qt5Core_LIBRARIES} ${Qt5Gui_LIBRARIES} ${Qt5Widgets_LIBRARIES}
if(WIN32)
foreach(i Qt5Core Qt5Gui Qt5Network Qt5SerialPort Qt5Widgets)
- install(FILES "${Qt5_DIR}/../../../bin/${i}.dll" DESTINATION .)
+ set(path "${Qt5_DIR}/../../../bin/${i}")
+ install(FILES "${path}.dll" DESTINATION .)
+ if(EXISTS "${path}.pdb")
+ install(FILES "${path}.pdb" DESTINATION "${opentrack-hier-debug}")
+ endif()
endforeach()
install(FILES "${Qt5_DIR}/../../../plugins/platforms/qwindows.dll" DESTINATION "./platforms")
endif()
diff --git a/cmake/opentrack-version.cmake b/cmake/opentrack-version.cmake
index 9cd597d3..00a5df1d 100644
--- a/cmake/opentrack-version.cmake
+++ b/cmake/opentrack-version.cmake
@@ -40,6 +40,6 @@ endif()
add_library(opentrack-version STATIC ${CMAKE_BINARY_DIR}/version.c)
if(NOT MSVC)
- set_property(TARGET opentrack-version APPEND_STRING PROPERTY COMPILE_FLAGS "-fno-lto")
+ set_property(TARGET opentrack-version APPEND_STRING PROPERTY COMPILE_FLAGS " -fno-lto")
endif()
otr_compat(opentrack-version)
diff --git a/compat/CMakeLists.txt b/compat/CMakeLists.txt
index 40850862..7655a223 100644
--- a/compat/CMakeLists.txt
+++ b/compat/CMakeLists.txt
@@ -5,5 +5,5 @@ if(NOT WIN32 AND NOT APPLE)
endif()
if(CMAKE_COMPILER_IS_GNUCXX)
- set_property(SOURCE nan.cpp APPEND_STRING PROPERTY COMPILE_FLAGS "-fno-lto -fno-fast-math -fno-finite-math-only -O0")
+ set_property(SOURCE nan.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -fno-lto -fno-fast-math -fno-finite-math-only -O0")
endif()
diff --git a/compat/functional.hpp b/compat/functional.hpp
new file mode 100644
index 00000000..893fe1a0
--- /dev/null
+++ b/compat/functional.hpp
@@ -0,0 +1,86 @@
+#pragma once
+
+#include <algorithm>
+#include <iterator>
+#include <type_traits>
+
+template<typename t>
+using remove_qualifiers = std::remove_reference_t<std::remove_cv_t<t>>;
+
+namespace functools
+{
+
+template<typename seq_, typename = void>
+struct reserver_
+{
+ static inline void maybe_reserve_space(seq_&, unsigned)
+ {
+ //qDebug() << "nada";
+ }
+};
+
+template<typename seq_>
+struct reserver_<seq_, decltype(std::declval<seq_>().reserve(0u), (void)0)>
+{
+ static inline void maybe_reserve_space(seq_& seq, unsigned sz)
+ {
+ seq.reserve(sz);
+ }
+};
+
+template<typename seq_>
+inline void maybe_reserve_space(seq_& seq, unsigned sz)
+{
+ reserver_<seq_, void>::maybe_reserve_space(seq, sz);
+}
+
+} // ns
+
+template<typename t, t value_>
+struct constant final
+{
+ using type = t;
+ constexpr type operator()() const noexcept
+ {
+ return value_;
+ }
+ static constexpr type value = value_;
+
+ constant() = delete;
+};
+
+template<typename seq_, typename F>
+auto map(F&& fun, const seq_& seq)
+{
+ using seq_type = remove_qualifiers<seq_>;
+
+ seq_type ret;
+ std::back_insert_iterator<seq_type> it = std::back_inserter(ret);
+
+ for (const auto& elt : seq)
+ it = fun(elt);
+
+ return ret;
+}
+
+template<typename seq_, typename F>
+auto remove_if_not(F&& fun, const seq_& seq)
+{
+ using namespace functools;
+
+ using seq_type = remove_qualifiers<seq_>;
+ using value_type = typename std::iterator_traits<decltype(std::begin(std::declval<seq_>()))>::value_type;
+ using fun_ret_type = decltype(fun(std::declval<const value_type&>()));
+ static_assert(std::is_convertible<fun_ret_type, bool>::value, "must return bool");
+
+ seq_type ret;
+ maybe_reserve_space(ret, seq.size());
+
+ std::back_insert_iterator<seq_type> it = std::back_inserter(ret);
+
+ for (const value_type& elt : seq)
+ if (fun(elt))
+ it = elt;
+
+ return ret;
+}
diff --git a/compat/meta.hpp b/compat/meta.hpp
index b1c1dd1a..900c515f 100644
--- a/compat/meta.hpp
+++ b/compat/meta.hpp
@@ -1,6 +1,8 @@
#pragma once
+#include <type_traits>
#include <tuple>
+#include <cstddef>
namespace meta {
@@ -29,7 +31,20 @@ namespace detail {
{
using type = inst<xs...>;
};
-}
+
+ template<typename N, N max, N pos, typename... xs>
+ struct index_sequence_
+ {
+ using part = std::integral_constant<N, pos>;
+ using type = typename index_sequence_<N, max, pos+1, xs..., part>::type;
+ };
+
+ template<typename N, N max, typename... xs>
+ struct index_sequence_<N, max, max, xs...>
+ {
+ using type = std::tuple<xs...>;
+ };
+} // ns detail
template<typename... xs>
@@ -50,4 +65,7 @@ using butlast = reverse<rest<reverse<xs...>>>;
template<typename... xs>
using last = lift<first, reverse<xs...>>;
-}
+template<std::size_t max>
+using index_sequence = typename detail::index_sequence_<std::size_t, max, std::size_t(0)>::type;
+
+} // ns meta
diff --git a/compat/time.hpp b/compat/time.hpp
new file mode 100644
index 00000000..fbe7469a
--- /dev/null
+++ b/compat/time.hpp
@@ -0,0 +1,25 @@
+#pragma once
+
+#include <chrono>
+#include <type_traits>
+
+namespace time_units {
+
+template<typename repr, typename ratio>
+using duration = std::chrono::duration<repr, ratio>;
+
+template<typename t, typename u>
+static inline constexpr auto time_cast(const u& in)
+{
+ return std::chrono::duration_cast<t>(in);
+}
+
+using secs = duration<double, std::ratio<1, 1>>;
+using secs_ = duration<long long, std::ratio<1, 1>>;
+using ms = duration<double, std::milli>;
+using ms_ = duration<long long, std::milli>;
+using us = duration<double, std::micro>;
+using us_ = duration<long long, std::micro>;
+using ns = duration<long long, std::nano>;
+
+} // ns time_units
diff --git a/compat/timer-resolution.cpp b/compat/timer-resolution.cpp
index 597ee91e..d59c250d 100644
--- a/compat/timer-resolution.cpp
+++ b/compat/timer-resolution.cpp
@@ -8,12 +8,11 @@
#include "timer-resolution.hpp"
#if defined _WIN32
-# include <windows.h>
-
# include <QLibrary>
# include <QDebug>
-typedef LONG (__stdcall *funptr_NtSetTimerResolution) (ULONG, BOOLEAN, PULONG);
+using namespace timer_impl;
+
static funptr_NtSetTimerResolution init_timer_resolution_funptr();
static funptr_NtSetTimerResolution get_funptr();
@@ -41,62 +40,72 @@ static funptr_NtSetTimerResolution init_timer_resolution_funptr()
static funptr_NtSetTimerResolution get_funptr()
{
+ // starting with C++11 static initializers are fully
+ // thread-safe and run the first time function is called
+
+ // cf. http://stackoverflow.com/questions/8102125/is-local-static-variable-initialization-thread-safe-in-c11
+
static auto ret = init_timer_resolution_funptr();
return ret;
}
-timer_resolution::timer_resolution(int msecs) : old_value(-1)
+timer_resolution::timer_resolution(int msecs) : old_value(fail_())
{
- if (msecs <= 0 || msecs > 30)
+ if (msecs <= 0 || msecs > 100)
{
qDebug() << "can't set timer resolution to" << msecs << "ms";
return;
}
- funptr_NtSetTimerResolution f = get_funptr();
- if (f == nullptr)
+ funptr_NtSetTimerResolution set_timer_res = get_funptr();
+ if (set_timer_res == nullptr)
return;
// hundredth of a nanosecond
- const ULONG value = msecs * ULONG(10000);
- NTSTATUS error = f(value, TRUE, &old_value);
- ULONG old_value_ = -1;
+ const ulong_ value = msecs * ulong_(10000);
+ ntstatus_ res;
- if (error != 0)
+ res = set_timer_res(value, true_(), &old_value);
+
+ if (res < 0)
{
- old_value = -1;
- qDebug() << "NtSetTimerResolution erred with" << error;
+ old_value = fail_();
+ qDebug() << "NtSetTimerResolution erred with" << res;
return;
}
// see if it stuck
- error = f(value, TRUE, &old_value_);
- if (error != 0)
+ ulong_ old_value_ = fail_();
+
+ res = set_timer_res(value, true_(), &old_value_);
+ if (res < 0)
{
- old_value = -1;
- qDebug() << "NtSetTimerResolution check erred with" << error;
+ old_value = fail_();
+ qDebug() << "NtSetTimerResolution check erred with" << res;
return;
}
if (old_value_ != old_value)
{
+ using t = long long;
+
qDebug() << "NtSetTimerResolution:"
<< "old value didn't stick"
- << "current resolution" << old_value_
- << "* 100 ns";
- old_value = -1;
+ << "current resolution" << (t(old_value_) * t(100))
+ << "ns";
+ old_value = fail_();
return;
}
}
timer_resolution::~timer_resolution()
{
- if (old_value != ULONG(-1))
+ if (old_value != fail_())
{
funptr_NtSetTimerResolution f = get_funptr();
- ULONG fuzz = -1;
- (void) f(old_value, TRUE, &fuzz);
+ ulong_ fuzz = fail_();
+ (void) f(old_value, true_(), &fuzz);
}
}
diff --git a/compat/timer-resolution.hpp b/compat/timer-resolution.hpp
index 5db877c0..8c18a600 100644
--- a/compat/timer-resolution.hpp
+++ b/compat/timer-resolution.hpp
@@ -3,14 +3,57 @@
#if defined _WIN32
# include "export.hpp"
+#include <type_traits>
+
+namespace timer_impl
+{
+
+// cf. https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
+// for NTSTATUS, see http://stackoverflow.com/questions/3378622/how-to-understand-the-ntstatus-nt-success-typedef-in-windows-ddk
+
+using ulong_ = unsigned long;
+using long_ = long;
+using byte_ = unsigned char;
+using boolean_ = byte_;
+
+using true_ = std::integral_constant<int, 1>;
+
+using fail_ = std::integral_constant<byte_, byte_(-1)>;
+
+// cf. http://stackoverflow.com/questions/3378622/how-to-understand-the-ntstatus-nt-success-typedef-in-windows-ddk
+
+// typedef __success(return >= 0) LONG NTSTATUS;
+
+// __success(expr) T f() : indicates whether function f succeeded or
+// not. If is true at exit, all the function's guarantees (as given
+// by other annotations) must hold. If is false at exit, the caller
+// should not expect any of the function's guarantees to hold. If not used,
+// the function must always satisfy its guarantees. Added automatically to
+// functions that indicate success in standard ways, such as by returning an
+// HRESULT.
+
+using ntstatus_ = long_;
+
+// finally what we want
+// this is equivalent to typedef syntax
+
+using funptr_NtSetTimerResolution = ntstatus_ (__stdcall *)(ulong_, boolean_, ulong_*);
+
+// RAII wrapper
+
class OTR_COMPAT_EXPORT timer_resolution final
{
- unsigned long old_value;
+ ulong_ old_value;
public:
timer_resolution(int msecs);
~timer_resolution();
};
+
+}
+
+using timer_impl::timer_resolution;
+
#else
struct timer_resolution final
{
diff --git a/compat/timer.cpp b/compat/timer.cpp
index d5052ccb..3ecdf528 100644
--- a/compat/timer.cpp
+++ b/compat/timer.cpp
@@ -7,6 +7,7 @@
*/
#include "timer.hpp"
+#include <cmath>
Timer::Timer()
{
@@ -15,17 +16,20 @@ Timer::Timer()
void Timer::start()
{
- wrap_gettime(&state);
+ gettime(&state);
}
// common
-void Timer::wrap_gettime(timespec* state)
+void Timer::gettime(timespec* state)
{
#if defined(_WIN32) || defined(__MACH__)
otr_clock_gettime(state);
+#elif defined CLOCK_MONOTONIC
+ const int res = clock_gettime(CLOCK_MONOTONIC, state);
+ assert(res == 0 && "must support CLOCK_MONOTONIC");
#else
- (void) clock_gettime(CLOCK_MONOTONIC, state);
+# error "timer query method not known"
#endif
}
@@ -33,14 +37,13 @@ void Timer::wrap_gettime(timespec* state)
long long Timer::elapsed_nsecs() const
{
- struct timespec cur = {};
- wrap_gettime(&cur);
+ timespec cur{};
+ gettime(&cur);
return conv_nsecs(cur);
}
long long Timer::conv_nsecs(const timespec& cur) const
{
- // this can and will overflow
return (cur.tv_sec - state.tv_sec) * 1000000000LL + (cur.tv_nsec - state.tv_nsec);
}
@@ -48,8 +51,8 @@ long long Timer::conv_nsecs(const timespec& cur) const
double Timer::elapsed_usecs() const
{
- struct timespec cur = {};
- wrap_gettime(&cur);
+ timespec cur{};
+ gettime(&cur);
const long long nsecs = conv_nsecs(cur);
return nsecs * 1e-3;
}
@@ -73,27 +76,26 @@ double Timer::elapsed_seconds() const
#if defined _WIN32
LARGE_INTEGER Timer::otr_get_clock_frequency()
{
- LARGE_INTEGER freq = {};
+ LARGE_INTEGER freq{};
(void) QueryPerformanceFrequency(&freq);
return freq;
}
void Timer::otr_clock_gettime(timespec* ts)
{
- static LARGE_INTEGER freq = otr_get_clock_frequency();
+ static const LARGE_INTEGER freq = otr_get_clock_frequency();
LARGE_INTEGER d;
(void) QueryPerformanceCounter(&d);
using ll = long long;
- using ld = long double;
- const long long part = ll(d.QuadPart / ld(freq.QuadPart) * 1000000000.L);
+ const ll part = ll(std::roundl((d.QuadPart * 1000000000.L) / ll(freq.QuadPart)));
using t_s = decltype(ts->tv_sec);
using t_ns = decltype(ts->tv_nsec);
- ts->tv_sec = t_s(part / 1000000000LL);
- ts->tv_nsec = t_ns(part % 1000000000LL);
+ ts->tv_sec = t_s(part / 1000000000);
+ ts->tv_nsec = t_ns(part % 1000000000);
}
#elif defined __MACH__
@@ -106,7 +108,7 @@ mach_timebase_info_data_t Timer::otr_get_mach_frequency()
double Timer::otr_clock_gettime(timespec* ts)
{
- static mach_timebase_info_data_t timebase_info = otr_get_mach_frequency();
+ static const mach_timebase_info_data_t timebase_info = otr_get_mach_frequency();
uint64_t state, nsec;
state = mach_absolute_time();
nsec = state * timebase_info.numer / timebase_info.denom;
diff --git a/compat/timer.hpp b/compat/timer.hpp
index e9efba79..58e1c7d6 100644
--- a/compat/timer.hpp
+++ b/compat/timer.hpp
@@ -20,7 +20,9 @@
#include <ctime>
#include <tuple>
-class OTR_COMPAT_EXPORT Timer
+#include "time.hpp"
+
+class OTR_COMPAT_EXPORT Timer final
{
struct timespec state;
long long conv_nsecs(const struct timespec& cur) const;
@@ -31,16 +33,22 @@ class OTR_COMPAT_EXPORT Timer
static mach_timebase_info_data_t otr_get_mach_frequency();
#endif
- static void wrap_gettime(struct timespec* state);
+ static void gettime(struct timespec* state);
+ using ns = time_units::ns;
public:
Timer();
-
void start();
+
+ template<typename t>
+ t elapsed() const
+ {
+ using namespace time_units;
+ return static_cast<const t&>(ns(elapsed_nsecs()));
+ }
+
long long elapsed_nsecs() const;
double elapsed_usecs() const;
double elapsed_ms() const;
double elapsed_seconds() const;
};
-
-
diff --git a/compat/util.hpp b/compat/util.hpp
index b904978b..823b83d1 100644
--- a/compat/util.hpp
+++ b/compat/util.hpp
@@ -3,6 +3,7 @@
#include "ndebug-guard.hpp"
#include "run-in-thread.hpp"
#include "meta.hpp"
+#include "functional.hpp"
#include <memory>
#include <cmath>
@@ -12,10 +13,14 @@
#include <QDebug>
#define progn(...) ([&]() { __VA_ARGS__ }())
+#define prog1(x, ...) (([&]() { auto _ret1324 = (x); do { __VA_ARGS__; } while (0); return _ret1324; })())
#define once_only(...) progn(static bool once = false; if (!once) { once = true; __VA_ARGS__; })
-
-#define load_time_value(x) progn(static const auto _value132((x)); return _value132;)
+#define load_time_value(x) \
+ progn( \
+ static const auto _value132((x)); \
+ return static_cast<decltype(_value132)&>(value132); \
+ )
template<typename t> using mem = std::shared_ptr<t>;
template<typename t> using ptr = std::unique_ptr<t>;
@@ -40,20 +45,34 @@ template<typename t> using ptr = std::unique_ptr<t>;
# define unused_on_unix(t, i) t i
#endif
+#if defined __GNUC__
+# define likely(x) __builtin_expect((x),1)
+# define unlikely(x) __builtin_expect((x),0)
+#else
+# define likely(x) (x)
+# define unlikely(x) (x)
+#endif
+
template<typename t>
-int iround(const t& val)
+inline int iround(const t& val)
{
return int(std::round(val));
}
+template<typename t>
+inline unsigned uround(const t& val)
+{
+ return std::round(std::fmax(t(0), val));
+}
+
namespace util_detail {
template<typename n>
inline auto clamp_(n val, n min, n max) -> n
{
- if (val > max)
+ if (unlikely(val > max))
return max;
- if (val < min)
+ if (unlikely(val < min))
return min;
return val;
}
@@ -61,9 +80,9 @@ inline auto clamp_(n val, n min, n max) -> n
}
template<typename t, typename u, typename w>
-inline auto clamp(const t& val, const u& min, const w& max) -> decltype(val * min * max)
+inline auto clamp(const t& val, const u& min, const w& max) -> decltype(val + min + max)
{
- return ::util_detail::clamp_<decltype(val * min * max)>(val, min, max);
+ return ::util_detail::clamp_<decltype(val + min + max)>(val, min, max);
}
template<typename t, typename... xs>
diff --git a/csv/CMakeLists.txt b/csv/CMakeLists.txt
index 82595688..177db52e 100644
--- a/csv/CMakeLists.txt
+++ b/csv/CMakeLists.txt
@@ -1,2 +1 @@
otr_module(csv)
-target_link_libraries(opentrack-csv opentrack-api)
diff --git a/dinput/keybinding-worker.cpp b/dinput/keybinding-worker.cpp
index b94b762e..0e16ac71 100644
--- a/dinput/keybinding-worker.cpp
+++ b/dinput/keybinding-worker.cpp
@@ -9,6 +9,7 @@
#ifdef _WIN32
#include "keybinding-worker.hpp"
+#include "compat/util.hpp"
#include <functional>
#include <windows.h>
#include <QDebug>
@@ -18,8 +19,8 @@ bool Key::should_process()
{
if (!enabled || (keycode == 0 && guid == ""))
return false;
- bool ret = !held || timer.elapsed_ms() > 100;
- timer.start();
+ bool ret = prog1(!held || timer.elapsed_ms() > 100,
+ timer.start());
return ret;
}
diff --git a/filter-accela/ftnoir_filter_accela.cpp b/filter-accela/ftnoir_filter_accela.cpp
index 3f78c7a6..b8a0ac77 100644
--- a/filter-accela/ftnoir_filter_accela.cpp
+++ b/filter-accela/ftnoir_filter_accela.cpp
@@ -32,6 +32,7 @@ static inline constexpr T signum(T x)
}
template<int N = 3, typename F>
+OTR_NEVER_INLINE
static void do_deltas(const double* deltas, double* output, double alpha, double& smoothed, F&& fun)
{
double norm[N];
@@ -152,6 +153,12 @@ void accela::filter(const double* input, double *output)
{
output[k] *= dt;
output[k] += last_output[k];
+
+ if (signum(last_output[k] - output[k]) < 0)
+ output[k] = std::fmax(input[k], output[k]);
+ else
+ output[k] = std::fmin(input[k], output[k]);
+
last_output[k] = output[k];
}
}
diff --git a/filter-ewma2/ftnoir_ewma_filtercontrols.ui b/filter-ewma2/ftnoir_ewma_filtercontrols.ui
index d5cc082e..e0a98174 100644
--- a/filter-ewma2/ftnoir_ewma_filtercontrols.ui
+++ b/filter-ewma2/ftnoir_ewma_filtercontrols.ui
@@ -23,7 +23,7 @@
<string>EWMA filter settings</string>
</property>
<property name="windowIcon">
- <iconset resource="../gui/ui-res.qrc">
+ <iconset resource="../gui/opentrack-res.qrc">
<normaloff>:/images/filter-16.png</normaloff>:/images/filter-16.png</iconset>
</property>
<property name="layoutDirection">
@@ -73,7 +73,7 @@
<number>0</number>
</property>
<property name="maximum">
- <number>1000</number>
+ <number>990</number>
</property>
<property name="singleStep">
<number>5</number>
@@ -82,7 +82,7 @@
<number>50</number>
</property>
<property name="value">
- <number>1000</number>
+ <number>990</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
@@ -123,10 +123,10 @@
</sizepolicy>
</property>
<property name="minimum">
- <number>1</number>
+ <number>0</number>
</property>
<property name="maximum">
- <number>1000</number>
+ <number>990</number>
</property>
<property name="singleStep">
<number>5</number>
@@ -135,7 +135,7 @@
<number>50</number>
</property>
<property name="value">
- <number>1000</number>
+ <number>980</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
@@ -173,7 +173,7 @@
<number>0</number>
</property>
<property name="maximum">
- <number>1000</number>
+ <number>2450</number>
</property>
<property name="singleStep">
<number>5</number>
@@ -182,7 +182,7 @@
<number>50</number>
</property>
<property name="value">
- <number>1000</number>
+ <number>490</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
@@ -287,7 +287,7 @@ p, li { white-space: pre-wrap; }
</layout>
</widget>
<resources>
- <include location="../gui/ui-res.qrc"/>
+ <include location="../gui/opentrack-res.qrc"/>
</resources>
<connections/>
<slots>
diff --git a/filter-ewma2/ftnoir_filter_ewma2.h b/filter-ewma2/ftnoir_filter_ewma2.h
index 8babc540..f8c77280 100644
--- a/filter-ewma2/ftnoir_filter_ewma2.h
+++ b/filter-ewma2/ftnoir_filter_ewma2.h
@@ -19,7 +19,6 @@ struct settings : opts {
{}
};
-
class ewma : public IFilter
{
public:
@@ -54,7 +53,6 @@ private:
private slots:
void doOK();
void doCancel();
- void update_labels(int);
};
class ewmaDll : public Metadata
diff --git a/filter-ewma2/ftnoir_filter_ewma2_dialog.cpp b/filter-ewma2/ftnoir_filter_ewma2_dialog.cpp
index ad07737b..55e9782e 100644
--- a/filter-ewma2/ftnoir_filter_ewma2_dialog.cpp
+++ b/filter-ewma2/ftnoir_filter_ewma2_dialog.cpp
@@ -1,7 +1,10 @@
#include "ftnoir_filter_ewma2.h"
+
#include <cmath>
+
#include <QDebug>
#include <QString>
+
#include "api/plugin-api.hpp"
#include "ui_ftnoir_ewma_filtercontrols.h"
@@ -16,17 +19,23 @@ dialog_ewma::dialog_ewma()
tie_setting(s.kMinSmoothing, ui.minSmooth);
tie_setting(s.kSmoothingScaleCurve, ui.powCurve);
- connect(ui.powCurve, &QSlider::valueChanged, this, &dialog_ewma::update_labels);
- connect(ui.minSmooth, &QSlider::valueChanged, this, &dialog_ewma::update_labels);
- connect(ui.maxSmooth, &QSlider::valueChanged, this, &dialog_ewma::update_labels);
+ tie_setting(s.kSmoothingScaleCurve, ui.curve_label,
+ [](auto& x) { return x * 100; },
+ "%1%", 0, 'f', 2);
+
+ tie_setting(s.kMinSmoothing, ui.min_label,
+ [](auto& x) { return x * 100; },
+ "%1%", 0, 'f', 2);
+
+ tie_setting(s.kMaxSmoothing, ui.max_label,
+ [](auto& x) { return x * 100; },
+ "%1%", 0, 'f', 2);
connect(ui.minSmooth, &QSlider::valueChanged, this,
[&](int v) -> void { if (ui.maxSmooth->value() < v) ui.maxSmooth->setValue(v); });
connect(ui.maxSmooth, &QSlider::valueChanged, this,
[&](int v) -> void { if (ui.minSmooth->value() > v) ui.minSmooth->setValue(v); });
-
- update_labels(0);
}
void dialog_ewma::doOK()
@@ -39,10 +48,3 @@ void dialog_ewma::doCancel()
{
close();
}
-
-void dialog_ewma::update_labels(int)
-{
- ui.curve_label->setText(QString::number(static_cast<slider_value>(s.kSmoothingScaleCurve).cur() * 100, 'f', 2) + "%");
- ui.min_label->setText(QString::number(static_cast<slider_value>(s.kMinSmoothing).cur() * 100, 'f', 2) + "%");
- ui.max_label->setText(QString::number(static_cast<slider_value>(s.kMaxSmoothing).cur() * 100, 'f', 2) + "%");
-}
diff --git a/gui/main-window.cpp b/gui/main-window.cpp
index d64858c4..aa8e16f3 100644
--- a/gui/main-window.cpp
+++ b/gui/main-window.cpp
@@ -74,13 +74,13 @@ MainWindow::MainWindow() :
{
modules.filters().push_front(std::make_shared<dylib>("", dylib::Filter));
- for (mem<dylib>& x : modules.trackers())
+ for (std::shared_ptr<dylib>& x : modules.trackers())
ui.iconcomboTrackerSource->addItem(x->icon, x->name);
- for (mem<dylib>& x : modules.protocols())
+ for (std::shared_ptr<dylib>& x : modules.protocols())
ui.iconcomboProtocol->addItem(x->icon, x->name);
- for (mem<dylib>& x : modules.filters())
+ for (std::shared_ptr<dylib>& x : modules.filters())
ui.iconcomboFilter->addItem(x->icon, x->name);
}
@@ -277,6 +277,14 @@ void MainWindow::die_on_config_not_writable()
bool MainWindow::maybe_die_on_config_not_writable(const QString& current, QStringList* ini_list_)
{
+ const bool writable =
+ group::with_settings_object([&](QSettings& s) {
+ return s.isWritable();
+ });
+
+ if (writable)
+ return false;
+
const bool open = QFile(group::ini_combine(current)).open(QFile::ReadWrite);
const QStringList ini_list = group::ini_list();
@@ -593,7 +601,7 @@ inline bool MainWindow::mk_window(ptr<t>& place, Args&&... params)
}
template<typename t>
-bool MainWindow::mk_dialog(mem<dylib> lib, ptr<t>& d)
+bool MainWindow::mk_dialog(std::shared_ptr<dylib> lib, ptr<t>& d)
{
const bool just_created = mk_window_common(d, [&]() -> t* {
if (lib && lib->Dialog)
diff --git a/gui/main-window.hpp b/gui/main-window.hpp
index 71e372f0..ef6143e7 100644
--- a/gui/main-window.hpp
+++ b/gui/main-window.hpp
@@ -68,15 +68,15 @@ class MainWindow : public QMainWindow, private State
menu_action_tracker, menu_action_filter, menu_action_proto,
menu_action_options, menu_action_mappings;
- mem<dylib> current_tracker()
+ std::shared_ptr<dylib> current_tracker()
{
return modules.trackers().value(ui.iconcomboTrackerSource->currentIndex(), nullptr);
}
- mem<dylib> current_protocol()
+ std::shared_ptr<dylib> current_protocol()
{
return modules.protocols().value(ui.iconcomboProtocol->currentIndex(), nullptr);
}
- mem<dylib> current_filter()
+ std::shared_ptr<dylib> current_filter()
{
return modules.filters().value(ui.iconcomboFilter->currentIndex(), nullptr);
}
@@ -99,7 +99,7 @@ class MainWindow : public QMainWindow, private State
// only use in impl file since no definition in header!
template<typename t>
- bool mk_dialog(mem<dylib> lib, ptr<t>& d);
+ bool mk_dialog(std::shared_ptr<dylib> lib, ptr<t>& d);
// idem
template<typename t, typename... Args>
diff --git a/gui/main.cpp b/gui/main.cpp
index 80040732..16e08b6e 100644
--- a/gui/main.cpp
+++ b/gui/main.cpp
@@ -129,13 +129,13 @@ main(int argc, char** argv)
if (!QSettings(OPENTRACK_ORG).value("disable-translation", false).toBool())
{
- (void) t.load(QLocale(), "", "", QCoreApplication::applicationDirPath() + "/" + OPENTRACK_I18N_PATH, ".qm");
+ (void) t.load(QLocale(), "", "", QCoreApplication::applicationDirPath() + "/" OPENTRACK_I18N_PATH, ".qm");
(void) QCoreApplication::installTranslator(&t);
}
do
{
- mem<MainWindow> w = std::make_shared<MainWindow>();
+ std::shared_ptr<MainWindow> w = std::make_shared<MainWindow>();
if (!w->isEnabled())
break;
diff --git a/gui/mapping-window.cpp b/gui/mapping-window.cpp
index 0ee8c562..0a5d3049 100644
--- a/gui/mapping-window.cpp
+++ b/gui/mapping-window.cpp
@@ -114,18 +114,15 @@ void MapWidget::closeEvent(QCloseEvent*)
void MapWidget::save_dialog()
{
- mem<QSettings> settings_ = group::ini_file();
- QSettings& settings = *settings_;
-
- s.b_map->save_deferred(settings);
+ s.b_map->save();
for (int i = 0; i < 6; i++)
{
m.forall([&](Map& s)
{
- s.spline_main.save(settings);
- s.spline_alt.save(settings);
- s.opts.b_mapping_window->save_deferred(settings);
+ s.spline_main.save();
+ s.spline_alt.save();
+ s.opts.b_mapping_window->save();
});
}
}
diff --git a/logic/mappings.cpp b/logic/mappings.cpp
index d7764375..bae8c2c0 100644
--- a/logic/mappings.cpp
+++ b/logic/mappings.cpp
@@ -11,10 +11,10 @@ Map::Map(QString primary, QString secondary, int max_x, int max_y, axis_opts& op
spline_alt.set_max_input(opts.clamp);
}
-void Map::save(QSettings& s)
+void Map::save()
{
- spline_main.save(s);
- spline_alt.save(s);
+ spline_main.save();
+ spline_alt.save();
}
void Map::load()
diff --git a/logic/mappings.hpp b/logic/mappings.hpp
index 4e0f7218..b3587749 100644
--- a/logic/mappings.hpp
+++ b/logic/mappings.hpp
@@ -17,7 +17,7 @@ struct OTR_LOGIC_EXPORT Map final
{
Map(QString primary, QString secondary, int max_x, int max_y, axis_opts& opts);
- void save(QSettings& s);
+ void save();
void load();
axis_opts& opts;
diff --git a/logic/selected-libraries.hpp b/logic/selected-libraries.hpp
index 689cbec3..65e9733e 100644
--- a/logic/selected-libraries.hpp
+++ b/logic/selected-libraries.hpp
@@ -15,11 +15,14 @@
struct OTR_LOGIC_EXPORT SelectedLibraries
{
- using dylibptr = mem<dylib>;
- mem<ITracker> pTracker;
- mem<IFilter> pFilter;
- mem<IProtocol> pProtocol;
+ using dylibptr = std::shared_ptr<dylib>;
+
+ std::shared_ptr<ITracker> pTracker;
+ std::shared_ptr<IFilter> pFilter;
+ std::shared_ptr<IProtocol> pProtocol;
+
SelectedLibraries(QFrame* frame, dylibptr t, dylibptr p, dylibptr f);
SelectedLibraries() : pTracker(nullptr), pFilter(nullptr), pProtocol(nullptr), correct(false) {}
+
bool correct;
};
diff --git a/logic/state.hpp b/logic/state.hpp
index f5892557..8bef71ad 100644
--- a/logic/state.hpp
+++ b/logic/state.hpp
@@ -26,5 +26,5 @@ struct State
Modules modules;
main_settings s;
Mappings pose;
- mem<Work> work;
+ std::shared_ptr<Work> work;
};
diff --git a/logic/tracker.cpp b/logic/tracker.cpp
index 7411d3b4..8367ee2f 100644
--- a/logic/tracker.cpp
+++ b/logic/tracker.cpp
@@ -24,6 +24,7 @@
using namespace euler;
using namespace gui_tracker_impl;
+using namespace time_units;
constexpr double Tracker::r2d;
constexpr double Tracker::d2r;
@@ -32,7 +33,7 @@ Tracker::Tracker(Mappings& m, SelectedLibraries& libs, TrackLogger& logger) :
m(m),
libs(libs),
logger(logger),
- backlog_time(0),
+ backlog_time(ns(0)),
tracking_started(false)
{
}
@@ -403,21 +404,22 @@ void Tracker::run()
{
logic();
- static constexpr long const_sleep_us = 4000;
- const long elapsed_usecs = t.elapsed_usecs();
- t.start();
+ static constexpr ns const_sleep_ms(time_cast<ns>(ms(4)));
+ const ns elapsed_nsecs = prog1(t.elapsed<ns>(), t.start());
- backlog_time += elapsed_usecs - const_sleep_us;
+ backlog_time += ns(elapsed_nsecs - const_sleep_ms);
- if (std::fabs(backlog_time) > 3000 * 1000)
+ if (backlog_time > secs_(3) || backlog_time < secs_(-3))
{
- qDebug() << "tracker: backlog interval overflow" << backlog_time;
- backlog_time = 0;
+ qDebug() << "tracker: backlog interval overflow"
+ << time_cast<ms>(backlog_time).count() << "ms";
+ backlog_time = backlog_time.zero();
}
- const unsigned sleep_time = unsigned(std::round(clamp((const_sleep_us - backlog_time)/1000., 0, const_sleep_us*2.5/1000)));
+ const int sleep_time_ms = iround(clamp(const_sleep_ms - backlog_time,
+ ns(0), ms(50)).count());
- portable::sleep(sleep_time);
+ portable::sleep(sleep_time_ms);
}
{
diff --git a/logic/tracker.h b/logic/tracker.h
index 85bd1ed8..2f29aca7 100644
--- a/logic/tracker.h
+++ b/logic/tracker.h
@@ -85,7 +85,7 @@ private:
state real_rotation, scaled_rotation;
euler_t t_center;
- long backlog_time;
+ time_units::ns backlog_time;
bool tracking_started;
diff --git a/logic/work.cpp b/logic/work.cpp
index 7b9e550e..6829e62b 100644
--- a/logic/work.cpp
+++ b/logic/work.cpp
@@ -60,7 +60,7 @@ std::shared_ptr<TrackLogger> Work::make_logger(main_settings &s)
}
-Work::Work(Mappings& m, QFrame* frame, mem<dylib> tracker_, mem<dylib> filter_, mem<dylib> proto_) :
+Work::Work(Mappings& m, QFrame* frame, std::shared_ptr<dylib> tracker_, std::shared_ptr<dylib> filter_, std::shared_ptr<dylib> proto_) :
libs(frame, tracker_, filter_, proto_),
logger(make_logger(s)),
tracker(std::make_shared<Tracker>(m, libs, *logger)),
diff --git a/logic/work.hpp b/logic/work.hpp
index f1d5e401..dc32536c 100644
--- a/logic/work.hpp
+++ b/logic/work.hpp
@@ -35,7 +35,7 @@ struct OTR_LOGIC_EXPORT Work
std::shared_ptr<Shortcuts> sc;
std::vector<key_tuple> keys;
- Work(Mappings& m, QFrame* frame, mem<dylib> tracker, mem<dylib> filter, mem<dylib> proto);
+ Work(Mappings& m, QFrame* frame, std::shared_ptr<dylib> tracker, std::shared_ptr<dylib> filter, std::shared_ptr<dylib> proto);
~Work();
void reload_shortcuts();
bool is_ok() const;
diff --git a/migration/20160906_00-mappings.cpp b/migration/20160906_00-mappings.cpp
index 58674843..a5184825 100644
--- a/migration/20160906_00-mappings.cpp
+++ b/migration/20160906_00-mappings.cpp
@@ -36,31 +36,30 @@ struct mappings_from_2_3_0_rc11 : migration
"rz", "rz_alt",
};
- std::shared_ptr<QSettings> settings_ = options::group::ini_file();
- QSettings& settings(*settings_);
-
- for (const char* name : names)
- {
- QList<QPointF> points;
+ return group::with_settings_object([&](QSettings& settings) {
+ for (const char* name : names)
+ {
+ QList<QPointF> points;
- settings.beginGroup(QString("Curves-%1").arg(name));
+ settings.beginGroup(QString("Curves-%1").arg(name));
- const int max = settings.value("point-count", 0).toInt();
+ const int max = settings.value("point-count", 0).toInt();
- for (int i = 0; i < max; i++)
- {
- QPointF new_point(settings.value(QString("point-%1-x").arg(i), 0).toDouble(),
- settings.value(QString("point-%1-y").arg(i), 0).toDouble());
+ for (int i = 0; i < max; i++)
+ {
+ QPointF new_point(settings.value(QString("point-%1-x").arg(i), 0).toDouble(),
+ settings.value(QString("point-%1-y").arg(i), 0).toDouble());
- points.append(new_point);
- }
+ points.append(new_point);
+ }
- settings.endGroup();
+ settings.endGroup();
- ret.append(points);
- }
+ ret.append(points);
+ }
- return ret;
+ return ret;
+ });
}
QString unique_date() const override { return "20160909_00"; }
@@ -94,9 +93,6 @@ struct mappings_from_2_3_0_rc11 : migration
const QList<QList<QPointF>> old_mappings = get_old_splines();
Mappings m = get_new_mappings();
- std::shared_ptr<QSettings> s_ = options::group::ini_file();
- QSettings& s = *s_;
-
for (int i = 0; i < 12; i++)
{
spline& spl = (i % 2) == 0 ? m(i / 2).spline_main : m(i / 2).spline_alt;
@@ -104,7 +100,7 @@ struct mappings_from_2_3_0_rc11 : migration
const QList<QPointF>& points = old_mappings[i];
for (const QPointF& pt : points)
spl.add_point(pt);
- spl.save(s);
+ spl.save();
}
}
};
diff --git a/migration/migration.cpp b/migration/migration.cpp
index bb8386fc..747ea06b 100644
--- a/migration/migration.cpp
+++ b/migration/migration.cpp
@@ -78,11 +78,11 @@ QString migrator::last_migration_time()
{
QString ret;
- std::shared_ptr<QSettings> s(options::group::ini_file());
-
- s->beginGroup("migrations");
- ret = s->value("last-migration-at", "19700101_00").toString();
- s->endGroup();
+ options::group::with_settings_object([&](QSettings& s) {
+ s.beginGroup("migrations");
+ ret = s.value("last-migration-at", "19700101_00").toString();
+ s.endGroup();
+ });
return ret;
}
@@ -102,11 +102,16 @@ QString migrator::time_after_migrations()
void migrator::set_last_migration_time(const QString& val)
{
- std::shared_ptr<QSettings> s(options::group::ini_file());
-
- s->beginGroup("migrations");
- s->setValue("last-migration-at", val);
- s->endGroup();
+ options::group::with_settings_object([&](QSettings& s) {
+ s.beginGroup("migrations");
+ const QString old_value = s.value("last-migration-at", "").toString();
+ if (val != old_value)
+ {
+ s.setValue("last-migration-at", val);
+ options::group::mark_ini_modified();
+ }
+ s.endGroup();
+ });
}
std::vector<migration*> migrator::sorted_migrations()
diff --git a/options/CMakeLists.txt b/options/CMakeLists.txt
index cbebeb87..0c4b53a5 100644
--- a/options/CMakeLists.txt
+++ b/options/CMakeLists.txt
@@ -2,3 +2,4 @@ otr_module(options NO-COMPAT BIN)
if(NOT WIN32 AND NOT APPLE)
target_link_libraries(opentrack-options rt)
endif()
+target_link_libraries(opentrack-options opentrack-compat)
diff --git a/options/base-value.cpp b/options/base-value.cpp
new file mode 100644
index 00000000..29f4b496
--- /dev/null
+++ b/options/base-value.cpp
@@ -0,0 +1,27 @@
+#include "base-value.hpp"
+
+using namespace options;
+
+base_value::base_value(bundle b, const QString& name, base_value::comparator cmp, std::type_index type_idx) :
+ b(b),
+ self_name(name),
+ cmp(cmp),
+ type_index(type_idx)
+{
+ b->on_value_created(name, this);
+}
+
+base_value::~base_value()
+{
+ b->on_value_destructed(self_name, this);
+}
+
+void base_value::store(const QVariant& datum)
+{
+ b->store_kv(self_name, datum);
+}
+
+void ::options::detail::set_base_value_to_default(base_value* val)
+{
+ val->set_to_default();
+}
diff --git a/options/base-value.hpp b/options/base-value.hpp
new file mode 100644
index 00000000..4f90e3fc
--- /dev/null
+++ b/options/base-value.hpp
@@ -0,0 +1,85 @@
+#pragma once
+
+#include "bundle.hpp"
+#include "slider.hpp"
+#include "connector.hpp"
+
+#include "export.hpp"
+
+#include <QObject>
+#include <QString>
+#include <QList>
+#include <QPointF>
+#include <QVariant>
+
+#include <typeindex>
+
+#define OPENTRACK_DEFINE_SLOT(t) void setValue(t datum) { store(datum); }
+#define OPENTRACK_DEFINE_SIGNAL(t) void valueChanged(t) const
+
+namespace options {
+
+class OTR_OPTIONS_EXPORT base_value : public QObject
+{
+ Q_OBJECT
+ friend class detail::connector;
+
+ using comparator = bool(*)(const QVariant& val1, const QVariant& val2);
+public:
+ QString name() const { return self_name; }
+ base_value(bundle b, const QString& name, comparator cmp, std::type_index type_idx);
+ ~base_value() override;
+signals:
+ OPENTRACK_DEFINE_SIGNAL(double);
+ OPENTRACK_DEFINE_SIGNAL(float);
+ OPENTRACK_DEFINE_SIGNAL(int);
+ OPENTRACK_DEFINE_SIGNAL(bool);
+ OPENTRACK_DEFINE_SIGNAL(const QString&);
+ OPENTRACK_DEFINE_SIGNAL(const slider_value&);
+ OPENTRACK_DEFINE_SIGNAL(const QPointF&);
+ OPENTRACK_DEFINE_SIGNAL(const QVariant&);
+
+ OPENTRACK_DEFINE_SIGNAL(const QList<double>&);
+ OPENTRACK_DEFINE_SIGNAL(const QList<float>&);
+ OPENTRACK_DEFINE_SIGNAL(const QList<int>&);
+ OPENTRACK_DEFINE_SIGNAL(const QList<bool>&);
+ OPENTRACK_DEFINE_SIGNAL(const QList<QString>&);
+ OPENTRACK_DEFINE_SIGNAL(const QList<slider_value>&);
+ OPENTRACK_DEFINE_SIGNAL(const QList<QPointF>&);
+protected:
+ bundle b;
+ QString self_name;
+ comparator cmp;
+ std::type_index type_index;
+
+ void store(const QVariant& datum);
+
+ template<typename t>
+ void store(const t& datum)
+ {
+ b->store_kv(self_name, QVariant::fromValue(datum));
+ }
+
+public slots:
+ OPENTRACK_DEFINE_SLOT(double)
+ OPENTRACK_DEFINE_SLOT(int)
+ OPENTRACK_DEFINE_SLOT(bool)
+ OPENTRACK_DEFINE_SLOT(const QString&)
+ OPENTRACK_DEFINE_SLOT(const slider_value&)
+ OPENTRACK_DEFINE_SLOT(const QPointF&)
+ OPENTRACK_DEFINE_SLOT(const QVariant&)
+
+ OPENTRACK_DEFINE_SLOT(const QList<double>&)
+ OPENTRACK_DEFINE_SLOT(const QList<float>&)
+ OPENTRACK_DEFINE_SLOT(const QList<int>&)
+ OPENTRACK_DEFINE_SLOT(const QList<bool>&)
+ OPENTRACK_DEFINE_SLOT(const QList<QString>&)
+ OPENTRACK_DEFINE_SLOT(const QList<slider_value>&)
+ OPENTRACK_DEFINE_SLOT(const QList<QPointF>&)
+
+ virtual void reload() = 0;
+ virtual void bundle_value_changed() const = 0;
+ virtual void set_to_default() = 0;
+};
+
+} //ns options
diff --git a/options/bundle.cpp b/options/bundle.cpp
index 43f4a8e3..c78df274 100644
--- a/options/bundle.cpp
+++ b/options/bundle.cpp
@@ -31,12 +31,12 @@ bundle::~bundle()
{
}
-void bundle::reload(std::shared_ptr<QSettings> settings)
+void bundle::reload()
{
if (group_name.size())
{
QMutexLocker l(&mtx);
- saved = group(group_name, settings);
+ saved = group(group_name);
const bool has_changes = is_modified();
transient = saved;
@@ -51,7 +51,12 @@ void bundle::reload(std::shared_ptr<QSettings> settings)
void bundle::set_all_to_default()
{
+ QMutexLocker l(&mtx);
+
forall([](const QString&, base_value* val) { set_base_value_to_default(val); });
+
+ if (is_modified())
+ group::mark_ini_modified();
}
void bundle::store_kv(const QString& name, const QVariant& datum)
@@ -72,10 +77,10 @@ bool bundle::contains(const QString &name) const
return transient.contains(name);
}
-void bundle::save_deferred(QSettings& s)
+void bundle::save()
{
if (QThread::currentThread() != qApp->thread())
- qCritical() << "group::save - current thread not ui thread";
+ qDebug() << "group::save - current thread not ui thread";
if (group_name.size() == 0)
return;
@@ -84,12 +89,13 @@ void bundle::save_deferred(QSettings& s)
{
QMutexLocker l(&mtx);
+
if (is_modified())
{
//qDebug() << "bundle" << group_name << "changed, saving";
modified_ = true;
saved = transient;
- saved.save_deferred(s);
+ saved.save();
}
}
@@ -97,11 +103,6 @@ void bundle::save_deferred(QSettings& s)
emit saving();
}
-void bundle::save()
-{
- save_deferred(*group::ini_file());
-}
-
bool bundle::is_modified() const
{
QMutexLocker l(mtx);
@@ -119,8 +120,7 @@ bool bundle::is_modified() const
for (const auto& kv : saved.kvs)
{
- const QVariant other = transient.get<QVariant>(kv.first);
- if (!transient.contains(kv.first) || !is_equal(kv.first, kv.second, other))
+ if (!transient.contains(kv.first))
{
//if (logspam)
// qDebug() << "bundle" << group_name << "modified" << "key" << kv.first << "-" << other << "<>" << kv.second;
@@ -135,8 +135,6 @@ void bundler::after_profile_changed_()
{
QMutexLocker l(&implsgl_mtx);
- std::shared_ptr<QSettings> s = group::ini_file();
-
for (auto& kv : implsgl_data)
{
weak bundle = kv.second;
@@ -144,7 +142,7 @@ void bundler::after_profile_changed_()
if (bundle_)
{
//qDebug() << "bundle: reverting" << kv.first << "due to profile change";
- bundle_->reload(s);
+ bundle_->reload();
}
}
}
diff --git a/options/bundle.hpp b/options/bundle.hpp
index f05999a7..63ee82d0 100644
--- a/options/bundle.hpp
+++ b/options/bundle.hpp
@@ -81,8 +81,7 @@ public:
}
public slots:
void save();
- void reload(std::shared_ptr<QSettings> settings = group::ini_file());
- void save_deferred(QSettings& s);
+ void reload();
void set_all_to_default();
};
diff --git a/options/connector.cpp b/options/connector.cpp
index 63d70ca7..075a57e1 100644
--- a/options/connector.cpp
+++ b/options/connector.cpp
@@ -83,11 +83,12 @@ void connector::on_value_created(const QString& name, value_type val)
QMutexLocker l(get_mtx());
- if (on_value_destructed_impl(name, val))
+ int i = 1;
+ while (on_value_destructed_impl(name, val))
{
qWarning() << "options/connector: value created twice;"
- << "bundle"
- << val->b->name()
+ << "cnt" << i++
+ << "bundle" << val->b->name()
<< "value-name" << name
<< "value-ptr" << quintptr(val);
}
diff --git a/options/group.cpp b/options/group.cpp
index 9a4bd912..60e8a7b4 100644
--- a/options/group.cpp
+++ b/options/group.cpp
@@ -8,46 +8,49 @@
#include "group.hpp"
#include "defs.hpp"
+
+#include "compat/timer.hpp"
+
+#include <cmath>
+
#include <QStandardPaths>
#include <QDir>
-
#include <QDebug>
namespace options {
-group::group(const QString& name, std::shared_ptr<QSettings> conf) : name(name)
+group::group(const QString& name) : name(name)
{
if (name == "")
return;
- conf->beginGroup(name);
- for (auto& k_ : conf->childKeys())
- {
- auto tmp = k_.toUtf8();
- QString k(tmp);
- kvs[k] = conf->value(k_);
- }
- conf->endGroup();
-}
-
-group::group(const QString& name) : group(name, ini_file())
-{
+ with_settings_object([&](QSettings& conf) {
+ conf.beginGroup(name);
+ for (auto& k_ : conf.childKeys())
+ {
+ auto tmp = k_.toUtf8();
+ QString k(tmp);
+ QVariant val = conf.value(k_);
+ if (val.type() != QVariant::Invalid)
+ kvs[k] = std::move(val);
+ }
+ conf.endGroup();
+ });
}
void group::save() const
{
- save_deferred(*ini_file());
-}
-
-void group::save_deferred(QSettings& s) const
-{
if (name == "")
return;
- s.beginGroup(name);
- for (auto& i : kvs)
- s.setValue(i.first, i.second);
- s.endGroup();
+ with_settings_object([&](QSettings& s) {
+ s.beginGroup(name);
+ for (auto& i : kvs)
+ s.setValue(i.first, i.second);
+ s.endGroup();
+
+ mark_ini_modified();
+ });
}
void group::put(const QString &s, const QVariant &d)
@@ -103,12 +106,52 @@ QStringList group::ini_list()
return list;
}
-std::shared_ptr<QSettings> group::ini_file()
+void group::mark_ini_modified()
+{
+ QMutexLocker l(&cur_ini_mtx);
+ ini_modifiedp = true;
+}
+
+QString group::cur_ini_pathname;
+std::shared_ptr<QSettings> group::cur_ini;
+QMutex group::cur_ini_mtx(QMutex::Recursive);
+int group::ini_refcount = 0;
+bool group::ini_modifiedp = false;
+
+std::shared_ptr<QSettings> group::cur_settings_object()
{
- const auto pathname = ini_pathname();
- if (pathname != "")
- return std::make_shared<QSettings>(ini_pathname(), QSettings::IniFormat);
- return std::make_shared<QSettings>();
+ const QString pathname = ini_pathname();
+
+ if (pathname.isEmpty())
+ return std::make_shared<QSettings>();
+
+ QMutexLocker l(&cur_ini_mtx);
+
+ if (pathname != cur_ini_pathname)
+ {
+ cur_ini = std::make_shared<QSettings>(pathname, QSettings::IniFormat);
+ cur_ini_pathname = pathname;
+ }
+
+ return cur_ini;
}
+group::saver_::~saver_()
+{
+ if (--ini_refcount == 0 && ini_modifiedp)
+ {
+ ini_modifiedp = false;
+ static Timer t;
+ const double tm = t.elapsed_seconds();
+ qDebug() << QStringLiteral("%1.%2").arg(int(tm)).arg(int(std::fmod(tm, 1.)*10)).toLatin1().data()
+ << "saving .ini file" << cur_ini_pathname;
+ s.sync();
+ }
}
+
+group::saver_::saver_(QSettings& s, QMutex& mtx) : s(s), mtx(mtx), lck(&mtx)
+{
+ ini_refcount++;
+}
+
+} // ns options
diff --git a/options/group.hpp b/options/group.hpp
index e2a8058c..b0e13a6a 100644
--- a/options/group.hpp
+++ b/options/group.hpp
@@ -1,13 +1,16 @@
#pragma once
#include "export.hpp"
+
#include "compat/util.hpp"
+
#include <map>
#include <memory>
#include <QString>
#include <QList>
#include <QVariant>
#include <QSettings>
+#include <QMutex>
namespace options {
@@ -15,12 +18,27 @@ namespace options {
class OTR_OPTIONS_EXPORT group final
{
QString name;
+
+ static QString cur_ini_pathname;
+ static std::shared_ptr<QSettings> cur_ini;
+ static QMutex cur_ini_mtx;
+ static int ini_refcount;
+ static bool ini_modifiedp;
+ struct OTR_OPTIONS_EXPORT saver_ final
+ {
+ QSettings& s;
+ QMutex& mtx;
+ QMutexLocker lck;
+
+ ~saver_();
+ saver_(QSettings& s, QMutex&);
+ };
+ static std::shared_ptr<QSettings> cur_settings_object();
+
public:
std::map<QString, QVariant> kvs;
- group(const QString& name, mem<QSettings> s);
group(const QString& name);
void save() const;
- void save_deferred(QSettings& s) const;
void put(const QString& s, const QVariant& d);
bool contains(const QString& s) const;
static QString ini_directory();
@@ -28,9 +46,11 @@ public:
static QString ini_pathname();
static QString ini_combine(const QString& filename);
static QStringList ini_list();
- static std::shared_ptr<QSettings> ini_file();
+
+ static void mark_ini_modified();
template<typename t>
+ OTR_NEVER_INLINE
t get(const QString& k) const
{
auto value = kvs.find(k);
@@ -38,6 +58,15 @@ public:
return value->second.value<t>();
return t();
}
+
+ template<typename F>
+ OTR_NEVER_INLINE
+ static auto with_settings_object(F&& fun)
+ {
+ saver_ saver { *cur_settings_object(), cur_ini_mtx };
+
+ return fun(static_cast<QSettings&>(saver.s));
+ }
};
}
diff --git a/options/scoped.cpp b/options/scoped.cpp
index 96f4a261..58a4ee02 100644
--- a/options/scoped.cpp
+++ b/options/scoped.cpp
@@ -2,8 +2,8 @@
#include <QApplication>
#include <QThread>
-// for std::abort()
#include <cstdlib>
+#include <atomic>
#include <QDebug>
diff --git a/options/tie.hpp b/options/tie.hpp
index a3b5a19f..94fe5d49 100644
--- a/options/tie.hpp
+++ b/options/tie.hpp
@@ -58,6 +58,23 @@ void tie_setting(value<t>& v, QLabel* lb, const QString& format, const xs&... ar
v.SAFE_CONNTYPE);
}
+// Clang 3.9 has a bug
+// error: missing default argument on parameter 'args'
+
+// cf. http://stackoverflow.com/questions/29098835/can-parameter-pack-function-arguments-be-defaulted
+
+template<typename t, typename F, typename... xs>
+decltype((void)((std::declval<F>())(std::declval<const t&>())))
+tie_setting(value<t>& v, QLabel* lb, F&& fun, const QString& fmt = QStringLiteral("%1"), const xs&... args)
+{
+ auto closure = [=](const t& x) { lb->setText(fmt.arg(fun(x), args...)); };
+
+ closure(v());
+ base_value::connect(&v, static_cast<void(base_value::*)(const t&) const>(&base_value::valueChanged),
+ lb, closure,
+ v.SAFE_CONNTYPE);
+}
+
OTR_OPTIONS_EXPORT void tie_setting(value<int>& v, QComboBox* cb);
OTR_OPTIONS_EXPORT void tie_setting(value<QString>& v, QComboBox* cb);
OTR_OPTIONS_EXPORT void tie_setting(value<QVariant>& v, QComboBox* cb);
diff --git a/options/value-traits.hpp b/options/value-traits.hpp
new file mode 100644
index 00000000..cf12649c
--- /dev/null
+++ b/options/value-traits.hpp
@@ -0,0 +1,50 @@
+#include "export.hpp"
+
+#include "compat/functional.hpp"
+#include "slider.hpp"
+
+#include <QString>
+
+#include <type_traits>
+
+namespace options {
+namespace detail {
+
+template<typename t, typename u = t, typename Enable = void>
+struct default_value_traits
+{
+ using element_type = remove_qualifiers<t>;
+ using value_type = u;
+
+ static inline value_type from_value(const value_type& val, const value_type&) { return val; }
+ static inline value_type from_storage(const element_type& x) { return static_cast<value_type>(x); }
+ static inline element_type to_storage(const value_type& val) { return static_cast<element_type>(val); }
+};
+
+template<typename t, typename u = t, typename Enable = void>
+struct value_traits : default_value_traits<t, u, Enable>
+{
+};
+
+template<>
+struct value_traits<slider_value> : default_value_traits<slider_value>
+{
+ static inline slider_value from_value(const slider_value& val, const slider_value& def)
+ {
+ return slider_value(val.cur(), def.min(), def.max());
+ }
+};
+
+// Qt uses int a lot in slots so use it for all enums
+template<typename t>
+struct value_traits<t, t, std::enable_if_t<std::is_enum<t>::value>> : public default_value_traits<int, t>
+{
+};
+
+template<>
+struct value_traits<float> : public default_value_traits<float, double, void>
+{
+};
+
+} // ns detail
+} // ns options
diff --git a/options/value.cpp b/options/value.cpp
deleted file mode 100644
index d3d24a58..00000000
--- a/options/value.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Copyright (c) 2015-2016, 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 "value.hpp"
-
-namespace options {
-
-base_value::base_value(bundle b, const QString& name, base_value::comparator cmp, std::type_index type_idx) :
- b(b),
- self_name(name),
- cmp(cmp),
- type_index(type_idx)
-{
- b->on_value_created(name, this);
-}
-
-base_value::~base_value()
-{
- b->on_value_destructed(self_name, this);
-}
-
-namespace detail
-{
- void set_base_value_to_default(base_value* val)
- {
- val->set_to_default();
- }
-}
-
-} // ns options
diff --git a/options/value.hpp b/options/value.hpp
index 020cbeea..ebb2096c 100644
--- a/options/value.hpp
+++ b/options/value.hpp
@@ -12,153 +12,59 @@
#include "compat/util.hpp"
-#include "connector.hpp"
#include "bundle.hpp"
#include "slider.hpp"
+#include "base-value.hpp"
+#include "value-traits.hpp"
+
+#include <cstdio>
#include <type_traits>
#include <typeinfo>
#include <typeindex>
+#include <utility>
+
+#include <QVariant>
#include <QString>
#include <QPointF>
#include <QList>
+#include <QMutex>
-#define OPENTRACK_DEFINE_SLOT(t) void setValue(t datum) { store(datum); }
-#define OPENTRACK_DEFINE_SIGNAL(t) void valueChanged(t) const
namespace options {
namespace detail {
-template<typename t> struct value_type_traits { using type = t;};
-template<> struct value_type_traits<QString> { using type = const QString&; };
-template<> struct value_type_traits<slider_value> { using type = const slider_value&; };
-template<typename u> struct value_type_traits<QList<u>>
-{
- using type = const QList<u>&;
-};
-template<typename t> using value_type_t = typename value_type_traits<t>::type;
-}
-
-class OTR_OPTIONS_EXPORT base_value : public QObject
-{
- Q_OBJECT
- friend class ::options::detail::connector;
- using comparator = bool(*)(const QVariant& val1, const QVariant& val2);
-public:
- QString name() const { return self_name; }
- base_value(bundle b, const QString& name, comparator cmp, std::type_index type_idx);
- ~base_value() override;
-signals:
- OPENTRACK_DEFINE_SIGNAL(double);
- OPENTRACK_DEFINE_SIGNAL(float);
- OPENTRACK_DEFINE_SIGNAL(int);
- OPENTRACK_DEFINE_SIGNAL(bool);
- OPENTRACK_DEFINE_SIGNAL(const QString&);
- OPENTRACK_DEFINE_SIGNAL(const slider_value&);
- OPENTRACK_DEFINE_SIGNAL(const QPointF&);
- OPENTRACK_DEFINE_SIGNAL(const QVariant&);
-
- OPENTRACK_DEFINE_SIGNAL(const QList<double>&);
- OPENTRACK_DEFINE_SIGNAL(const QList<float>&);
- OPENTRACK_DEFINE_SIGNAL(const QList<int>&);
- OPENTRACK_DEFINE_SIGNAL(const QList<bool>&);
- OPENTRACK_DEFINE_SIGNAL(const QList<QString>&);
- OPENTRACK_DEFINE_SIGNAL(const QList<slider_value>&);
- OPENTRACK_DEFINE_SIGNAL(const QList<QPointF>&);
-protected:
- bundle b;
- QString self_name;
- comparator cmp;
- std::type_index type_index;
-
- void store(const QVariant& datum)
- {
- b->store_kv(self_name, datum);
- }
-
- template<typename t>
- void store(const t& datum)
- {
- b->store_kv(self_name, QVariant::fromValue(datum));
- }
+OTR_OPTIONS_EXPORT void acct_lookup(bool is_fresh);
-public slots:
- OPENTRACK_DEFINE_SLOT(double)
- OPENTRACK_DEFINE_SLOT(int)
- OPENTRACK_DEFINE_SLOT(bool)
- OPENTRACK_DEFINE_SLOT(const QString&)
- OPENTRACK_DEFINE_SLOT(const slider_value&)
- OPENTRACK_DEFINE_SLOT(const QPointF&)
- OPENTRACK_DEFINE_SLOT(const QVariant&)
-
- OPENTRACK_DEFINE_SLOT(const QList<double>&)
- OPENTRACK_DEFINE_SLOT(const QList<float>&)
- OPENTRACK_DEFINE_SLOT(const QList<int>&)
- OPENTRACK_DEFINE_SLOT(const QList<bool>&)
- OPENTRACK_DEFINE_SLOT(const QList<QString>&)
- OPENTRACK_DEFINE_SLOT(const QList<slider_value>&)
- OPENTRACK_DEFINE_SLOT(const QList<QPointF>&)
-
- virtual void reload() = 0;
- virtual void bundle_value_changed() const = 0;
- virtual void set_to_default() = 0;
-};
+} // ns detail
-namespace detail {
template<typename t>
-struct value_get_traits
+class value final : public base_value
{
- static inline t get(const t& val, const t&)
- {
- return val;
- }
-};
+ using traits = detail::value_traits<t, t, void>;
+ using element_type = typename traits::element_type;
-template<>
-struct value_get_traits<slider_value>
-{
- using t = slider_value;
- static inline t get(const t& val, const t& def)
+ static bool is_equal(const QVariant& val1, const QVariant& val2)
{
- return t(val.cur(), def.min(), def.max());
+ return val1.value<element_type>() == val2.value<element_type>();
}
-};
-template<typename t, typename Enable = void>
-struct value_element_type
-{
- using type = typename std::remove_reference<typename std::remove_cv<t>::type>::type;
-};
-
-// Qt uses int a lot in slots so use it for all enums
-template<typename t>
-struct value_element_type<t, typename std::enable_if<std::is_enum<t>::value>::type>
-{
- using type = int;
-};
-
-template<> struct value_element_type<float, void> { using type = double; };
-
-template<typename t> using value_element_type_t = typename value_element_type<t>::type;
+ OTR_NEVER_INLINE
+ t get() const
+ {
+ if (!b->contains(self_name) || b->get<QVariant>(self_name).type() == QVariant::Invalid)
+ return def;
-}
+ const element_type x(b->get<element_type>(self_name));
-template<typename t>
-class value final : public base_value
-{
- static bool is_equal(const QVariant& val1, const QVariant& val2)
- {
- return val1.value<element_type>() == val2.value<element_type>();
+ return traits::from_value(traits::from_storage(x), def);
}
public:
- using element_type = detail::value_element_type_t<t>;
-
OTR_NEVER_INLINE
t operator=(const t& datum)
{
- const element_type tmp = static_cast<element_type>(datum);
- if (tmp != get())
- store(tmp);
+ if (datum != get())
+ store(traits::to_storage(datum));
return datum;
}
@@ -167,13 +73,12 @@ public:
OTR_NEVER_INLINE
value(bundle b, const QString& name, t def) :
- base_value(b, name, &is_equal, std::type_index(typeid(element_type))), def(def)
+ base_value(b, name, &is_equal, std::type_index(typeid(element_type))),
+ def(def)
{
QObject::connect(b.get(), SIGNAL(reloading()),
this, SLOT(reload()),
DIRECT_CONNTYPE);
- if (!b->contains(name) || b->get<QVariant>(name).type() == QVariant::Invalid)
- *this = def;
}
OTR_NEVER_INLINE
@@ -181,6 +86,7 @@ public:
{
}
+ OTR_NEVER_INLINE
t default_value() const
{
return def;
@@ -193,7 +99,7 @@ public:
}
OTR_NEVER_INLINE
- operator t() const { return get(); }
+ operator t() const { return std::forward<t>(get()); }
OTR_NEVER_INLINE
void reload() override
@@ -201,34 +107,26 @@ public:
*this = static_cast<t>(*this);
}
+ OTR_NEVER_INLINE
void bundle_value_changed() const override
{
- emit valueChanged(static_cast<detail::value_type_t<t>>(get()));
+ emit valueChanged(traits::to_storage(get()));
}
OTR_NEVER_INLINE
t operator()() const
{
- return static_cast<t>(get());
+ return get();
}
template<typename u>
OTR_NEVER_INLINE
u to() const
{
- return static_cast<u>(get());
+ return static_cast<u>(std::forward<t>(get()));
}
private:
- OTR_NEVER_INLINE
- t get() const
- {
- t val = b->contains(self_name)
- ? static_cast<t>(b->get<element_type>(self_name))
- : def;
- return detail::value_get_traits<t>::get(val, def);
- }
-
const t def;
};
diff --git a/pose-widget/pose-widget.cpp b/pose-widget/pose-widget.cpp
index b511f4c5..8646df30 100644
--- a/pose-widget/pose-widget.cpp
+++ b/pose-widget/pose-widget.cpp
@@ -18,11 +18,12 @@
using namespace pose_widget_impl;
+static constexpr int offset = 2;
+
pose_transform::pose_transform(QWidget* dst) :
dst(dst),
- image(w, h, QImage::Format_ARGB32),
- image2(w, h, QImage::Format_ARGB32),
- width(w), height(h),
+ image(w+offset*2, h+offset*2, QImage::Format_ARGB32),
+ image2(w+offset*2, h+offset*2, QImage::Format_ARGB32),
fresh(false)
{
front = QImage(QString(":/images/side1.png"));
@@ -43,8 +44,10 @@ pose_transform::~pose_transform()
void pose_widget::paintEvent(QPaintEvent* event)
{
QPainter p(this);
- xform.with_image_lock([&](const QImage& image) {
- p.drawImage(event->rect(), image);
+
+ xform.with_image_lock([&](const QImage& image)
+ {
+ p.drawImage(event->rect(), image, QRect(offset, offset, pose_transform::w, pose_transform::h));
});
}
@@ -68,7 +71,7 @@ void pose_transform::run()
project_quad_texture();
end:
- portable::sleep(9);
+ portable::sleep(23);
}
}
@@ -186,7 +189,7 @@ void pose_transform::project_quad_texture()
num dir;
vec2 pt[4];
- const int sx = width - 1, sy = height - 1;
+ const int sx = w - 1, sy = h - 1;
vec2 projected[3];
{
@@ -252,7 +255,7 @@ void pose_transform::project_quad_texture()
const unsigned dest_pitch = image.bytesPerLine();
const unsigned char* orig = tex.bits();
- unsigned char* dest = image.bits();
+ unsigned char* dest = image.bits() + offset*dest_pitch;
const int orig_depth = tex.depth() / 8;
const int dest_depth = image.depth() / 8;
@@ -270,8 +273,8 @@ void pose_transform::project_quad_texture()
return;
}
- for (int y = 1; y < sy; y++)
- for (int x = 1; x < sx; x++)
+ for (int y = 0; y < sy; y++)
+ for (int x = 0; x < sx; x++)
{
vec2 pos(x, y);
vec2 uv;
@@ -309,7 +312,7 @@ void pose_transform::project_quad_texture()
const float ax = 1 - ax_;
const float ay = 1 - ay_;
- const unsigned pos = y * dest_pitch + x * dest_depth;
+ const unsigned pos = y * dest_pitch + (x+offset) * dest_depth;
for (int k = 0; k < 4; k++)
{
@@ -336,13 +339,13 @@ vec2 pose_transform::project(const vec3 &point)
vec3 ret = rotation * point;
num z = std::fmax(num(.5), 1 + translation.z()/-80);
- num w = width, h = height;
- num x = w * translation.x() / 2 / -80;
- if (fabs(x) > w/2)
- x = x > 0 ? w/2 : w/-2;
- num y = h * translation.y() / 2 / -80;
- if (fabs(y) > h/2)
- y = y > 0 ? h/2 : h/-2;
+ num w_ = w, h_ = h;
+ num x = w_ * translation.x() / 2 / -80;
+ if (fabs(x) > w_/2)
+ x = x > 0 ? w_/2 : w_/-2;
+ num y = h_ * translation.y() / 2 / -80;
+ if (fabs(y) > h_/2)
+ y = y > 0 ? h_/2 : h_/-2;
return vec2(z * (ret.x() + x), z * (ret.y() + y));
}
diff --git a/pose-widget/pose-widget.hpp b/pose-widget/pose-widget.hpp
index b528d394..a27bf4b9 100644
--- a/pose-widget/pose-widget.hpp
+++ b/pose-widget/pose-widget.hpp
@@ -37,7 +37,7 @@ using lock_guard = std::unique_lock<std::mutex>;
class pose_widget;
-class pose_transform final : private QThread
+struct pose_transform final : private QThread
{
pose_transform(QWidget* dst);
~pose_transform();
@@ -69,8 +69,6 @@ class pose_transform final : private QThread
QImage front, back;
QImage image, image2;
- int width, height;
-
std::atomic<bool> fresh;
static constexpr int w = 320, h = 240;
diff --git a/proto-fsuipc/CMakeLists.txt b/proto-fsuipc/CMakeLists.txt
index b3e94c32..24006644 100644
--- a/proto-fsuipc/CMakeLists.txt
+++ b/proto-fsuipc/CMakeLists.txt
@@ -5,7 +5,7 @@ if(WIN32)
target_link_libraries(opentrack-proto-fsuipc ${SDK_FSUIPC}/FSUIPC_User.lib)
target_include_directories(opentrack-proto-fsuipc SYSTEM PUBLIC ${SDK_FSUIPC})
if(MSVC)
- set_property(TARGET opentrack-proto-fsuipc APPEND_STRING PROPERTY LINK_FLAGS "/NODEFAULTLIB:LIBC.lib")
+ set_property(TARGET opentrack-proto-fsuipc APPEND_STRING PROPERTY LINK_FLAGS " /NODEFAULTLIB:LIBC.lib")
endif()
endif()
endif()
diff --git a/proto-libevdev/CMakeLists.txt b/proto-libevdev/CMakeLists.txt
index f2809c93..04f6924e 100644
--- a/proto-libevdev/CMakeLists.txt
+++ b/proto-libevdev/CMakeLists.txt
@@ -5,6 +5,6 @@ if(LINUX OR APPLE)
otr_module(proto-libevdev)
pkg_check_modules(libevdev REQUIRED QUIET libevdev)
target_link_libraries(opentrack-proto-libevdev ${libevdev_LIBRARIES})
- include_directories(opentrack-proto-libevdev SYSTEM PUBLIC ${libevdev_INCLUDE_DIRS})
+ target_include_directories(opentrack-proto-libevdev SYSTEM PUBLIC ${libevdev_INCLUDE_DIRS})
endif()
endif()
diff --git a/qxt-mini/CMakeLists.txt b/qxt-mini/CMakeLists.txt
index d09cbdfa..bf8a30f9 100644
--- a/qxt-mini/CMakeLists.txt
+++ b/qxt-mini/CMakeLists.txt
@@ -3,6 +3,6 @@ if(UNIX OR APPLE)
if(NOT APPLE)
target_link_libraries(opentrack-qxt-mini X11)
else()
- set_property(TARGET opentrack-qxt-mini APPEND_STRING PROPERTY LINK_FLAGS "-framework Carbon -framework CoreFoundation")
+ set_property(TARGET opentrack-qxt-mini APPEND_STRING PROPERTY LINK_FLAGS " -framework Carbon -framework CoreFoundation")
endif()
endif()
diff --git a/spline/spline-widget.cpp b/spline/spline-widget.cpp
index fef03e82..c71626f0 100644
--- a/spline/spline-widget.cpp
+++ b/spline/spline-widget.cpp
@@ -59,7 +59,7 @@ void spline_widget::setConfig(spline* spl)
if (spl)
{
- mem<spline::settings> s = spl->get_settings();
+ std::shared_ptr<spline::settings> s = spl->get_settings();
connection = connect(s.get(), &spline::settings::recomputed,
this, [this]() { reload_spline(); },
Qt::QueuedConnection);
diff --git a/spline/spline.cpp b/spline/spline.cpp
index 195d68d6..7ca8147c 100644
--- a/spline/spline.cpp
+++ b/spline/spline.cpp
@@ -25,7 +25,7 @@ constexpr int spline::value_count;
spline::spline(qreal maxx, qreal maxy, const QString& name) :
s(nullptr),
- data(value_count, -1.f),
+ data(value_count, -16),
_mutex(QMutex::Recursive),
max_x(maxx),
max_y(maxy),
@@ -50,6 +50,7 @@ spline::spline() : spline(0, 0, "") {}
void spline::set_tracking_active(bool value)
{
+ QMutexLocker l(&_mutex);
activep = value;
}
@@ -69,14 +70,14 @@ void spline::set_max_input(qreal max_input)
{
QMutexLocker l(&_mutex);
max_x = max_input;
- recompute();
+ validp = false;
}
void spline::set_max_output(qreal max_output)
{
QMutexLocker l(&_mutex);
max_y = max_output;
- recompute();
+ validp = false;
}
qreal spline::max_input() const
@@ -113,7 +114,7 @@ float spline::get_value_no_save_internal(double x)
if (max_x > 0)
x = std::fmin(max_x, x);
- float q = float(x * precision(s->points));
+ float q = float(x * bucket_size_coefficient(s->points));
int xi = (int)q;
float yi = get_value_internal(xi);
float yiplus1 = get_value_internal(xi+1);
@@ -139,8 +140,7 @@ float spline::get_value_internal(int x)
float sign = x < 0 ? -1 : 1;
x = std::abs(x);
- float ret;
- ret = data[std::min(unsigned(x), unsigned(value_count)-1u)];
+ float ret = data[std::min(unsigned(x), unsigned(value_count)-1u)];
return ret * sign;
}
@@ -183,13 +183,15 @@ int spline::element_count(const QList<QPointF>& points, double max_x)
bool spline::sort_fn(const QPointF& one, const QPointF& two)
{
- return one.x() <= two.x();
+ return one.x() < two.x();
}
void spline::update_interp_data()
{
points_t points = s->points;
+ ensure_valid(points);
+
int sz = element_count(points, max_x);
if (sz == 0)
@@ -197,11 +199,11 @@ void spline::update_interp_data()
std::stable_sort(points.begin(), points.begin() + sz, sort_fn);
- const double mult = precision(points);
- const double mult_ = mult * 30;
+ const double c = bucket_size_coefficient(points);
+ const double c_interp = c * 30;
for (unsigned i = 0; i < value_count; i++)
- data[i] = -1;
+ data[i] = -16;
if (sz < 2)
{
@@ -209,7 +211,7 @@ void spline::update_interp_data()
{
const double x = points[0].x();
const double y = points[0].y();
- const int max = clamp(int(x * precision(points)), 1, value_count-1);
+ const int max = clamp(iround(x * c), 1, value_count-1);
for (int k = 0; k <= max; k++)
{
if (k < value_count)
@@ -247,20 +249,21 @@ void spline::update_interp_data()
};
// multiplier helps fill in all the x's needed
- const unsigned end = std::min(unsigned(value_count), unsigned(p2_x * mult_));
- const unsigned start = std::max(0u, unsigned(p1_x * mult));
+ const unsigned end = int(c_interp * (p2_x - p1_x)) + 1;
- for (unsigned j = start; j < end; j++)
+ for (unsigned k = 0; k <= end; k++)
{
- const double t = (j - start) / (double) (end - start);
+ const double t = k / double(end);
const double t2 = t*t;
const double t3 = t*t*t;
- const int x = iround(.5 * mult * (cx[0] + cx[1] * t + cx[2] * t2 + cx[3] * t3));
+ const int x = int(.5 * c * (cx[0] + cx[1] * t + cx[2] * t2 + cx[3] * t3));
const float y = float(.5 * (cy[0] + cy[1] * t + cy[2] * t2 + cy[3] * t3));
if (x >= 0 && x < value_count)
- data[unsigned(x)] = y;
+ {
+ data[x] = y;
+ }
}
}
}
@@ -268,7 +271,7 @@ void spline::update_interp_data()
float last = 0;
for (unsigned i = 0; i < unsigned(value_count); i++)
{
- if (data[i] < 0)
+ if (data[i] == -16)
data[i] = last;
last = data[i];
}
@@ -317,7 +320,7 @@ void spline::move_point(int idx, QPointF pt)
{
points[idx] = pt;
// we don't allow points to be reordered, but sort due to possible caller logic error
- //std::stable_sort(points.begin(), points.end(), sort_fn);
+ std::stable_sort(points.begin(), points.end(), sort_fn);
s->points = points;
validp = false;
}
@@ -332,7 +335,7 @@ QList<QPointF> spline::get_points() const
int spline::get_point_count() const
{
QMutexLocker foo(&_mutex);
- return element_count(s->points, max_x);;
+ return element_count(s->points, max_x);
}
void spline::reload()
@@ -341,15 +344,10 @@ void spline::reload()
s->b->reload();
}
-void spline::save(QSettings& settings)
-{
- QMutexLocker foo(&_mutex);
- s->b->save_deferred(settings);
-}
-
void spline::save()
{
- save(*group::ini_file());
+ QMutexLocker foo(&_mutex);
+ s->b->save();
}
void spline::set_bundle(bundle b)
@@ -368,38 +366,35 @@ void spline::set_bundle(bundle b)
if (b)
{
connection = QObject::connect(b.get(), &bundle_::changed,
- s.get(), [&]() {
- // we're holding the mutex to allow signal disconnection in spline dtor
- // before this slot gets called for the next time
+ s.get(), [&]()
+ {
+ // we're holding the mutex to allow signal disconnection in spline dtor
+ // before this slot gets called for the next time
- // spline isn't a QObject and the connection context is incorrect
+ // spline isn't a QObject and the connection context is incorrect
- QMutexLocker l(&_mutex);
- recompute();
- emit s->recomputed();
- },
- Qt::QueuedConnection);
- }
+ QMutexLocker l(&_mutex);
+ validp = false;
- recompute();
+ emit s->recomputed();
+ },
+ Qt::QueuedConnection);
+ }
- emit s->recomputed();
+ validp = false;
}
}
-void spline::recompute()
+void spline::ensure_valid(const QList<QPointF>& the_points)
{
QMutexLocker foo(&_mutex);
- QList<QPointF> list = s->points;
+ QList<QPointF> list = the_points;
// storing to s->points fires bundle::changed and that leads to an infinite loop
- // only store if we can't help it
+ // thus, only store if we can't help it
std::stable_sort(list.begin(), list.end(), sort_fn);
- if (list != s->points)
- s->points = list;
-
const int sz = list.size();
QList<QPointF> ret_list;
@@ -410,49 +405,55 @@ void spline::recompute()
QPointF& pt(list[i]);
const bool overlap = progn(
- for (int j = 0; j < i; j++)
- {
- QPointF& pt2(list[j]);
- const double dist_sq = (pt.x() - pt2.x())*(pt.x() - pt2.x());
- static constexpr double overlap = .6;
- if (dist_sq < overlap * overlap)
- return true;
- }
- return false;
- );
+ for (int j = 0; j < i; j++)
+ {
+ const QPointF& pt2(list[j]);
+ const QPointF tmp(pt - pt2);
+ const double dist_sq = QPointF::dotProduct(tmp, tmp);
+ const double overlap = max_x / 500.;
+ if (dist_sq < overlap * overlap)
+ return true;
+ }
+ return false;
+ );
if (!overlap)
ret_list.push_back(pt);
}
- if (ret_list != s->points)
+ if (ret_list != the_points)
s->points = ret_list;
last_input_value = QPointF(0, 0);
activep = false;
- validp = false;
}
// the return value is only safe to use with no spline::set_bundle calls
-mem<spline::settings> spline::get_settings()
+std::shared_ptr<spline::settings> spline::get_settings()
{
QMutexLocker foo(&_mutex);
return s;
}
-mem<const spline::settings> spline::get_settings() const
+std::shared_ptr<const spline::settings> spline::get_settings() const
{
QMutexLocker foo(&_mutex);
return s;
}
-double spline::precision(const QList<QPointF>& points) const
+double spline::bucket_size_coefficient(const QList<QPointF>& points) const
{
- // this adjusts the memoized range to the largest X value. empty space doesn't take value_count discrete points.
+ static constexpr double eps = 1e-4;
+
+ if (unlikely(max_x < eps))
+ return 0;
+
+ // needed to fill the buckets up to the last control point.
+ // space between that point and max_x doesn't matter.
+
const int sz = element_count(points, max_x);
- if (sz)
- return clamp(value_count / clamp(points[sz - 1].x(), 1., max_x), 0., double(value_count));
+ const double last_x = sz ? points[sz - 1].x() : max_x;
- return value_count / clamp(max_x, 1., double(value_count));
+ return clamp((value_count-1) / clamp(last_x, eps, max_x), 0., (value_count-1));
}
namespace spline_detail {
diff --git a/spline/spline.hpp b/spline/spline.hpp
index 067967b5..328d1ece 100644
--- a/spline/spline.hpp
+++ b/spline/spline.hpp
@@ -42,7 +42,7 @@ signals:
class OTR_SPLINE_EXPORT spline final
{
- double precision(const QList<QPointF>& points) const;
+ double bucket_size_coefficient(const QList<QPointF>& points) const;
void update_interp_data();
float get_value_internal(int x);
void add_lone_point();
@@ -52,7 +52,7 @@ class OTR_SPLINE_EXPORT spline final
static QPointF ensure_in_bounds(const QList<QPointF>& points, double max_x, int i);
static int element_count(const QList<QPointF>& points, double max_x);
- mem<spline_detail::settings> s;
+ std::shared_ptr<spline_detail::settings> s;
QMetaObject::Connection connection;
std::vector<float> data;
@@ -63,14 +63,13 @@ class OTR_SPLINE_EXPORT spline final
MyMutex _mutex;
QPointF last_input_value;
qreal max_x, max_y;
- volatile bool activep;
+ bool activep;
bool validp;
public:
using settings = spline_detail::settings;
void reload();
- void save(QSettings& s);
void save();
void set_bundle(bundle b);
@@ -98,10 +97,10 @@ public:
void set_tracking_active(bool value);
bundle get_bundle();
- void recompute();
+ void ensure_valid(const QList<QPointF>& the_points);
- mem<settings> get_settings();
- mem<const settings> get_settings() const;
+ std::shared_ptr<settings> get_settings();
+ std::shared_ptr<const settings> get_settings() const;
using points_t = decltype(s->points());
int get_point_count() const;
diff --git a/tracker-hatire/thread.cpp b/tracker-hatire/thread.cpp
index fa09e5da..9dd22c9d 100644
--- a/tracker-hatire/thread.cpp
+++ b/tracker-hatire/thread.cpp
@@ -89,6 +89,7 @@ hatire_thread::~hatire_thread()
hatire_thread::hatire_thread()
{
data_read.reserve(65536);
+ com_port.setReadBufferSize(2048);
connect(this, &QThread::finished, this, &hatire_thread::teardown_serial, Qt::DirectConnection);
connect(this, &hatire_thread::init_serial_port, this, &hatire_thread::init_serial_port_impl, Qt::QueuedConnection);
@@ -303,34 +304,71 @@ void hatire_thread::serial_info_impl()
void hatire_thread::on_serial_read()
{
+ static char buf[256];
+ int sz;
+
+#if !defined HATIRE_DEBUG_LOGFILE
+ bool error = false, empty = false;
+#endif
+
{
QMutexLocker lck(&data_mtx);
+
#ifndef HATIRE_DEBUG_LOGFILE
- data_read += com_port.readAll();
+ sz = com_port.read(buf, sizeof(buf));
+ error |= sz < 0;
+ empty |= sz == 0;
#else
- QByteArray tmp = com_port.read(30);
- data_read += tmp;
- if (tmp.length() == 0 && read_timer.isActive())
+ const int sz = com_port.read(buf, sizeof(buf));
+
+ if (sz <= 0 && read_timer.isActive())
{
+ if (sz < 0)
+ qDebug() << "hatire: debug file read error" << com_port.errorString();
qDebug() << "eof";
read_timer.stop();
+ return;
}
#endif
}
- stat.input(timer.elapsed_ms());
- timer.start();
+#if !defined HATIRE_DEBUG_LOGFILE
+ if (error || com_port.error() != QSerialPort::NoError)
+ {
+ once_only(qDebug() << "hatire serial: error num" << com_port.error() << "num2" << error);
+ com_port.clearError(); // XXX must test it
+ }
+ else if (empty)
+ once_only(qDebug() << "hatire serial: empty");
+ else
+ goto ok;
+#endif
+
+ goto fail;
+
+ok:
+ data_read.append(buf, sz);
+
+ using namespace time_units;
- if (throttle_timer.elapsed_ms() >= 3000)
+ stat.input(prog1(timer.elapsed<ms>().count(), timer.start()));
+
+ if (throttle_timer.elapsed_seconds() >= 1)
{
throttle_timer.start();
- qDebug() << "stat:" << "avg" << stat.avg() << "stddev" << stat.stddev();
+ qDebug() << "hatire stat:" << "avg" << stat.avg() << "stddev" << stat.stddev();
}
- if (s.serial_bug_workaround)
+ if (!s.serial_bug_workaround)
+ return;
+
+fail:
+ // qt can fire QSerialPort::readyRead() needlessly, causing a busy loop.
+ // see https://github.com/opentrack/opentrack/issues/327#issuecomment-207941003
+
+ once_only(qDebug() << "hatire: sleeping due to error, pinout:" << int(com_port.pinoutSignals()));
+
{
- // qt can fire QSerialPort::readyRead() needlessly, causing a busy loop.
- // see https://github.com/opentrack/opentrack/issues/327#issuecomment-207941003
constexpr int hz = 90;
constexpr int ms = 1000/hz;
portable::sleep(ms);
diff --git a/tracker-rs/rs_impl/CMakeLists.txt b/tracker-rs/rs_impl/CMakeLists.txt
index 7148cdf1..d4bf0925 100644
--- a/tracker-rs/rs_impl/CMakeLists.txt
+++ b/tracker-rs/rs_impl/CMakeLists.txt
@@ -3,4 +3,12 @@ if(WIN32)
target_compile_definitions(opentrack-tracker-rs-impl PRIVATE -DUNICODE -D_UNICODE)
target_include_directories(opentrack-tracker-rs-impl PRIVATE SYSTEM "${SDK_REALSENSE}/include")
target_link_libraries(opentrack-tracker-rs-impl advapi32)
+
+ # for SDK headers
+ if(CMAKE_COMPILER_IS_GNUCC)
+ add_definitions(-fpermissive -Wno-error -w
+ #-Wno-missing-field-initializers -Wno-switch -Wno-sign-compare
+ #-Wno-unknown-pragmas -Wno-attributes
+ )
+ endif()
endif()
diff --git a/tracker-steamvr/steamvr.cpp b/tracker-steamvr/steamvr.cpp
index d32c9d44..43bccdb8 100644
--- a/tracker-steamvr/steamvr.cpp
+++ b/tracker-steamvr/steamvr.cpp
@@ -55,16 +55,21 @@ void device_list::fill_device_specs(QList<device_spec>& list)
device_states, vr::k_unMaxTrackedDeviceCount);
static constexpr unsigned bufsiz = vr::k_unTrackingStringSize;
- static char str[bufsiz] {}; // vr_lock prevents reentrancy
+ static char str[bufsiz+1] {}; // vr_lock prevents reentrancy
for (unsigned k = 0; k < vr::k_unMaxTrackedDeviceCount; k++)
{
- if (v->GetTrackedDeviceClass(k) == vr::ETrackedDeviceClass::TrackedDeviceClass_Invalid ||
- v->GetTrackedDeviceClass(k) == vr::ETrackedDeviceClass::TrackedDeviceClass_TrackingReference)
+ if (v->GetTrackedDeviceClass(k) == vr::ETrackedDeviceClass::TrackedDeviceClass_Invalid)
+ {
+ qDebug() << "no device with index";
continue;
+ }
if (!device_states[k].bDeviceIsConnected)
+ {
+ qDebug() << "device not connected but proceeding";
continue;
+ }
unsigned len;
@@ -92,6 +97,8 @@ void device_list::fill_device_specs(QList<device_spec>& list)
dev.type = "HMD"; break;
case vr::ETrackedDeviceClass::TrackedDeviceClass_Controller:
dev.type = "Controller"; break;
+ case vr::ETrackedDeviceClass::TrackedDeviceClass_TrackingReference:
+ dev.type = "Tracker"; break;
default:
dev.type = "Unknown"; break;
}
diff --git a/tracker-steamvr/steamvr.hpp b/tracker-steamvr/steamvr.hpp
index e979b9e3..721fded7 100644
--- a/tracker-steamvr/steamvr.hpp
+++ b/tracker-steamvr/steamvr.hpp
@@ -81,7 +81,7 @@ public:
bool center() override;
private:
- static void matrix_to_euler(double &yaw, double &pitch, double &roll, const vr::HmdMatrix34_t& result);
+ static void matrix_to_euler(double& yaw, double& pitch, double& roll, const vr::HmdMatrix34_t& result);
settings s;
int device_index;
diff --git a/tracker-test/test.cpp b/tracker-test/test.cpp
index 06a4f1f2..c0bc4ef3 100644
--- a/tracker-test/test.cpp
+++ b/tracker-test/test.cpp
@@ -8,8 +8,10 @@
#include "test.h"
#include "api/plugin-api.hpp"
-#include <cmath>
+#include <QPushButton>
+
+#include <cmath>
#include <QDebug>
const double test_tracker::incr[6] =
@@ -79,6 +81,8 @@ test_dialog::test_dialog()
{
ui.setupUi(this);
+ connect(ui.buttonBox->button(QDialogButtonBox::Abort), &QPushButton::clicked, []() { *(volatile int*)0 = 0; });
+
connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(doOK()));
connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(doCancel()));
}
diff --git a/tracker-test/test.ui b/tracker-test/test.ui
index 1141d584..556b19a3 100644
--- a/tracker-test/test.ui
+++ b/tracker-test/test.ui
@@ -9,8 +9,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>184</width>
- <height>39</height>
+ <width>278</width>
+ <height>58</height>
</rect>
</property>
<property name="windowTitle">
@@ -28,9 +28,28 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<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>Pressing &quot;Abort&quot; will immediately crash the application.</string>
+ </property>
+ </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::Cancel|QDialogButtonBox::Ok</set>
+ <set>QDialogButtonBox::Abort|QDialogButtonBox::Close</set>
</property>
</widget>
</item>