Merge pull request #6162 from jherico/controllers

Controllers Branch - Fixing omnitool
This commit is contained in:
Brad Hefta-Gaub 2015-10-23 13:54:14 -07:00
commit e0211e4b0a
13 changed files with 239 additions and 113 deletions

View file

@ -15,16 +15,18 @@ Script.include("omniTool/models/invisibleWand.js");
OmniToolModules = {}; OmniToolModules = {};
OmniToolModuleType = null; OmniToolModuleType = null;
LOG_DEBUG = 1;
OmniTool = function(side) { OmniTool = function(left) {
this.OMNI_KEY = "OmniTool"; this.OMNI_KEY = "OmniTool";
this.MAX_FRAMERATE = 60; this.MAX_FRAMERATE = 60;
this.UPDATE_INTERVAL = 1.0 / this.MAX_FRAMERATE this.UPDATE_INTERVAL = 1.0 / this.MAX_FRAMERATE
this.SIDE = side; this.left = left;
this.PALM = 2 * side; this.triggered = false;
this.ACTION = findAction(side ? "ACTION2" : "ACTION1"); var actions = Controller.Actions;
this.ALT_ACTION = findAction(side ? "ACTION1" : "ACTION2"); var standard = Controller.Standard;
this.palmControl = left ? actions.LeftHand : actions.RightHand;
logDebug("Init OmniTool " + (left ? "left" : "right"));
this.highlighter = new Highlighter(); this.highlighter = new Highlighter();
this.ignoreEntities = {}; this.ignoreEntities = {};
this.nearestOmniEntity = { this.nearestOmniEntity = {
@ -47,22 +49,25 @@ OmniTool = function(side) {
this.showWand(false); this.showWand(false);
// Connect to desired events // Connect to desired events
var _this = this; var that = this;
Controller.actionEvent.connect(function(action, state) {
_this.onActionEvent(action, state);
});
Script.update.connect(function(deltaTime) { Script.update.connect(function(deltaTime) {
_this.lastUpdateInterval += deltaTime; that.lastUpdateInterval += deltaTime;
if (_this.lastUpdateInterval >= _this.UPDATE_INTERVAL) { if (that.lastUpdateInterval >= that.UPDATE_INTERVAL) {
_this.onUpdate(_this.lastUpdateInterval); that.onUpdate(that.lastUpdateInterval);
_this.lastUpdateInterval = 0; that.lastUpdateInterval = 0;
} }
}); });
Script.scriptEnding.connect(function() { Script.scriptEnding.connect(function() {
_this.onCleanup(); that.onCleanup();
}); });
this.mapping = Controller.newMapping();
this.mapping.from(left ? standard.LeftPrimaryThumb : standard.RightPrimaryThumb).to(function(value){
that.onUpdateTrigger(value);
})
this.mapping.enable();
} }
OmniTool.prototype.showWand = function(show) { OmniTool.prototype.showWand = function(show) {
@ -81,30 +86,23 @@ OmniTool.prototype.showWand = function(show) {
} }
} }
OmniTool.prototype.onCleanup = function(action) { OmniTool.prototype.onCleanup = function(action) {
this.mapping.disable();
this.unloadModule(); this.unloadModule();
} }
OmniTool.prototype.onActionEvent = function(action, state) {
// FIXME figure out the issues when only one spatial controller is active
// logDebug("Action: " + action + " " + state);
if (this.module && this.module.onActionEvent) { OmniTool.prototype.onUpdateTrigger = function (value) {
this.module.onActionEvent(action, state); //logDebug("Trigger update value " + value);
} var triggered = value != 0;
if (triggered != this.triggered) {
if (action == this.ACTION) { this.triggered = triggered;
if (state) { if (this.triggered) {
this.onClick(); this.onClick();
} else { } else {
this.onRelease(); this.onRelease();
} }
} }
// FIXME Does not work
//// with only one controller active (listed as 2 here because 'tip' + 'palm')
//// then treat the alt action button as the action button
} }
OmniTool.prototype.getOmniToolData = function(entityId) { OmniTool.prototype.getOmniToolData = function(entityId) {
@ -127,7 +125,7 @@ OmniTool.prototype.setActive = function(active) {
if (active === this.active) { if (active === this.active) {
return; return;
} }
logDebug("OmniTool changing active state: " + active); logDebug("OmniTool " + this.left + " changing active state: " + active);
this.active = active; this.active = active;
this.model.setVisible(this.active); this.model.setVisible(this.active);
if (this.module && this.module.onActiveChanged) { if (this.module && this.module.onActiveChanged) {
@ -138,17 +136,17 @@ OmniTool.prototype.setActive = function(active) {
OmniTool.prototype.onUpdate = function(deltaTime) { OmniTool.prototype.onUpdate = function(deltaTime) {
// FIXME this returns data if either the left or right controller is not on the base // FIXME this returns data if either the left or right controller is not on the base
this.position = Controller.getSpatialControlPosition(this.PALM); this.pose = Controller.getPoseValue(this.palmControl);
this.position = this.left ? MyAvatar.leftHandTipPosition : MyAvatar.rightHandTipPosition;
// When on the base, hydras report a position of 0 // When on the base, hydras report a position of 0
this.setActive(Vec3.length(this.position) > 0.001); this.setActive(Vec3.length(this.position) > 0.001);
if (!this.active) { if (!this.active) {
return; return;
} }
if (this.model) { if (this.model) {
// Update the wand // Update the wand
var rawRotation = Controller.getSpatialControlRawRotation(this.PALM); var rawRotation = this.pose.rotation;
this.rotation = Quat.multiply(MyAvatar.orientation, rawRotation); this.rotation = Quat.multiply(MyAvatar.orientation, rawRotation);
this.model.setTransform({ this.model.setTransform({
rotation: this.rotation, rotation: this.rotation,
@ -306,6 +304,7 @@ OmniTool.prototype.scan = function() {
} }
OmniTool.prototype.unloadModule = function() { OmniTool.prototype.unloadModule = function() {
logDebug("Unloading omniTool module")
if (this.module && this.module.onUnload) { if (this.module && this.module.onUnload) {
this.module.onUnload(); this.module.onUnload();
} }
@ -348,4 +347,4 @@ OmniTool.prototype.activateNewOmniModule = function() {
} }
// FIXME find a good way to sync the two omni tools // FIXME find a good way to sync the two omni tools
OMNI_TOOLS = [ new OmniTool(0), new OmniTool(1) ]; OMNI_TOOLS = [ new OmniTool(true), new OmniTool(false) ];

View file

@ -31,13 +31,7 @@ scaleLine = function (start, end, scale) {
} }
findAction = function(name) { findAction = function(name) {
var actions = Controller.getAllActions(); return Controller.findAction(name);
for (var i = 0; i < actions.length; i++) {
if (actions[i].actionName == name) {
return i;
}
}
return 0;
} }
addLine = function(origin, vector, color) { addLine = function(origin, vector, color) {

View file

@ -627,7 +627,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
// Setup the userInputMapper with the actions // Setup the userInputMapper with the actions
auto userInputMapper = DependencyManager::get<UserInputMapper>(); auto userInputMapper = DependencyManager::get<UserInputMapper>();
connect(userInputMapper.data(), &UserInputMapper::actionEvent, _controllerScriptingInterface, &ControllerScriptingInterface::actionEvent);
connect(userInputMapper.data(), &UserInputMapper::actionEvent, [this](int action, float state) { connect(userInputMapper.data(), &UserInputMapper::actionEvent, [this](int action, float state) {
if (state && action == toInt(controller::Action::TOGGLE_MUTE)) { if (state && action == toInt(controller::Action::TOGGLE_MUTE)) {
DependencyManager::get<AudioClient>()->toggleMute(); DependencyManager::get<AudioClient>()->toggleMute();

View file

@ -120,8 +120,6 @@ signals:
void wheelEvent(const WheelEvent& event); void wheelEvent(const WheelEvent& event);
void actionEvent(int action, float state);
private: private:
QString sanatizeName(const QString& name); /// makes a name clean for inclusing in JavaScript QString sanatizeName(const QString& name); /// makes a name clean for inclusing in JavaScript

View file

@ -0,0 +1,37 @@
//
// Created by Bradley Austin Davis 2015/10/20
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#pragma once
#ifndef hifi_Controllers_Forward_h
#define hifi_Controllers_Forward_h
namespace controller {
class Endpoint;
using EndpointPointer = std::shared_ptr<Endpoint>;
using EndpointList = std::list<EndpointPointer>;
class Filter;
using FilterPointer = std::shared_ptr<Filter>;
using FilterList = std::list<FilterPointer>;
class Route;
using RoutePointer = std::shared_ptr<Route>;
using RouteList = std::list<RoutePointer>;
class Conditional;
using ConditionalPointer = std::shared_ptr<Conditional>;
using ConditionalList = std::list<ConditionalPointer>;
class Mapping;
using MappingPointer = std::shared_ptr<Mapping>;
using MappingList = std::list<MappingPointer>;
}
#endif

View file

@ -9,10 +9,9 @@
#include "Input.h" #include "Input.h"
namespace controller { namespace controller {
const Input Input::INVALID_INPUT = Input(0x7fffffff);
const uint16_t Input::INVALID_DEVICE = 0xffff; const uint16_t Input::INVALID_DEVICE = Input::INVALID_INPUT.device;
const uint16_t Input::INVALID_CHANNEL = 0x1fff; const uint16_t Input::INVALID_CHANNEL = Input::INVALID_INPUT.channel;
const uint16_t Input::INVALID_TYPE = (uint16_t)ChannelType::INVALID; const uint16_t Input::INVALID_TYPE = Input::INVALID_INPUT.type;
const Input Input::INVALID_INPUT = Input(INVALID_DEVICE, INVALID_CHANNEL, ChannelType::INVALID);
} }

View file

@ -16,10 +16,12 @@
namespace controller { namespace controller {
enum class ChannelType { enum class ChannelType {
INVALID = 0, UNKNOWN = 0,
BUTTON = 1, BUTTON,
AXIS, AXIS,
POSE, POSE,
RUMBLE,
INVALID = 0x7
}; };
// Input is the unique identifier to find a n input channel of a particular device // Input is the unique identifier to find a n input channel of a particular device
@ -30,8 +32,8 @@ struct Input {
uint32_t id{ 0 }; // by default Input is 0 meaning invalid uint32_t id{ 0 }; // by default Input is 0 meaning invalid
struct { struct {
uint16_t device; // Up to 64K possible devices uint16_t device; // Up to 64K possible devices
uint16_t channel : 13 ; // 2^13 possible channel per Device uint16_t channel : 12 ; // 2^12 possible channel per Device
uint16_t type : 2; // 2 bits to store the Type directly in the ID uint16_t type : 3; // 2 bits to store the Type directly in the ID
uint16_t padding : 1; // 2 bits to store the Type directly in the ID uint16_t padding : 1; // 2 bits to store the Type directly in the ID
}; };
}; };

View file

@ -44,6 +44,9 @@ static QVariantMap createDeviceMap(const controller::DeviceProxy::Pointer device
controller::ScriptingInterface::ScriptingInterface() { controller::ScriptingInterface::ScriptingInterface() {
auto userInputMapper = DependencyManager::get<UserInputMapper>(); auto userInputMapper = DependencyManager::get<UserInputMapper>();
connect(userInputMapper.data(), &UserInputMapper::actionEvent, this, &controller::ScriptingInterface::actionEvent);
connect(userInputMapper.data(), &UserInputMapper::inputEvent, this, &controller::ScriptingInterface::inputEvent);
// FIXME make this thread safe // FIXME make this thread safe
connect(userInputMapper.data(), &UserInputMapper::hardwareChanged, [=] { connect(userInputMapper.data(), &UserInputMapper::hardwareChanged, [=] {
updateMaps(); updateMaps();

View file

@ -129,6 +129,9 @@ namespace controller {
virtual void captureActionEvents() { _actionsCaptured = true; } virtual void captureActionEvents() { _actionsCaptured = true; }
virtual void releaseActionEvents() { _actionsCaptured = false; } virtual void releaseActionEvents() { _actionsCaptured = false; }
signals:
void actionEvent(int action, float state);
void inputEvent(int action, float state);
private: private:
// Update the exposed variant maps reporting active hardware // Update the exposed variant maps reporting active hardware

View file

@ -21,8 +21,13 @@
#include <NumericalConstants.h> #include <NumericalConstants.h>
#include "StandardController.h" #include "StandardController.h"
#include "Logging.h" #include "Logging.h"
#include "Endpoint.h"
#include "Route.h"
#include "Mapping.h"
namespace controller { namespace controller {
const uint16_t UserInputMapper::ACTIONS_DEVICE = Input::INVALID_DEVICE - 0xFF; const uint16_t UserInputMapper::ACTIONS_DEVICE = Input::INVALID_DEVICE - 0xFF;
const uint16_t UserInputMapper::STANDARD_DEVICE = 0; const uint16_t UserInputMapper::STANDARD_DEVICE = 0;
@ -226,7 +231,15 @@ public:
qFatal("AnyEndpoint is read only"); qFatal("AnyEndpoint is read only");
} }
virtual bool writeable() const override { return false; } // AnyEndpoint is used for reading, so return false if any child returns false (has been written to)
virtual bool writeable() const override {
for (auto& child : _children) {
if (!child->writeable()) {
return false;
}
}
return true;
}
virtual bool readable() const override { virtual bool readable() const override {
for (auto& child : _children) { for (auto& child : _children) {
@ -278,13 +291,11 @@ public:
virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override { } virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override { }
virtual bool writeable() const { return !_written; } virtual bool writeable() const { return false; }
virtual bool readable() const { return !_read; } virtual bool readable() const { return !_read; }
virtual void reset() { _written = _read = false; } virtual void reset() { _read = false; }
private: private:
bool _written { false };
bool _read { false }; bool _read { false };
}; };
@ -516,6 +527,24 @@ void UserInputMapper::update(float deltaTime) {
} }
// TODO: emit signal for pose changes // TODO: emit signal for pose changes
} }
auto standardInputs = getStandardInputs();
if (_lastStandardStates.size() != standardInputs.size()) {
_lastStandardStates.resize(standardInputs.size());
for (auto& lastValue : _lastStandardStates) {
lastValue = 0;
}
}
for (int i = 0; i < standardInputs.size(); ++i) {
const auto& input = standardInputs[i].first;
float value = getValue(input);
float& oldValue = _lastStandardStates[i];
if (value != oldValue) {
oldValue = value;
emit inputEvent(input.id, value);
}
}
} }
Input::NamedVector UserInputMapper::getAvailableInputs(uint16 deviceID) const { Input::NamedVector UserInputMapper::getAvailableInputs(uint16 deviceID) const {
@ -656,51 +685,87 @@ Input UserInputMapper::makeStandardInput(controller::StandardPoseChannel pose) {
static auto lastDebugTime = usecTimestampNow(); static auto lastDebugTime = usecTimestampNow();
static auto debugRoutes = false; static auto debugRoutes = false;
static auto debuggableRoutes = false;
static const auto DEBUG_INTERVAL = USECS_PER_SECOND; static const auto DEBUG_INTERVAL = USECS_PER_SECOND;
void UserInputMapper::runMappings() { void UserInputMapper::runMappings() {
auto now = usecTimestampNow(); auto now = usecTimestampNow();
if (now - lastDebugTime > DEBUG_INTERVAL) { if (debuggableRoutes && now - lastDebugTime > DEBUG_INTERVAL) {
lastDebugTime = now; lastDebugTime = now;
debugRoutes = true; debugRoutes = true;
} }
static auto deviceNames = getDeviceNames();
if (debugRoutes) {
qCDebug(controllers) << "Beginning mapping frame";
}
for (auto endpointEntry : this->_endpointsByInput) { for (auto endpointEntry : this->_endpointsByInput) {
endpointEntry.second->reset(); endpointEntry.second->reset();
} }
// Now process the current values for each level of the stack if (debugRoutes) {
for (const auto& route : _deviceRoutes) { qCDebug(controllers) << "Processing device routes";
if (!route) {
continue;
}
applyRoute(route);
} }
// Now process the current values for each level of the stack
applyRoutes(_deviceRoutes);
for (const auto& route : _standardRoutes) { if (debugRoutes) {
if (!route) { qCDebug(controllers) << "Processing standard routes";
continue; }
} applyRoutes(_standardRoutes);
applyRoute(route);
if (debugRoutes) {
qCDebug(controllers) << "Done with mappings";
} }
debugRoutes = false; debugRoutes = false;
} }
void UserInputMapper::applyRoute(const Route::Pointer& route) { // Encapsulate the logic that routes should not be read before they are written
void UserInputMapper::applyRoutes(const Route::List& routes) {
Route::List deferredRoutes;
for (const auto& route : routes) {
if (!route) {
continue;
}
// Try all the deferred routes
deferredRoutes.remove_if([](Route::Pointer route) {
return UserInputMapper::applyRoute(route);
});
if (!applyRoute(route)) {
deferredRoutes.push_back(route);
}
}
bool force = true;
for (const auto& route : deferredRoutes) {
UserInputMapper::applyRoute(route, force);
}
}
bool UserInputMapper::applyRoute(const Route::Pointer& route, bool force) {
if (debugRoutes && route->debug) { if (debugRoutes && route->debug) {
qCDebug(controllers) << "Applying route " << route->json; qCDebug(controllers) << "Applying route " << route->json;
} }
// If the source hasn't been written yet, defer processing of this route
auto source = route->source;
if (!force && source->writeable()) {
return false;
}
if (route->conditional) { if (route->conditional) {
// FIXME for endpoint conditionals we need to check if they've been written
if (!route->conditional->satisfied()) { if (!route->conditional->satisfied()) {
if (debugRoutes && route->debug) { if (debugRoutes && route->debug) {
qCDebug(controllers) << "Conditional failed"; qCDebug(controllers) << "Conditional failed";
} }
return; return true;
} }
} }
auto source = route->source;
// Most endpoints can only be read once (though a given mapping can route them to // Most endpoints can only be read once (though a given mapping can route them to
// multiple places). Consider... If the default is to wire the A button to JUMP // multiple places). Consider... If the default is to wire the A button to JUMP
@ -711,7 +776,7 @@ void UserInputMapper::applyRoute(const Route::Pointer& route) {
if (debugRoutes && route->debug) { if (debugRoutes && route->debug) {
qCDebug(controllers) << "Source unreadable"; qCDebug(controllers) << "Source unreadable";
} }
return; return true;
} }
auto destination = route->destination; auto destination = route->destination;
@ -721,14 +786,14 @@ void UserInputMapper::applyRoute(const Route::Pointer& route) {
if (debugRoutes && route->debug) { if (debugRoutes && route->debug) {
qCDebug(controllers) << "Bad Destination"; qCDebug(controllers) << "Bad Destination";
} }
return; return true;
} }
if (!destination->writeable()) { if (!destination->writeable()) {
if (debugRoutes && route->debug) { if (debugRoutes && route->debug) {
qCDebug(controllers) << "Destination unwritable"; qCDebug(controllers) << "Destination unwritable";
} }
return; return true;
} }
// Fetch the value, may have been overriden by previous loopback routes // Fetch the value, may have been overriden by previous loopback routes
@ -764,6 +829,7 @@ void UserInputMapper::applyRoute(const Route::Pointer& route) {
destination->apply(value, 0, source); destination->apply(value, 0, source);
} }
return true;
} }
Endpoint::Pointer UserInputMapper::endpointFor(const QJSValue& endpoint) { Endpoint::Pointer UserInputMapper::endpointFor(const QJSValue& endpoint) {
@ -869,12 +935,12 @@ void UserInputMapper::enableMapping(const QString& mappingName, bool enable) {
} }
} }
float UserInputMapper::getValue(const Endpoint::Pointer& endpoint) const { float UserInputMapper::getValue(const Endpoint::Pointer& endpoint) {
Locker locker(_lock);
return endpoint->value(); return endpoint->value();
} }
float UserInputMapper::getValue(const Input& input) const { float UserInputMapper::getValue(const Input& input) const {
Locker locker(_lock);
auto endpoint = endpointFor(input); auto endpoint = endpointFor(input);
if (!endpoint) { if (!endpoint) {
return 0; return 0;
@ -882,7 +948,7 @@ float UserInputMapper::getValue(const Input& input) const {
return endpoint->value(); return endpoint->value();
} }
Pose UserInputMapper::getPose(const Endpoint::Pointer& endpoint) const { Pose UserInputMapper::getPose(const Endpoint::Pointer& endpoint) {
if (!endpoint->isPose()) { if (!endpoint->isPose()) {
return Pose(); return Pose();
} }
@ -890,6 +956,7 @@ Pose UserInputMapper::getPose(const Endpoint::Pointer& endpoint) const {
} }
Pose UserInputMapper::getPose(const Input& input) const { Pose UserInputMapper::getPose(const Input& input) const {
Locker locker(_lock);
auto endpoint = endpointFor(input); auto endpoint = endpointFor(input);
if (!endpoint) { if (!endpoint) {
return Pose(); return Pose();
@ -1156,6 +1223,16 @@ Mapping::Pointer UserInputMapper::parseMapping(const QString& json) {
return parseMapping(doc.object()); return parseMapping(doc.object());
} }
template <typename T>
bool hasDebuggableRoute(const T& routes) {
for (auto route : routes) {
if (route->debug) {
return true;
}
}
return false;
}
void UserInputMapper::enableMapping(const Mapping::Pointer& mapping) { void UserInputMapper::enableMapping(const Mapping::Pointer& mapping) {
Locker locker(_lock); Locker locker(_lock);
@ -1174,6 +1251,10 @@ void UserInputMapper::enableMapping(const Mapping::Pointer& mapping) {
return (value->source->getInput().device == STANDARD_DEVICE); return (value->source->getInput().device == STANDARD_DEVICE);
}); });
_deviceRoutes.insert(_deviceRoutes.begin(), deviceRoutes.begin(), deviceRoutes.end()); _deviceRoutes.insert(_deviceRoutes.begin(), deviceRoutes.begin(), deviceRoutes.end());
if (!debuggableRoutes) {
debuggableRoutes = hasDebuggableRoute(_deviceRoutes) || hasDebuggableRoute(_standardRoutes);
}
} }
void UserInputMapper::disableMapping(const Mapping::Pointer& mapping) { void UserInputMapper::disableMapping(const Mapping::Pointer& mapping) {
@ -1186,6 +1267,10 @@ void UserInputMapper::disableMapping(const Mapping::Pointer& mapping) {
_standardRoutes.remove_if([&](const Route::Pointer& value) { _standardRoutes.remove_if([&](const Route::Pointer& value) {
return routeSet.count(value) != 0; return routeSet.count(value) != 0;
}); });
if (debuggableRoutes) {
debuggableRoutes = hasDebuggableRoute(_deviceRoutes) || hasDebuggableRoute(_standardRoutes);
}
} }
} }

View file

@ -23,13 +23,12 @@
#include <DependencyManager.h> #include <DependencyManager.h>
#include <RegisteredMetaTypes.h> #include <RegisteredMetaTypes.h>
#include "Forward.h"
#include "Pose.h" #include "Pose.h"
#include "Input.h" #include "Input.h"
#include "InputDevice.h" #include "InputDevice.h"
#include "DeviceProxy.h" #include "DeviceProxy.h"
#include "StandardControls.h" #include "StandardControls.h"
#include "Mapping.h"
#include "Endpoint.h"
#include "Actions.h" #include "Actions.h"
namespace controller { namespace controller {
@ -45,15 +44,14 @@ namespace controller {
public: public:
using InputPair = Input::NamedPair; using InputPair = Input::NamedPair;
// FIXME move to unordered set / map // FIXME move to unordered set / map
using EndpointToInputMap = std::map<Endpoint::Pointer, Input>; using EndpointToInputMap = std::map<EndpointPointer, Input>;
using MappingNameMap = std::map<QString, Mapping::Pointer>; using MappingNameMap = std::map<QString, MappingPointer>;
using MappingDeviceMap = std::map<uint16_t, Mapping::Pointer>; using MappingDeviceMap = std::map<uint16_t, MappingPointer>;
using MappingStack = std::list<Mapping::Pointer>; using MappingStack = std::list<MappingPointer>;
using InputToEndpointMap = std::map<Input, Endpoint::Pointer>; using InputToEndpointMap = std::map<Input, EndpointPointer>;
using EndpointSet = std::unordered_set<Endpoint::Pointer>; using EndpointSet = std::unordered_set<EndpointPointer>;
using EndpointOverrideMap = std::map<Endpoint::Pointer, Endpoint::Pointer>; using EndpointPair = std::pair<EndpointPointer, EndpointPointer>;
using EndpointPair = std::pair<Endpoint::Pointer, Endpoint::Pointer>; using EndpointPairMap = std::map<EndpointPair, EndpointPointer>;
using EndpointPairMap = std::map<EndpointPair, Endpoint::Pointer>;
using DevicesMap = std::map<int, DeviceProxy::Pointer>; using DevicesMap = std::map<int, DeviceProxy::Pointer>;
using uint16 = uint16_t; using uint16 = uint16_t;
using uint32 = uint32_t; using uint32 = uint32_t;
@ -107,9 +105,9 @@ namespace controller {
uint16 getStandardDeviceID() const { return STANDARD_DEVICE; } uint16 getStandardDeviceID() const { return STANDARD_DEVICE; }
DeviceProxy::Pointer getStandardDevice() { return _registeredDevices[getStandardDeviceID()]; } DeviceProxy::Pointer getStandardDevice() { return _registeredDevices[getStandardDeviceID()]; }
Mapping::Pointer newMapping(const QString& mappingName); MappingPointer newMapping(const QString& mappingName);
Mapping::Pointer parseMapping(const QString& json); MappingPointer parseMapping(const QString& json);
Mapping::Pointer loadMapping(const QString& jsonFile); MappingPointer loadMapping(const QString& jsonFile);
void enableMapping(const QString& mappingName, bool enable = true); void enableMapping(const QString& mappingName, bool enable = true);
float getValue(const Input& input) const; float getValue(const Input& input) const;
@ -117,6 +115,7 @@ namespace controller {
signals: signals:
void actionEvent(int action, float state); void actionEvent(int action, float state);
void inputEvent(int input, float state);
void hardwareChanged(); void hardwareChanged();
protected: protected:
@ -130,36 +129,38 @@ namespace controller {
std::vector<float> _actionScales = std::vector<float>(toInt(Action::NUM_ACTIONS), 1.0f); std::vector<float> _actionScales = std::vector<float>(toInt(Action::NUM_ACTIONS), 1.0f);
std::vector<float> _lastActionStates = std::vector<float>(toInt(Action::NUM_ACTIONS), 0.0f); std::vector<float> _lastActionStates = std::vector<float>(toInt(Action::NUM_ACTIONS), 0.0f);
std::vector<Pose> _poseStates = std::vector<Pose>(toInt(Action::NUM_ACTIONS)); std::vector<Pose> _poseStates = std::vector<Pose>(toInt(Action::NUM_ACTIONS));
std::vector<float> _lastStandardStates = std::vector<float>();
glm::mat4 _sensorToWorldMat; glm::mat4 _sensorToWorldMat;
int recordDeviceOfType(const QString& deviceName); int recordDeviceOfType(const QString& deviceName);
QHash<const QString&, int> _deviceCounts; QHash<const QString&, int> _deviceCounts;
float getValue(const Endpoint::Pointer& endpoint) const; static float getValue(const EndpointPointer& endpoint);
Pose getPose(const Endpoint::Pointer& endpoint) const; static Pose getPose(const EndpointPointer& endpoint);
friend class RouteBuilderProxy; friend class RouteBuilderProxy;
friend class MappingBuilderProxy; friend class MappingBuilderProxy;
void runMappings(); void runMappings();
void applyRoute(const Route::Pointer& route); static void applyRoutes(const RouteList& route);
void enableMapping(const Mapping::Pointer& mapping); static bool applyRoute(const RoutePointer& route, bool force = false);
void disableMapping(const Mapping::Pointer& mapping); void enableMapping(const MappingPointer& mapping);
Endpoint::Pointer endpointFor(const QJSValue& endpoint); void disableMapping(const MappingPointer& mapping);
Endpoint::Pointer endpointFor(const QScriptValue& endpoint); EndpointPointer endpointFor(const QJSValue& endpoint);
Endpoint::Pointer endpointFor(const Input& endpoint) const; EndpointPointer endpointFor(const QScriptValue& endpoint);
Endpoint::Pointer compositeEndpointFor(Endpoint::Pointer first, Endpoint::Pointer second); EndpointPointer endpointFor(const Input& endpoint) const;
EndpointPointer compositeEndpointFor(EndpointPointer first, EndpointPointer second);
Mapping::Pointer parseMapping(const QJsonValue& json); MappingPointer parseMapping(const QJsonValue& json);
Route::Pointer parseRoute(const QJsonValue& value); RoutePointer parseRoute(const QJsonValue& value);
Endpoint::Pointer parseDestination(const QJsonValue& value); EndpointPointer parseDestination(const QJsonValue& value);
Endpoint::Pointer parseSource(const QJsonValue& value); EndpointPointer parseSource(const QJsonValue& value);
Endpoint::Pointer parseEndpoint(const QJsonValue& value); EndpointPointer parseEndpoint(const QJsonValue& value);
Conditional::Pointer parseConditional(const QJsonValue& value); ConditionalPointer parseConditional(const QJsonValue& value);
static Filter::Pointer parseFilter(const QJsonValue& value); static FilterPointer parseFilter(const QJsonValue& value);
static Filter::List parseFilters(const QJsonValue& value); static FilterList parseFilters(const QJsonValue& value);
InputToEndpointMap _endpointsByInput; InputToEndpointMap _endpointsByInput;
EndpointToInputMap _inputsByEndpoint; EndpointToInputMap _inputsByEndpoint;
@ -168,8 +169,8 @@ namespace controller {
MappingNameMap _mappingsByName; MappingNameMap _mappingsByName;
MappingDeviceMap _mappingsByDevice; MappingDeviceMap _mappingsByDevice;
Route::List _deviceRoutes; RouteList _deviceRoutes;
Route::List _standardRoutes; RouteList _standardRoutes;
using Locker = std::unique_lock<std::recursive_mutex>; using Locker = std::unique_lock<std::recursive_mutex>;

View file

@ -39,6 +39,11 @@ void RouteBuilderProxy::to(const Endpoint::Pointer& destination) {
deleteLater(); deleteLater();
} }
QObject* RouteBuilderProxy::debug(bool enable) {
_route->debug = enable;
return this;
}
QObject* RouteBuilderProxy::filterQml(const QJSValue& expression) { QObject* RouteBuilderProxy::filterQml(const QJSValue& expression) {
if (expression.isCallable()) { if (expression.isCallable()) {
addFilter([=](float value) { addFilter([=](float value) {

View file

@ -35,6 +35,7 @@ class RouteBuilderProxy : public QObject {
Q_INVOKABLE QObject* filterQml(const QJSValue& expression); Q_INVOKABLE QObject* filterQml(const QJSValue& expression);
Q_INVOKABLE void to(const QScriptValue& destination); Q_INVOKABLE void to(const QScriptValue& destination);
Q_INVOKABLE QObject* debug(bool enable = true);
Q_INVOKABLE QObject* filter(const QScriptValue& expression); Q_INVOKABLE QObject* filter(const QScriptValue& expression);
Q_INVOKABLE QObject* clamp(float min, float max); Q_INVOKABLE QObject* clamp(float min, float max);
Q_INVOKABLE QObject* pulse(float interval); Q_INVOKABLE QObject* pulse(float interval);