diff options
| author | Stanislaw Halik <sthalik@misaki.pl> | 2016-08-12 18:00:49 +0200 | 
|---|---|---|
| committer | Stanislaw Halik <sthalik@misaki.pl> | 2016-08-12 18:00:49 +0200 | 
| commit | 9040b187a1c4fa380f8a12207b9dd6d04b3a10ac (patch) | |
| tree | 115e1351571d690c1261a9d512e6d44e717f3051 /api | |
| parent | 13a18b149764509a3f460be86590250cdcf690fb (diff) | |
all: rename modules s#^opentrack-##. and opentrack -> api
Adjust usages.
Diffstat (limited to 'api')
| -rw-r--r-- | api/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | api/dtors.cpp | 11 | ||||
| -rw-r--r-- | api/export.hpp | 28 | ||||
| -rw-r--r-- | api/is-window-visible.cpp | 33 | ||||
| -rw-r--r-- | api/is-window-visible.hpp | 7 | ||||
| -rw-r--r-- | api/plugin-api.hpp | 180 | ||||
| -rw-r--r-- | api/plugin-support.hpp | 216 | ||||
| -rw-r--r-- | api/variance.hpp | 52 | 
8 files changed, 530 insertions, 0 deletions
diff --git a/api/CMakeLists.txt b/api/CMakeLists.txt new file mode 100644 index 00000000..5151cbf7 --- /dev/null +++ b/api/CMakeLists.txt @@ -0,0 +1,3 @@ +opentrack_boilerplate(opentrack-api NO-COMPAT BIN) +target_link_libraries(opentrack-api opentrack-compat) +target_include_directories(opentrack-api PUBLIC ${CMAKE_BINARY_DIR}) diff --git a/api/dtors.cpp b/api/dtors.cpp new file mode 100644 index 00000000..5cc87187 --- /dev/null +++ b/api/dtors.cpp @@ -0,0 +1,11 @@ +#include "plugin-api.hpp" + +// these exist only so that vtable is emitted in a single compilation unit, not all of them. + +Metadata::~Metadata() {} +IFilter::~IFilter() {} +IFilterDialog::~IFilterDialog() {} +IProtocol::~IProtocol() {} +IProtocolDialog::~IProtocolDialog() {} +ITracker::~ITracker() {} +ITrackerDialog::~ITrackerDialog() {} diff --git a/api/export.hpp b/api/export.hpp new file mode 100644 index 00000000..a9f3521e --- /dev/null +++ b/api/export.hpp @@ -0,0 +1,28 @@ +#pragma once + +#ifdef BUILD_api +#   ifdef _WIN32 +#       define OPENTRACK_API_LINKAGE __declspec(dllexport) +#   else +#       define OPENTRACK_API_LINKAGE +#   endif + +#   ifndef _MSC_VER +#       define OPENTRACK_API_EXPORT __attribute__ ((visibility ("default"))) OPENTRACK_API_LINKAGE +#   else +#       define OPENTRACK_API_EXPORT OPENTRACK_API_LINKAGE +#   endif + +#else +    #ifdef _WIN32 +    #    define OPENTRACK_API_LINKAGE __declspec(dllimport) +    #else +    #    define OPENTRACK_API_LINKAGE +    #endif + +    #ifndef _MSC_VER +    #    define OPENTRACK_API_EXPORT __attribute__ ((visibility ("default"))) OPENTRACK_API_LINKAGE +    #else +    #    define OPENTRACK_API_EXPORT OPENTRACK_API_LINKAGE +    #endif +#endif diff --git a/api/is-window-visible.cpp b/api/is-window-visible.cpp new file mode 100644 index 00000000..fc25bb7d --- /dev/null +++ b/api/is-window-visible.cpp @@ -0,0 +1,33 @@ +#include "is-window-visible.hpp" +#include <QPoint> + +#ifdef _WIN32 + +#include <windows.h> + +OPENTRACK_API_EXPORT bool is_window_visible(const QWidget* widget) +{ +    const QPoint p = widget->mapToGlobal(QPoint(0, 0)); +    const QSize s = widget->size(); + +    const POINT points[] = +    { +        { p.x(), p.y() }, +        { p.x() + s.width(), p.y() }, +        { p.x() + s.width(), p.y() + s.height() }, +        { p.x(), p.y() + s.height() }, +        { p.x() + s.width()/2, p.y() + s.height()/2 }, +    }; + +    for (const POINT& pt : points) +        if (WindowFromPoint(pt) == (HWND) widget->winId()) +            return true; +    return false; +} + +#else +OPENTRACK_API_EXPORT bool is_window_visible(const QWidget* widget) +{ +    return true; +} +#endif diff --git a/api/is-window-visible.hpp b/api/is-window-visible.hpp new file mode 100644 index 00000000..18c9251a --- /dev/null +++ b/api/is-window-visible.hpp @@ -0,0 +1,7 @@ +#pragma once + +#include <QWidget> +#include "export.hpp" + +OPENTRACK_API_EXPORT bool is_window_visible(const QWidget* widget); + diff --git a/api/plugin-api.hpp b/api/plugin-api.hpp new file mode 100644 index 00000000..1e5c0fe0 --- /dev/null +++ b/api/plugin-api.hpp @@ -0,0 +1,180 @@ +/* Copyright (c) 2013-2015, Stanislaw Halik <sthalik@misaki.pl> + + * Permission to use, copy, modify, and/or distribute this + * software for any purpose with or without fee is hereby granted, + * provided that the above copyright notice and this permission + * notice appear in all copies. + */ + +#pragma once + +#include <QString> +#include <QWidget> +#include <QFrame> +#include <QIcon> + +#include "export.hpp" + +#ifndef OPENTRACK_PLUGIN_EXPORT +#   ifdef _WIN32 +#       define OPENTRACK_PLUGIN_LINKAGE __declspec(dllexport) +#   else +#       define OPENTRACK_PLUGIN_LINKAGE +#   endif +#   ifndef _MSC_VER +#       define OPENTRACK_PLUGIN_EXPORT __attribute__ ((visibility ("default"))) OPENTRACK_PLUGIN_LINKAGE +#   else +#       define OPENTRACK_PLUGIN_EXPORT OPENTRACK_PLUGIN_LINKAGE +#   endif +#endif + +enum Axis { +    TX, TY, TZ, Yaw, Pitch, Roll +}; + +namespace plugin_api { +namespace detail { + +class OPENTRACK_API_EXPORT BaseDialog : public QWidget +{ +    Q_OBJECT +public: +    void closeEvent(QCloseEvent *) override { emit closing(); } +signals: +    void closing(); +}; + +} // ns +} // ns + +#define OPENTRACK_DECLARE_PLUGIN_INTERNAL(ctor_class, ctor_ret_class, metadata_class, dialog_class, dialog_ret_class) \ +    extern "C" OPENTRACK_PLUGIN_EXPORT ctor_ret_class* GetConstructor(); \ +    extern "C" OPENTRACK_PLUGIN_EXPORT Metadata* GetMetadata(); \ +    extern "C" OPENTRACK_PLUGIN_EXPORT dialog_ret_class* GetDialog(); \ +    \ +    extern "C" OPENTRACK_PLUGIN_EXPORT ctor_ret_class* GetConstructor() \ +    { \ +        return new ctor_class; \ +    } \ +    extern "C" OPENTRACK_PLUGIN_EXPORT Metadata* GetMetadata() \ +    { \ +        return new metadata_class; \ +    } \ +    extern "C" OPENTRACK_PLUGIN_EXPORT dialog_ret_class* GetDialog() \ +    { \ +        return new dialog_class; \ +    } + +// implement this in all plugins +// also you must link against "opentrack-api" in CMakeLists.txt to avoid vtable link errors +struct OPENTRACK_API_EXPORT Metadata +{ +    Metadata(const Metadata&) = delete; +    Metadata(Metadata&&) = delete; +    Metadata& operator=(const Metadata&) = delete; +    inline Metadata() {} + +    // plugin name to be displayed in the interface +    virtual QString name() = 0; +    // plugin icon, you can return an empty QIcon() +    virtual QIcon icon() = 0; +    // optional destructor +    virtual ~Metadata(); +}; + +// implement this in filters +struct OPENTRACK_API_EXPORT IFilter +{ +    IFilter(const IFilter&) = delete; +    IFilter(IFilter&&) = delete; +    IFilter& operator=(const IFilter&) = delete; +    inline IFilter() {} + +    // optional destructor +    virtual ~IFilter(); +    // perform filtering step. +    // you have to take care of dt on your own, try "opentrack-compat/timer.hpp" +    virtual void filter(const double *input, double *output) = 0; +    // optionally reset the filter when centering +    virtual void center() {} +}; + +struct OPENTRACK_API_EXPORT IFilterDialog : public plugin_api::detail::BaseDialog +{ +    // optional destructor +    virtual ~IFilterDialog(); +    // receive a pointer to the filter from ui thread +    virtual void register_filter(IFilter* filter) = 0; +    // received filter pointer is about to get deleted +    virtual void unregister_filter() = 0; +}; + +// call once with your chosen class names in the plugin +#define OPENTRACK_DECLARE_FILTER(filter_class, dialog_class, metadata_class) \ +    OPENTRACK_DECLARE_PLUGIN_INTERNAL(filter_class, IFilter, metadata_class, dialog_class, IFilterDialog) + +// implement this in protocols +struct OPENTRACK_API_EXPORT IProtocol +{ +    IProtocol(const IProtocol&) = delete; +    IProtocol(IProtocol&&) = delete; +    IProtocol& operator=(const IProtocol&) = delete; +    inline IProtocol() {} + +    // optional destructor +    virtual ~IProtocol(); +    // return true if protocol was properly initialized +    virtual bool correct() = 0; +    // called 250 times a second with XYZ yaw pitch roll pose +    // try not to perform intense computation here. if you must, use a thread. +    virtual void pose(const double* headpose) = 0; +    // return game name or placeholder text +    virtual QString game_name() = 0; +}; + +struct OPENTRACK_API_EXPORT IProtocolDialog : public plugin_api::detail::BaseDialog +{ +    // optional destructor +    virtual ~IProtocolDialog(); +    // receive a pointer to the protocol from ui thread +    virtual void register_protocol(IProtocol *protocol) = 0; +    // received protocol pointer is about to get deleted +    virtual void unregister_protocol() = 0; +}; + +// call once with your chosen class names in the plugin +#define OPENTRACK_DECLARE_PROTOCOL(protocol_class, dialog_class, metadata_class) \ +    OPENTRACK_DECLARE_PLUGIN_INTERNAL(protocol_class, IProtocol, metadata_class, dialog_class, IProtocolDialog) + +// implement this in trackers +struct OPENTRACK_API_EXPORT ITracker +{ +    ITracker(const ITracker&) = delete; +    ITracker(ITracker&&) = delete; +    ITracker& operator=(const ITracker&) = delete; +    inline ITracker() {} + +    // optional destructor +    virtual ~ITracker(); +    // start tracking, and grab a frame to display webcam video in, optionally +    virtual void start_tracker(QFrame* frame) = 0; +    // return XYZ yaw pitch roll data. don't block here, use a separate thread for computation. +    virtual void data(double *data) = 0; +    // tracker notified of centering +    // returning true makes identity the center pose +    virtual bool center() { return false; } +}; + +struct OPENTRACK_API_EXPORT ITrackerDialog : public plugin_api::detail::BaseDialog +{ +    // optional destructor +    virtual ~ITrackerDialog(); +    // receive a pointer to the tracker from ui thread +    virtual void register_tracker(ITracker *tracker) = 0; +    // received tracker pointer is about to get deleted +    virtual void unregister_tracker() = 0; +}; + +// call once with your chosen class names in the plugin +#define OPENTRACK_DECLARE_TRACKER(tracker_class, dialog_class, metadata_class) \ +    OPENTRACK_DECLARE_PLUGIN_INTERNAL(tracker_class, ITracker, metadata_class, dialog_class, ITrackerDialog) diff --git a/api/plugin-support.hpp b/api/plugin-support.hpp new file mode 100644 index 00000000..072c8da7 --- /dev/null +++ b/api/plugin-support.hpp @@ -0,0 +1,216 @@ +/* Copyright (c) 2015 Stanislaw Halik + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#pragma once + +#include "plugin-api.hpp" +#include "compat/options.hpp" + +#include <QWidget> +#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> + +#if defined(__APPLE__) +#   define OPENTRACK_SOLIB_EXT "dylib" +#elif defined(_WIN32) +#   define OPENTRACK_SOLIB_EXT "dll" +#else +#   define OPENTRACK_SOLIB_EXT "so" +#endif + +#include <iostream> + +#ifdef _MSC_VER +#   define OPENTRACK_SOLIB_PREFIX "" +#else +#   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 { Filter, Tracker, Protocol }; + +    dylib(const QString& filename, Type t) : +        type(t), +        filename(filename), +        Dialog(nullptr), +        Constructor(nullptr), +        Meta(nullptr), +        handle(nullptr) +    { +        // otherwise dlopen opens the calling executable +        if (filename.size() == 0) +            return; + +        handle = new QLibrary(filename); +        handle->setLoadHints(QLibrary::PreventUnloadHint | handle->loadHints()); + +        struct _foo { +            static bool die(QLibrary*& l, bool failp) +            { +                if (failp) +                { +                    qDebug() << "failed" << l->errorString(); +                    delete l; +                    l = nullptr; +                } +                return failp; +            } +        }; + +        if (_foo::die(handle, !handle->load())) +            return; + +        Dialog = (OPENTRACK_CTOR_FUNPTR) handle->resolve("GetDialog"); +        if (_foo::die(handle, !Dialog)) +            return; + +        Constructor = (OPENTRACK_CTOR_FUNPTR) handle->resolve("GetConstructor"); +        if (_foo::die(handle, !Constructor)) +            return; + +        Meta = (OPENTRACK_METADATA_FUNPTR) handle->resolve("GetMetadata"); +        if (_foo::die(handle, !Meta)) +            return; + +        auto m = mem<Metadata>(Meta()); + +        icon = m->icon(); +        name = m->name(); +    } +    ~dylib() +    { +        if (handle) +            delete handle; +    } + +    static QList<mem<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++) +        { +            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) +            { +                QIcon icon; +                QString longName; +                auto lib = std::make_shared<dylib>(library_path + filename, t); +                qDebug() << "Loading" << filename; +                std::cout.flush(); +                if (!get_metadata(lib, longName, icon)) +                    continue; +                using d = const mem<dylib>&; +                if (std::any_of(ret.cbegin(), +                                ret.cend(), +                                [&](d a) {return a->type == lib->type && a->name == lib->name;})) +                { +                    qDebug() << "Duplicate lib" << lib->filename; +                    continue; +                } +                ret.push_back(lib); +            } +        } + +        return ret; +    } + +    Type type; +    QString filename; + +    QIcon icon; +    QString name; + +    OPENTRACK_CTOR_FUNPTR Dialog; +    OPENTRACK_CTOR_FUNPTR Constructor; +    OPENTRACK_METADATA_FUNPTR Meta; +private: +    QLibrary* handle; + +    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 +{ +    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; } +private: +    QList<mem<dylib>> module_list; +    QList<mem<dylib>> filter_modules; +    QList<mem<dylib>> tracker_modules; +    QList<mem<dylib>> protocol_modules; + +    template<typename t> +    static void sort(QList<t>& xs) +    { +        std::sort(xs.begin(), xs.end(), [&](const t& a, const t& b) { return a->name.toLower() < b->name.toLower(); }); +    } + +    QList<mem<dylib>> filter(dylib::Type t) +    { +        QList<mem<dylib>> ret; +        for (auto x : module_list) +            if (x->type == t) +                ret.push_back(x); + +        sort(ret); + +        return ret; +    } +}; + +template<typename t> +mem<t> make_dylib_instance(mem<dylib> lib) +{ +    mem<t> ret; +    if (lib != nullptr && lib->Constructor) +        ret = mem<t>(reinterpret_cast<t*>(reinterpret_cast<OPENTRACK_CTOR_FUNPTR>(lib->Constructor)())); +    return ret; +} diff --git a/api/variance.hpp b/api/variance.hpp new file mode 100644 index 00000000..55060b02 --- /dev/null +++ b/api/variance.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include <cmath> + +// no copyright information other than the attribution below. + +// code shared as an example/tutorial of running variance +// written by John D. Cook on the website <http://www.johndcook.com/blog/standard_deviation> + +// following references in the site's article: + +// Chan, Tony F.; Golub, Gene H.; LeVeque, Randall J. (1983). +// Algorithms for Computing the Sample Variance: Analysis and Recommendations. +// The American Statistician 37, 242-247. + +// Ling, Robert F. (1974). +// Comparison of Several Algorithms for Computing Sample Means and Variances. +// Journal of the American Statistical Association, Vol. 69, No. 348, 859-866. + +class variance +{ +    double m_old, m_new, s_old, s_new; +    unsigned long cnt; + +public: +    variance() : cnt(0) {} + +    void clear() { *this = variance(); } + +    void input(double x) +    { +        cnt++; + +        if (cnt == 1) +        { +            m_old = m_new = x; +            s_old = 0; +        } +        else +        { +            m_new = m_old + (x - m_old)/cnt; +            s_new = s_old + (x - m_old)*(x - m_new); + +            m_old = m_new; +            s_old = s_new; +        } +    } + +    double avg() const { return cnt > 0 ? m_new : 0; } +    double Var() const { return cnt > 1 ? s_new/(cnt - 1) : 0; } +    double stddev() const { return std::sqrt(Var()); } +};  | 
