mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 04:03:59 +02:00
Merge branch 'controllers' of https://github.com/highfidelity/hifi into controllers
This commit is contained in:
commit
eae316100a
44 changed files with 880 additions and 373 deletions
|
@ -148,6 +148,7 @@ function MyController(hand, triggerAction) {
|
|||
this.state = STATE_OFF;
|
||||
this.pointer = null; // entity-id of line object
|
||||
this.triggerValue = 0; // rolling average of trigger value
|
||||
this.rawTriggerValue = 0;
|
||||
|
||||
var _this = this;
|
||||
|
||||
|
@ -244,12 +245,17 @@ function MyController(hand, triggerAction) {
|
|||
this.pointer = null;
|
||||
};
|
||||
|
||||
this.updateSmoothedTrigger = function() {
|
||||
var triggerValue = Controller.getValue(this.triggerAction);
|
||||
this.eitherTrigger = function (value) {
|
||||
_this.rawTriggerValue = value;
|
||||
};
|
||||
|
||||
this.updateSmoothedTrigger = function () {
|
||||
var triggerValue = this.rawTriggerValue;
|
||||
// smooth out trigger value
|
||||
this.triggerValue = (this.triggerValue * TRIGGER_SMOOTH_RATIO) +
|
||||
(triggerValue * (1.0 - TRIGGER_SMOOTH_RATIO));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.triggerSmoothedSqueezed = function() {
|
||||
return this.triggerValue > TRIGGER_ON_VALUE;
|
||||
|
@ -259,8 +265,8 @@ function MyController(hand, triggerAction) {
|
|||
return this.triggerValue < TRIGGER_OFF_VALUE;
|
||||
};
|
||||
|
||||
this.triggerSqueezed = function() {
|
||||
var triggerValue = Controller.getValue(this.triggerAction);
|
||||
this.triggerSqueezed = function() {
|
||||
var triggerValue = this.rawTriggerValue;
|
||||
return triggerValue > TRIGGER_ON_VALUE;
|
||||
};
|
||||
|
||||
|
@ -861,6 +867,14 @@ function MyController(hand, triggerAction) {
|
|||
var rightController = new MyController(RIGHT_HAND, Controller.Standard.RT);
|
||||
var leftController = new MyController(LEFT_HAND, Controller.Standard.LT);
|
||||
|
||||
var MAPPING_NAME = "com.highfidelity.handControllerGrab";
|
||||
|
||||
var mapping = Controller.newMapping(MAPPING_NAME);
|
||||
mapping.from([Controller.Standard.RB, Controller.Standard.RT]).to(rightController.eitherTrigger);
|
||||
mapping.from([Controller.Standard.LB, Controller.Standard.LT]).to(leftController.eitherTrigger);
|
||||
Controller.enableMapping(MAPPING_NAME);
|
||||
|
||||
|
||||
function update() {
|
||||
rightController.update();
|
||||
leftController.update();
|
||||
|
@ -869,6 +883,7 @@ function update() {
|
|||
function cleanup() {
|
||||
rightController.cleanup();
|
||||
leftController.cleanup();
|
||||
Controller.disableMapping(MAPPING_NAME);
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
|
|
|
@ -20,10 +20,11 @@ var BALL_SIZE = 0.08;
|
|||
var PADDLE_SIZE = 0.20;
|
||||
var PADDLE_THICKNESS = 0.06;
|
||||
var PADDLE_COLOR = { red: 184, green: 134, blue: 11 };
|
||||
var BALL_COLOR = { red: 255, green: 0, blue: 0 };
|
||||
var BALL_COLOR = { red: 0, green: 255, blue: 0 };
|
||||
var LINE_COLOR = { red: 255, green: 255, blue: 0 };
|
||||
var PADDLE_BOX_OFFSET = { x: 0.05, y: 0.0, z: 0.0 };
|
||||
|
||||
//probably we need to fix these initial values (offsets and orientation)
|
||||
var HOLD_POSITION_LEFT_OFFSET = { x: -0.15, y: 0.05, z: -0.05 };
|
||||
var HOLD_POSITION_RIGHT_OFFSET = { x: -0.15, y: 0.05, z: 0.05 };
|
||||
var PADDLE_ORIENTATION = Quat.fromPitchYawRollDegrees(0,0,0);
|
||||
|
@ -32,18 +33,7 @@ var SPRING_FORCE = 15.0;
|
|||
var lastSoundTime = 0;
|
||||
var gameOn = false;
|
||||
var leftHanded = true;
|
||||
var controllerID;
|
||||
|
||||
|
||||
function setControllerID() {
|
||||
if (leftHanded) {
|
||||
controllerID = 1;
|
||||
} else {
|
||||
controllerID = 3;
|
||||
}
|
||||
}
|
||||
|
||||
setControllerID();
|
||||
Menu.addMenu("PaddleBall");
|
||||
Menu.addMenuItem({ menuName: "PaddleBall", menuItemName: "Left-Handed", isCheckable: true, isChecked: true });
|
||||
|
||||
|
@ -63,7 +53,7 @@ var ball, paddle, paddleModel, line;
|
|||
function createEntities() {
|
||||
ball = Entities.addEntity(
|
||||
{ type: "Sphere",
|
||||
position: Controller.getSpatialControlPosition(controllerID),
|
||||
position: leftHanded ? MyAvatar.leftHandPose.translation : MyAvatar.rightHandPose.translation,
|
||||
dimensions: { x: BALL_SIZE, y: BALL_SIZE, z: BALL_SIZE },
|
||||
color: BALL_COLOR,
|
||||
gravity: { x: 0, y: GRAVITY, z: 0 },
|
||||
|
@ -73,28 +63,28 @@ function createEntities() {
|
|||
|
||||
paddle = Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: Controller.getSpatialControlPosition(controllerID),
|
||||
position: leftHanded ? MyAvatar.leftHandPose.translation : MyAvatar.rightHandPose.translation,
|
||||
dimensions: { x: PADDLE_SIZE, y: PADDLE_THICKNESS, z: PADDLE_SIZE * 0.80 },
|
||||
color: PADDLE_COLOR,
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
damping: 0.10,
|
||||
visible: false,
|
||||
rotation: Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(controllerID)),
|
||||
collisionsWillMove: false });
|
||||
rotation : leftHanded ? MyAvatar.leftHandPose.rotation : MyAvatar.rightHandPose.rotation,
|
||||
collisionsWillMove: false });
|
||||
|
||||
modelURL = "http://public.highfidelity.io/models/attachments/pong_paddle.fbx";
|
||||
paddleModel = Entities.addEntity(
|
||||
{ type: "Model",
|
||||
position: Vec3.sum(Controller.getSpatialControlPosition(controllerID), PADDLE_BOX_OFFSET),
|
||||
position: Vec3.sum( leftHanded ? MyAvatar.leftHandPose.translation : MyAvatar.rightHandPose.translation, PADDLE_BOX_OFFSET),
|
||||
dimensions: { x: PADDLE_SIZE * 1.5, y: PADDLE_THICKNESS, z: PADDLE_SIZE * 1.25 },
|
||||
color: PADDLE_COLOR,
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
ignoreCollisions: true,
|
||||
modelURL: modelURL,
|
||||
damping: 0.10,
|
||||
rotation: Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(controllerID)),
|
||||
collisionsWillMove: false });
|
||||
rotation : leftHanded ? MyAvatar.leftHandPose.rotation : MyAvatar.rightHandPose.rotation,
|
||||
collisionsWillMove: false });
|
||||
|
||||
line = Overlays.addOverlay("line3d", {
|
||||
start: { x: 0, y: 0, z: 0 },
|
||||
|
@ -118,7 +108,7 @@ function deleteEntities() {
|
|||
}
|
||||
|
||||
function update(deltaTime) {
|
||||
var palmPosition = Controller.getSpatialControlPosition(controllerID);
|
||||
var palmPosition = leftHanded ? MyAvatar.leftHandPose.translation : MyAvatar.rightHandPose.translation;
|
||||
var controllerActive = (Vec3.length(palmPosition) > 0);
|
||||
|
||||
if (!gameOn && controllerActive) {
|
||||
|
@ -133,8 +123,8 @@ function update(deltaTime) {
|
|||
}
|
||||
|
||||
var paddleOrientation = leftHanded ? PADDLE_ORIENTATION : Quat.multiply(PADDLE_ORIENTATION, Quat.fromPitchYawRollDegrees(0, 180, 0));
|
||||
var paddleWorldOrientation = Quat.multiply(Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(controllerID)), paddleOrientation);
|
||||
var holdPosition = Vec3.sum(leftHanded ? MyAvatar.getLeftPalmPosition() : MyAvatar.getRightPalmPosition(),
|
||||
var paddleWorldOrientation = Quat.multiply(leftHanded ? MyAvatar.leftHandPose.rotation : MyAvatar.rightHandPose.rotation, paddleOrientation);
|
||||
var holdPosition = Vec3.sum(leftHanded ? MyAvatar.leftHandPose.translation : MyAvatar.rightHandPose.translation,
|
||||
Vec3.multiplyQbyV(paddleWorldOrientation, leftHanded ? HOLD_POSITION_LEFT_OFFSET : HOLD_POSITION_RIGHT_OFFSET ));
|
||||
|
||||
var props = Entities.getEntityProperties(ball);
|
||||
|
@ -146,10 +136,10 @@ function update(deltaTime) {
|
|||
Entities.editEntity(ball, { velocity: ballVelocity });
|
||||
Overlays.editOverlay(line, { start: props.position, end: holdPosition });
|
||||
Entities.editEntity(paddle, { position: holdPosition,
|
||||
velocity: Controller.getSpatialControlVelocity(controllerID),
|
||||
velocity: leftHanded ? MyAvatar.leftHandPose.velocity : MyAvatar.rightHandPose.velocity,
|
||||
rotation: paddleWorldOrientation });
|
||||
Entities.editEntity(paddleModel, { position: Vec3.sum(holdPosition, Vec3.multiplyQbyV(paddleWorldOrientation, PADDLE_BOX_OFFSET)),
|
||||
velocity: Controller.getSpatialControlVelocity(controllerID),
|
||||
velocity: leftHanded ? MyAvatar.leftHandPose.velocity : MyAvatar.rightHandPose.velocity,
|
||||
rotation: paddleWorldOrientation });
|
||||
|
||||
}
|
||||
|
@ -182,7 +172,6 @@ function menuItemEvent(menuItem) {
|
|||
leftHanded = Menu.isOptionChecked("Left-Handed");
|
||||
}
|
||||
if ((leftHanded != oldHanded) && gameOn) {
|
||||
setControllerID();
|
||||
deleteEntities();
|
||||
createEntities();
|
||||
}
|
||||
|
|
|
@ -59,9 +59,7 @@ function controller(side) {
|
|||
this.triggerHeld = false;
|
||||
this.triggerThreshold = 0.9;
|
||||
this.side = side;
|
||||
this.palm = 2 * side;
|
||||
this.tip = 2 * side + 1;
|
||||
this.trigger = side;
|
||||
this.trigger = side == LEFT ? Controller.Standard.LT : Controller.Standard.RT;
|
||||
this.originalGravity = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
|
@ -150,8 +148,8 @@ function controller(side) {
|
|||
|
||||
|
||||
this.updateControllerState = function() {
|
||||
this.palmPosition = Controller.getSpatialControlPosition(this.palm);
|
||||
this.tipPosition = Controller.getSpatialControlPosition(this.tip);
|
||||
this.palmPosition = this.side == RIGHT ? MyAvatar.rightHandPose.translation : MyAvatar.leftHandPose.translation;
|
||||
this.tipPosition = this.side == RIGHT ? MyAvatar.rightHandTipPose.translation : MyAvatar.leftHandTipPose.translation;
|
||||
this.triggerValue = Controller.getTriggerValue(this.trigger);
|
||||
}
|
||||
|
||||
|
|
|
@ -71,10 +71,8 @@ function controller(side, cycleColorButton) {
|
|||
this.triggerHeld = false;
|
||||
this.triggerThreshold = 0.9;
|
||||
this.side = side;
|
||||
this.palm = 2 * side;
|
||||
this.tip = 2 * side + 1;
|
||||
this.trigger = side;
|
||||
this.cycleColorButton = cycleColorButton;
|
||||
this.trigger = side == LEFT ? Controller.Stantard.LT : Controller.Standard.RT;
|
||||
this.cycleColorButton = side == LEFT ? Controller.Stantard.LeftPrimaryThumb : Controller.Standard.RightPrimaryThumb;
|
||||
|
||||
this.points = [];
|
||||
this.normals = [];
|
||||
|
@ -173,11 +171,10 @@ function controller(side, cycleColorButton) {
|
|||
|
||||
|
||||
this.updateControllerState = function() {
|
||||
this.cycleColorButtonPressed = Controller.isButtonPressed(this.cycleColorButton);
|
||||
this.palmPosition = Controller.getSpatialControlPosition(this.palm);
|
||||
this.tipPosition = Controller.getSpatialControlPosition(this.tip);
|
||||
this.palmNormal = Controller.getSpatialControlNormal(this.palm);
|
||||
this.triggerValue = Controller.getTriggerValue(this.trigger);
|
||||
this.cycleColorButtonPressed = Controller.getValue(this.cycleColorButton);
|
||||
this.palmPosition = this.side == RIGHT ? MyAvatar.rightHandPose.translation : MyAvatar.leftHandPose.translation;
|
||||
this.tipPosition = this.side == RIGHT ? MyAvatar.rightHandTipPose.translation : MyAvatar.leftHandTipPose.translation;
|
||||
this.triggerValue = Controller.getValue(this.trigger);
|
||||
|
||||
|
||||
if (this.prevCycleColorButtonPressed === true && this.cycleColorButtonPressed === false) {
|
||||
|
@ -215,8 +212,8 @@ function vectorIsZero(v) {
|
|||
}
|
||||
|
||||
|
||||
var rightController = new controller(RIGHT, RIGHT_BUTTON_4);
|
||||
var leftController = new controller(LEFT, LEFT_BUTTON_4);
|
||||
var rightController = new controller(RIGHT);
|
||||
var leftController = new controller(LEFT);
|
||||
Script.update.connect(update);
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
|
||||
|
|
|
@ -4,8 +4,10 @@ ControllerTest = function() {
|
|||
var xbox = Controller.Hardware.GamePad;
|
||||
this.mappingEnabled = false;
|
||||
this.mapping = Controller.newMapping();
|
||||
this.mapping.from(standard.LX).when([standard.LB, standard.RB]).to(actions.Yaw);
|
||||
this.mapping.from(standard.RX).to(actions.StepYaw);
|
||||
this.mapping.from(standard.RY).invert().to(actions.Pitch);
|
||||
this.mapping.from(standard.RY).invert().to(actions.Pitch);
|
||||
|
||||
|
||||
var testMakeAxis = false;
|
||||
|
|
|
@ -24,9 +24,22 @@
|
|||
|
||||
#include "Logging.h"
|
||||
|
||||
#include "Endpoint.h"
|
||||
#include "Route.h"
|
||||
#include "Mapping.h"
|
||||
#include "impl/conditionals/AndConditional.h"
|
||||
#include "impl/conditionals/EndpointConditional.h"
|
||||
#include "impl/conditionals/ScriptConditional.h"
|
||||
|
||||
#include "impl/endpoints/ActionEndpoint.h"
|
||||
#include "impl/endpoints/AnyEndpoint.h"
|
||||
#include "impl/endpoints/ArrayEndpoint.h"
|
||||
#include "impl/endpoints/CompositeEndpoint.h"
|
||||
#include "impl/endpoints/InputEndpoint.h"
|
||||
#include "impl/endpoints/JSEndpoint.h"
|
||||
#include "impl/endpoints/ScriptEndpoint.h"
|
||||
#include "impl/endpoints/StandardEndpoint.h"
|
||||
|
||||
#include "impl/Route.h"
|
||||
#include "impl/Mapping.h"
|
||||
|
||||
|
||||
namespace controller {
|
||||
const uint16_t UserInputMapper::ACTIONS_DEVICE = Input::INVALID_DEVICE - 0xFF;
|
||||
|
@ -42,300 +55,6 @@ controller::UserInputMapper::UserInputMapper() {
|
|||
|
||||
namespace controller {
|
||||
|
||||
class ScriptEndpoint : public Endpoint {
|
||||
Q_OBJECT;
|
||||
public:
|
||||
ScriptEndpoint(const QScriptValue& callable)
|
||||
: Endpoint(Input::INVALID_INPUT), _callable(callable) {
|
||||
}
|
||||
|
||||
virtual float value();
|
||||
virtual void apply(float newValue, float oldValue, const Pointer& source);
|
||||
|
||||
protected:
|
||||
Q_INVOKABLE void updateValue();
|
||||
Q_INVOKABLE virtual void internalApply(float newValue, float oldValue, int sourceID);
|
||||
private:
|
||||
QScriptValue _callable;
|
||||
float _lastValue = 0.0f;
|
||||
};
|
||||
|
||||
class StandardEndpoint : public VirtualEndpoint {
|
||||
public:
|
||||
StandardEndpoint(const Input& input) : VirtualEndpoint(input) {}
|
||||
virtual bool writeable() const override { return !_written; }
|
||||
virtual bool readable() const override { return !_read; }
|
||||
virtual void reset() override {
|
||||
apply(0.0f, 0.0f, Endpoint::Pointer());
|
||||
apply(Pose(), Pose(), Endpoint::Pointer());
|
||||
_written = _read = false;
|
||||
}
|
||||
|
||||
virtual float value() override {
|
||||
_read = true;
|
||||
return VirtualEndpoint::value();
|
||||
}
|
||||
|
||||
virtual void apply(float newValue, float oldValue, const Pointer& source) override {
|
||||
// For standard endpoints, the first NON-ZERO write counts.
|
||||
if (newValue != 0.0) {
|
||||
_written = true;
|
||||
}
|
||||
VirtualEndpoint::apply(newValue, oldValue, source);
|
||||
}
|
||||
|
||||
virtual Pose pose() override {
|
||||
_read = true;
|
||||
return VirtualEndpoint::pose();
|
||||
}
|
||||
|
||||
virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override {
|
||||
if (newValue != Pose()) {
|
||||
_written = true;
|
||||
}
|
||||
VirtualEndpoint::apply(newValue, oldValue, source);
|
||||
}
|
||||
|
||||
private:
|
||||
bool _written { false };
|
||||
bool _read { false };
|
||||
};
|
||||
|
||||
|
||||
class JSEndpoint : public Endpoint {
|
||||
public:
|
||||
JSEndpoint(const QJSValue& callable)
|
||||
: Endpoint(Input::INVALID_INPUT), _callable(callable) {
|
||||
}
|
||||
|
||||
virtual float value() {
|
||||
float result = (float)_callable.call().toNumber();;
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual void apply(float newValue, float oldValue, const Pointer& source) {
|
||||
_callable.call(QJSValueList({ QJSValue(newValue) }));
|
||||
}
|
||||
|
||||
private:
|
||||
QJSValue _callable;
|
||||
};
|
||||
|
||||
float ScriptEndpoint::value() {
|
||||
updateValue();
|
||||
return _lastValue;
|
||||
}
|
||||
|
||||
void ScriptEndpoint::updateValue() {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "updateValue", Qt::QueuedConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
_lastValue = (float)_callable.call().toNumber();
|
||||
}
|
||||
|
||||
void ScriptEndpoint::apply(float newValue, float oldValue, const Pointer& source) {
|
||||
internalApply(newValue, oldValue, source->getInput().getID());
|
||||
}
|
||||
|
||||
void ScriptEndpoint::internalApply(float newValue, float oldValue, int sourceID) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "internalApply", Qt::QueuedConnection,
|
||||
Q_ARG(float, newValue),
|
||||
Q_ARG(float, oldValue),
|
||||
Q_ARG(int, sourceID));
|
||||
return;
|
||||
}
|
||||
_callable.call(QScriptValue(),
|
||||
QScriptValueList({ QScriptValue(newValue), QScriptValue(oldValue), QScriptValue(sourceID) }));
|
||||
}
|
||||
|
||||
static const Input INVALID_STANDARD_INPUT = Input(UserInputMapper::STANDARD_DEVICE, Input::INVALID_CHANNEL, ChannelType::INVALID);
|
||||
|
||||
class CompositeEndpoint : public Endpoint, Endpoint::Pair {
|
||||
public:
|
||||
CompositeEndpoint(Endpoint::Pointer first, Endpoint::Pointer second)
|
||||
: Endpoint(Input::INVALID_INPUT), Pair(first, second) {
|
||||
if (first->getInput().device == UserInputMapper::STANDARD_DEVICE &&
|
||||
second->getInput().device == UserInputMapper::STANDARD_DEVICE) {
|
||||
this->_input = INVALID_STANDARD_INPUT;
|
||||
}
|
||||
}
|
||||
|
||||
virtual float value() {
|
||||
float result = first->value() * -1.0f + second->value();
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual void apply(float newValue, float oldValue, const Pointer& source) {
|
||||
// Composites are read only
|
||||
}
|
||||
};
|
||||
|
||||
class ArrayEndpoint : public Endpoint {
|
||||
friend class UserInputMapper;
|
||||
public:
|
||||
using Pointer = std::shared_ptr<ArrayEndpoint>;
|
||||
ArrayEndpoint() : Endpoint(Input::INVALID_INPUT) { }
|
||||
|
||||
virtual float value() override {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
virtual void apply(float newValue, float oldValue, const Endpoint::Pointer& source) override {
|
||||
for (auto& child : _children) {
|
||||
if (child->writeable()) {
|
||||
child->apply(newValue, oldValue, source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool readable() const override { return false; }
|
||||
|
||||
private:
|
||||
Endpoint::List _children;
|
||||
};
|
||||
|
||||
class AnyEndpoint : public Endpoint {
|
||||
friend class UserInputMapper;
|
||||
public:
|
||||
using Pointer = std::shared_ptr<AnyEndpoint>;
|
||||
AnyEndpoint(Endpoint::List children) : Endpoint(Input::INVALID_INPUT), _children(children) {
|
||||
bool standard = true;
|
||||
// Ensure if we're building a composite of standard devices the composite itself
|
||||
// is treated as a standard device for rule processing order
|
||||
for (auto endpoint : children) {
|
||||
if (endpoint->getInput().device != UserInputMapper::STANDARD_DEVICE) {
|
||||
standard = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (standard) {
|
||||
this->_input = INVALID_STANDARD_INPUT;
|
||||
}
|
||||
}
|
||||
|
||||
virtual float value() override {
|
||||
float result = 0;
|
||||
for (auto& child : _children) {
|
||||
float childResult = child->value();
|
||||
if (childResult != 0.0f) {
|
||||
result = childResult;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual void apply(float newValue, float oldValue, const Endpoint::Pointer& source) override {
|
||||
qFatal("AnyEndpoint is read only");
|
||||
}
|
||||
|
||||
// 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 {
|
||||
for (auto& child : _children) {
|
||||
if (!child->readable()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
Endpoint::List _children;
|
||||
};
|
||||
|
||||
class InputEndpoint : public Endpoint {
|
||||
public:
|
||||
InputEndpoint(const Input& id = Input::INVALID_INPUT)
|
||||
: Endpoint(id) {
|
||||
}
|
||||
|
||||
virtual float value() override {
|
||||
_read = true;
|
||||
if (isPose()) {
|
||||
return pose().valid ? 1.0f : 0.0f;
|
||||
}
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
auto deviceProxy = userInputMapper->getDeviceProxy(_input);
|
||||
if (!deviceProxy) {
|
||||
return 0.0f;
|
||||
}
|
||||
return deviceProxy->getValue(_input, 0);
|
||||
}
|
||||
|
||||
// FIXME need support for writing back to vibration / force feedback effects
|
||||
virtual void apply(float newValue, float oldValue, const Pointer& source) override {}
|
||||
|
||||
virtual Pose pose() override {
|
||||
_read = true;
|
||||
if (!isPose()) {
|
||||
return Pose();
|
||||
}
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
auto deviceProxy = userInputMapper->getDeviceProxy(_input);
|
||||
if (!deviceProxy) {
|
||||
return Pose();
|
||||
}
|
||||
return deviceProxy->getPose(_input, 0);
|
||||
}
|
||||
|
||||
virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override { }
|
||||
|
||||
virtual bool writeable() const { return false; }
|
||||
virtual bool readable() const { return !_read; }
|
||||
virtual void reset() { _read = false; }
|
||||
|
||||
private:
|
||||
bool _read { false };
|
||||
};
|
||||
|
||||
class ActionEndpoint : public Endpoint {
|
||||
public:
|
||||
ActionEndpoint(const Input& id = Input::INVALID_INPUT)
|
||||
: Endpoint(id) {
|
||||
}
|
||||
|
||||
virtual float value() override { return _currentValue; }
|
||||
virtual void apply(float newValue, float oldValue, const Pointer& source) override {
|
||||
_currentValue += newValue;
|
||||
if (_input != Input::INVALID_INPUT) {
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
userInputMapper->deltaActionState(Action(_input.getChannel()), newValue);
|
||||
}
|
||||
}
|
||||
|
||||
virtual Pose pose() override { return _currentPose; }
|
||||
virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override {
|
||||
_currentPose = newValue;
|
||||
if (!_currentPose.isValid()) {
|
||||
return;
|
||||
}
|
||||
if (_input != Input::INVALID_INPUT) {
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
userInputMapper->setActionState(Action(_input.getChannel()), _currentPose);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void reset() override {
|
||||
_currentValue = 0.0f;
|
||||
_currentPose = Pose();
|
||||
}
|
||||
|
||||
private:
|
||||
float _currentValue{ 0.0f };
|
||||
Pose _currentPose{};
|
||||
};
|
||||
|
||||
UserInputMapper::~UserInputMapper() {
|
||||
}
|
||||
|
||||
|
@ -856,6 +575,21 @@ Endpoint::Pointer UserInputMapper::endpointFor(const QScriptValue& endpoint) {
|
|||
return result;
|
||||
}
|
||||
|
||||
if (endpoint.isArray()) {
|
||||
int length = endpoint.property("length").toInteger();
|
||||
Endpoint::List children;
|
||||
for (int i = 0; i < length; i++) {
|
||||
QScriptValue arrayItem = endpoint.property(i);
|
||||
Endpoint::Pointer destination = endpointFor(arrayItem);
|
||||
if (!destination) {
|
||||
return Endpoint::Pointer();
|
||||
}
|
||||
children.push_back(destination);
|
||||
}
|
||||
return std::make_shared<AnyEndpoint>(children);
|
||||
}
|
||||
|
||||
|
||||
qWarning() << "Unsupported input type " << endpoint.toString();
|
||||
return Endpoint::Pointer();
|
||||
}
|
||||
|
@ -1004,32 +738,46 @@ Endpoint::Pointer UserInputMapper::parseEndpoint(const QJsonValue& value) {
|
|||
return result;
|
||||
}
|
||||
|
||||
class AndConditional : public Conditional {
|
||||
public:
|
||||
using Pointer = std::shared_ptr<AndConditional>;
|
||||
|
||||
AndConditional(Conditional::List children) : _children(children) { }
|
||||
Conditional::Pointer UserInputMapper::conditionalFor(const QJSValue& condition) {
|
||||
return Conditional::Pointer();
|
||||
}
|
||||
|
||||
virtual bool satisfied() override {
|
||||
for (auto& conditional : _children) {
|
||||
if (!conditional->satisfied()) {
|
||||
return false;
|
||||
Conditional::Pointer UserInputMapper::conditionalFor(const QScriptValue& condition) {
|
||||
if (condition.isArray()) {
|
||||
int length = condition.property("length").toInteger();
|
||||
Conditional::List children;
|
||||
for (int i = 0; i < length; i++) {
|
||||
Conditional::Pointer destination = conditionalFor(condition.property(i));
|
||||
if (!destination) {
|
||||
return Conditional::Pointer();
|
||||
}
|
||||
children.push_back(destination);
|
||||
}
|
||||
return true;
|
||||
return std::make_shared<AndConditional>(children);
|
||||
}
|
||||
|
||||
private:
|
||||
Conditional::List _children;
|
||||
};
|
||||
if (condition.isNumber()) {
|
||||
return conditionalFor(Input(condition.toInt32()));
|
||||
}
|
||||
|
||||
class EndpointConditional : public Conditional {
|
||||
public:
|
||||
EndpointConditional(Endpoint::Pointer endpoint) : _endpoint(endpoint) {}
|
||||
virtual bool satisfied() override { return _endpoint && _endpoint->value() != 0.0; }
|
||||
private:
|
||||
Endpoint::Pointer _endpoint;
|
||||
};
|
||||
if (condition.isFunction()) {
|
||||
return std::make_shared<ScriptConditional>(condition);
|
||||
}
|
||||
|
||||
qWarning() << "Unsupported conditional type " << condition.toString();
|
||||
return Conditional::Pointer();
|
||||
}
|
||||
|
||||
Conditional::Pointer UserInputMapper::conditionalFor(const Input& inputId) const {
|
||||
Locker locker(_lock);
|
||||
auto iterator = _endpointsByInput.find(inputId);
|
||||
if (_endpointsByInput.end() == iterator) {
|
||||
qWarning() << "Unknown input: " << QString::number(inputId.getID(), 16);
|
||||
return Conditional::Pointer();
|
||||
}
|
||||
return std::make_shared<EndpointConditional>(iterator->second);
|
||||
}
|
||||
|
||||
Conditional::Pointer UserInputMapper::parseConditional(const QJsonValue& value) {
|
||||
if (value.isArray()) {
|
||||
|
@ -1057,7 +805,6 @@ Conditional::Pointer UserInputMapper::parseConditional(const QJsonValue& value)
|
|||
return Conditional::parse(value);
|
||||
}
|
||||
|
||||
|
||||
Filter::Pointer UserInputMapper::parseFilter(const QJsonValue& value) {
|
||||
Filter::Pointer result;
|
||||
if (value.isString()) {
|
||||
|
@ -1073,7 +820,6 @@ Filter::Pointer UserInputMapper::parseFilter(const QJsonValue& value) {
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
Filter::List UserInputMapper::parseFilters(const QJsonValue& value) {
|
||||
if (value.isNull()) {
|
||||
return Filter::List();
|
||||
|
@ -1275,4 +1021,3 @@ void UserInputMapper::disableMapping(const Mapping::Pointer& mapping) {
|
|||
|
||||
}
|
||||
|
||||
#include "UserInputMapper.moc"
|
||||
|
|
|
@ -143,6 +143,7 @@ namespace controller {
|
|||
friend class MappingBuilderProxy;
|
||||
|
||||
void runMappings();
|
||||
|
||||
static void applyRoutes(const RouteList& route);
|
||||
static bool applyRoute(const RoutePointer& route, bool force = false);
|
||||
void enableMapping(const MappingPointer& mapping);
|
||||
|
@ -151,6 +152,9 @@ namespace controller {
|
|||
EndpointPointer endpointFor(const QScriptValue& endpoint);
|
||||
EndpointPointer endpointFor(const Input& endpoint) const;
|
||||
EndpointPointer compositeEndpointFor(EndpointPointer first, EndpointPointer second);
|
||||
ConditionalPointer conditionalFor(const QJSValue& endpoint);
|
||||
ConditionalPointer conditionalFor(const QScriptValue& endpoint);
|
||||
ConditionalPointer conditionalFor(const Input& endpoint) const;
|
||||
|
||||
MappingPointer parseMapping(const QJsonValue& json);
|
||||
RoutePointer parseRoute(const QJsonValue& value);
|
||||
|
|
|
@ -28,6 +28,7 @@ namespace controller {
|
|||
using Pointer = std::shared_ptr<Conditional>;
|
||||
using List = std::list<Pointer>;
|
||||
using Factory = hifi::SimpleFactory<Conditional, QString>;
|
||||
using Lambda = std::function<bool()>;
|
||||
|
||||
virtual bool satisfied() = 0;
|
||||
virtual bool parseParameters(const QJsonValue& parameters) { return true; }
|
|
@ -16,8 +16,8 @@
|
|||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include "Input.h"
|
||||
#include "Pose.h"
|
||||
#include "../Input.h"
|
||||
#include "../Pose.h"
|
||||
|
||||
class QScriptValue;
|
||||
|
|
@ -12,8 +12,8 @@
|
|||
#include <QtCore/QObject>
|
||||
#include <QtCore/QString>
|
||||
|
||||
#include "../Mapping.h"
|
||||
#include "../Endpoint.h"
|
||||
#include "Mapping.h"
|
||||
#include "Endpoint.h"
|
||||
|
||||
class QJSValue;
|
||||
class QScriptValue;
|
||||
|
|
|
@ -33,7 +33,6 @@ void RouteBuilderProxy::to(const QScriptValue& destination) {
|
|||
}
|
||||
|
||||
void RouteBuilderProxy::to(const Endpoint::Pointer& destination) {
|
||||
auto sourceEndpoint = _route->source;
|
||||
_route->destination = destination;
|
||||
_mapping->routes.push_back(_route);
|
||||
deleteLater();
|
||||
|
@ -56,6 +55,17 @@ QObject* RouteBuilderProxy::filterQml(const QJSValue& expression) {
|
|||
return this;
|
||||
}
|
||||
|
||||
QObject* RouteBuilderProxy::when(const QScriptValue& expression) {
|
||||
_route->conditional = _parent.conditionalFor(expression);
|
||||
return this;
|
||||
}
|
||||
|
||||
QObject* RouteBuilderProxy::whenQml(const QJSValue& expression) {
|
||||
_route->conditional = _parent.conditionalFor(expression);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
QObject* RouteBuilderProxy::filter(const QScriptValue& expression) {
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -11,10 +11,12 @@
|
|||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include "../Filter.h"
|
||||
#include "../Route.h"
|
||||
#include "../Mapping.h"
|
||||
#include "Filter.h"
|
||||
#include "Route.h"
|
||||
#include "Mapping.h"
|
||||
|
||||
#include "../UserInputMapper.h"
|
||||
|
||||
class QJSValue;
|
||||
class QScriptValue;
|
||||
class QJsonValue;
|
||||
|
@ -33,9 +35,11 @@ class RouteBuilderProxy : public QObject {
|
|||
|
||||
Q_INVOKABLE void toQml(const QJSValue& destination);
|
||||
Q_INVOKABLE QObject* filterQml(const QJSValue& expression);
|
||||
Q_INVOKABLE QObject* whenQml(const QJSValue& expression);
|
||||
|
||||
Q_INVOKABLE void to(const QScriptValue& destination);
|
||||
Q_INVOKABLE QObject* debug(bool enable = true);
|
||||
Q_INVOKABLE QObject* when(const QScriptValue& expression);
|
||||
Q_INVOKABLE QObject* filter(const QScriptValue& expression);
|
||||
Q_INVOKABLE QObject* clamp(float min, float max);
|
||||
Q_INVOKABLE QObject* pulse(float interval);
|
||||
|
@ -47,6 +51,7 @@ class RouteBuilderProxy : public QObject {
|
|||
|
||||
private:
|
||||
void to(const Endpoint::Pointer& destination);
|
||||
void conditional(const Conditional::Pointer& conditional);
|
||||
void addFilter(Filter::Lambda lambda);
|
||||
void addFilter(Filter::Pointer filter);
|
||||
UserInputMapper& _parent;
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis 2015/10/23
|
||||
// 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
|
||||
//
|
||||
|
||||
#include "AndConditional.h"
|
||||
|
||||
using namespace controller;
|
||||
|
||||
bool AndConditional::satisfied() {
|
||||
for (auto& conditional : _children) {
|
||||
if (!conditional->satisfied()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// 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_AndConditional_h
|
||||
#define hifi_Controllers_AndConditional_h
|
||||
|
||||
#include "../Conditional.h"
|
||||
|
||||
namespace controller {
|
||||
|
||||
class AndConditional : public Conditional {
|
||||
public:
|
||||
using Pointer = std::shared_ptr<AndConditional>;
|
||||
|
||||
AndConditional(Conditional::List children) : _children(children) { }
|
||||
|
||||
virtual bool satisfied() override;
|
||||
|
||||
private:
|
||||
Conditional::List _children;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,9 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis 2015/10/23
|
||||
// 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
|
||||
//
|
||||
|
||||
#include "EndpointConditional.h"
|
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// 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_EndpointConditional_h
|
||||
#define hifi_Controllers_EndpointConditional_h
|
||||
|
||||
#include "../Conditional.h"
|
||||
#include "../Endpoint.h"
|
||||
|
||||
namespace controller {
|
||||
|
||||
class EndpointConditional : public Conditional {
|
||||
public:
|
||||
EndpointConditional(Endpoint::Pointer endpoint) : _endpoint(endpoint) {}
|
||||
virtual bool satisfied() override { return _endpoint && _endpoint->value() != 0.0; }
|
||||
private:
|
||||
Endpoint::Pointer _endpoint;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,9 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis 2015/10/23
|
||||
// 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
|
||||
//
|
||||
|
||||
#include "NotConditional.h"
|
|
@ -0,0 +1,16 @@
|
|||
//
|
||||
// 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_NotConditional_h
|
||||
#define hifi_Controllers_NotConditional_h
|
||||
|
||||
#include "../Conditional.h"
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis 2015/10/23
|
||||
// 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
|
||||
//
|
||||
|
||||
#include "ScriptConditional.h"
|
||||
|
||||
#include <QtCore/QThread>
|
||||
|
||||
using namespace controller;
|
||||
|
||||
bool ScriptConditional::satisfied() {
|
||||
updateValue();
|
||||
return _lastValue;
|
||||
}
|
||||
|
||||
void ScriptConditional::updateValue() {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "updateValue", Qt::QueuedConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
_lastValue = _callable.call().toBool();
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// 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_ScriptConditional_h
|
||||
#define hifi_Controllers_ScriptConditional_h
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include <QtScript/QScriptValue>
|
||||
|
||||
#include "../Conditional.h"
|
||||
|
||||
namespace controller {
|
||||
|
||||
class ScriptConditional : public QObject, public Conditional {
|
||||
Q_OBJECT;
|
||||
public:
|
||||
ScriptConditional(const QScriptValue& callable) : _callable(callable) { }
|
||||
virtual bool satisfied() override;
|
||||
protected:
|
||||
Q_INVOKABLE void updateValue();
|
||||
private:
|
||||
QScriptValue _callable;
|
||||
bool _lastValue { false };
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis 2015/10/23
|
||||
// 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
|
||||
//
|
||||
|
||||
#include "ActionEndpoint.h"
|
||||
|
||||
#include <DependencyManager.h>
|
||||
|
||||
#include "../../UserInputMapper.h"
|
||||
|
||||
using namespace controller;
|
||||
|
||||
void ActionEndpoint::apply(float newValue, float oldValue, const Pointer& source) {
|
||||
_currentValue += newValue;
|
||||
if (_input != Input::INVALID_INPUT) {
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
userInputMapper->deltaActionState(Action(_input.getChannel()), newValue);
|
||||
}
|
||||
}
|
||||
|
||||
void ActionEndpoint::apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) {
|
||||
_currentPose = newValue;
|
||||
if (!_currentPose.isValid()) {
|
||||
return;
|
||||
}
|
||||
if (_input != Input::INVALID_INPUT) {
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
userInputMapper->setActionState(Action(_input.getChannel()), _currentPose);
|
||||
}
|
||||
}
|
||||
|
||||
void ActionEndpoint::reset() {
|
||||
_currentValue = 0.0f;
|
||||
_currentPose = Pose();
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis 2015/10/23
|
||||
// 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_ActionEndpoint_h
|
||||
#define hifi_Controllers_ActionEndpoint_h
|
||||
|
||||
#include "../Endpoint.h"
|
||||
|
||||
#include "../../Actions.h"
|
||||
#include <DependencyManager.h>
|
||||
|
||||
#include "../../UserInputMapper.h"
|
||||
|
||||
namespace controller {
|
||||
|
||||
class ActionEndpoint : public Endpoint {
|
||||
public:
|
||||
ActionEndpoint(const Input& id = Input::INVALID_INPUT) : Endpoint(id) { }
|
||||
|
||||
virtual float value() override { return _currentValue; }
|
||||
virtual void apply(float newValue, float oldValue, const Pointer& source) override;
|
||||
|
||||
virtual Pose pose() override { return _currentPose; }
|
||||
virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override;
|
||||
|
||||
virtual void reset() override;
|
||||
|
||||
private:
|
||||
float _currentValue{ 0.0f };
|
||||
Pose _currentPose{};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,63 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis 2015/10/23
|
||||
// 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
|
||||
//
|
||||
|
||||
#include "AnyEndpoint.h"
|
||||
|
||||
#include "../../UserInputMapper.h"
|
||||
|
||||
using namespace controller;
|
||||
|
||||
AnyEndpoint::AnyEndpoint(Endpoint::List children) : Endpoint(Input::INVALID_INPUT), _children(children) {
|
||||
bool standard = true;
|
||||
// Ensure if we're building a composite of standard devices the composite itself
|
||||
// is treated as a standard device for rule processing order
|
||||
for (auto endpoint : children) {
|
||||
if (endpoint->getInput().device != UserInputMapper::STANDARD_DEVICE) {
|
||||
standard = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (standard) {
|
||||
this->_input.device = UserInputMapper::STANDARD_DEVICE;
|
||||
}
|
||||
}
|
||||
|
||||
float AnyEndpoint::value() {
|
||||
float result = 0;
|
||||
for (auto& child : _children) {
|
||||
float childResult = child->value();
|
||||
if (childResult != 0.0f) {
|
||||
result = childResult;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void AnyEndpoint::apply(float newValue, float oldValue, const Endpoint::Pointer& source) {
|
||||
qFatal("AnyEndpoint is read only");
|
||||
}
|
||||
|
||||
// AnyEndpoint is used for reading, so return false if any child returns false (has been written to)
|
||||
bool AnyEndpoint::writeable() const {
|
||||
for (auto& child : _children) {
|
||||
if (!child->writeable()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AnyEndpoint::readable() const {
|
||||
for (auto& child : _children) {
|
||||
if (!child->readable()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis 2015/10/23
|
||||
// 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_AnyEndpoint_h
|
||||
#define hifi_Controllers_AnyEndpoint_h
|
||||
|
||||
#include "../Endpoint.h"
|
||||
|
||||
namespace controller {
|
||||
|
||||
class AnyEndpoint : public Endpoint {
|
||||
friend class UserInputMapper;
|
||||
public:
|
||||
AnyEndpoint(Endpoint::List children);
|
||||
virtual float value() override;
|
||||
virtual void apply(float newValue, float oldValue, const Endpoint::Pointer& source) override;
|
||||
virtual bool writeable() const override;
|
||||
virtual bool readable() const override;
|
||||
|
||||
private:
|
||||
Endpoint::List _children;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,9 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis 2015/10/23
|
||||
// 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
|
||||
//
|
||||
|
||||
#include "ArrayEndpoint.h"
|
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis 2015/10/23
|
||||
// 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_ArrayEndpoint_h
|
||||
#define hifi_Controllers_ArrayEndpoint_h
|
||||
|
||||
#include "../Endpoint.h"
|
||||
|
||||
namespace controller {
|
||||
|
||||
class ArrayEndpoint : public Endpoint {
|
||||
friend class UserInputMapper;
|
||||
public:
|
||||
using Pointer = std::shared_ptr<ArrayEndpoint>;
|
||||
ArrayEndpoint() : Endpoint(Input::INVALID_INPUT) { }
|
||||
|
||||
virtual float value() override {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
virtual void apply(float newValue, float oldValue, const Endpoint::Pointer& source) override {
|
||||
for (auto& child : _children) {
|
||||
if (child->writeable()) {
|
||||
child->apply(newValue, oldValue, source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool readable() const override { return false; }
|
||||
|
||||
private:
|
||||
Endpoint::List _children;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis 2015/10/23
|
||||
// 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
|
||||
//
|
||||
|
||||
#include "CompositeEndpoint.h"
|
||||
|
||||
#include "../../UserInputMapper.h"
|
||||
|
||||
namespace controller {
|
||||
|
||||
CompositeEndpoint::CompositeEndpoint(Endpoint::Pointer first, Endpoint::Pointer second)
|
||||
: Endpoint(Input::INVALID_INPUT), Pair(first, second) {
|
||||
if (first->getInput().device == UserInputMapper::STANDARD_DEVICE &&
|
||||
second->getInput().device == UserInputMapper::STANDARD_DEVICE) {
|
||||
this->_input.device = UserInputMapper::STANDARD_DEVICE;
|
||||
}
|
||||
}
|
||||
|
||||
float CompositeEndpoint::value() {
|
||||
float result = first->value() * -1.0f + second->value();
|
||||
return result;
|
||||
}
|
||||
|
||||
void CompositeEndpoint::apply(float newValue, float oldValue, const Pointer& source) {
|
||||
// Composites are read only
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis 2015/10/23
|
||||
// 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_CompositeEndpoint_h
|
||||
#define hifi_Controllers_CompositeEndpoint_h
|
||||
|
||||
#include "../Endpoint.h"
|
||||
|
||||
namespace controller {
|
||||
class CompositeEndpoint : public Endpoint, Endpoint::Pair {
|
||||
public:
|
||||
CompositeEndpoint(Endpoint::Pointer first, Endpoint::Pointer second);
|
||||
|
||||
virtual float value() override;
|
||||
virtual void apply(float newValue, float oldValue, const Pointer& source) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis 2015/10/23
|
||||
// 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
|
||||
//
|
||||
|
||||
#include "InputEndpoint.h"
|
||||
|
||||
#include <DependencyManager.h>
|
||||
|
||||
#include "../../UserInputMapper.h"
|
||||
|
||||
using namespace controller;
|
||||
float InputEndpoint::value(){
|
||||
_read = true;
|
||||
if (isPose()) {
|
||||
return pose().valid ? 1.0f : 0.0f;
|
||||
}
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
auto deviceProxy = userInputMapper->getDeviceProxy(_input);
|
||||
if (!deviceProxy) {
|
||||
return 0.0f;
|
||||
}
|
||||
return deviceProxy->getValue(_input, 0);
|
||||
}
|
||||
|
||||
Pose InputEndpoint::pose() {
|
||||
_read = true;
|
||||
if (!isPose()) {
|
||||
return Pose();
|
||||
}
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
auto deviceProxy = userInputMapper->getDeviceProxy(_input);
|
||||
if (!deviceProxy) {
|
||||
return Pose();
|
||||
}
|
||||
return deviceProxy->getPose(_input, 0);
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis 2015/10/23
|
||||
// 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_InputEndpoint_h
|
||||
#define hifi_Controllers_InputEndpoint_h
|
||||
|
||||
#include "../Endpoint.h"
|
||||
|
||||
namespace controller {
|
||||
|
||||
class InputEndpoint : public Endpoint {
|
||||
public:
|
||||
InputEndpoint(const Input& id = Input::INVALID_INPUT)
|
||||
: Endpoint(id) {
|
||||
}
|
||||
|
||||
virtual float value() override;
|
||||
// FIXME need support for writing back to vibration / force feedback effects
|
||||
virtual void apply(float newValue, float oldValue, const Pointer& source) override {}
|
||||
virtual Pose pose() override;
|
||||
virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override { }
|
||||
|
||||
virtual bool writeable() const { return false; }
|
||||
virtual bool readable() const { return !_read; }
|
||||
virtual void reset() { _read = false; }
|
||||
|
||||
private:
|
||||
bool _read { false };
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,9 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis 2015/10/23
|
||||
// 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
|
||||
//
|
||||
|
||||
#include "JSEndpoint.h"
|
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis 2015/10/23
|
||||
// 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_JSEndpoint_h
|
||||
#define hifi_Controllers_JSEndpoint_h
|
||||
|
||||
#include "../Endpoint.h"
|
||||
|
||||
#include <QtQml/QJSValue>
|
||||
#include <QtQml/QJSValueList>
|
||||
|
||||
namespace controller {
|
||||
|
||||
class JSEndpoint : public Endpoint {
|
||||
public:
|
||||
JSEndpoint(const QJSValue& callable)
|
||||
: Endpoint(Input::INVALID_INPUT), _callable(callable) {
|
||||
}
|
||||
|
||||
virtual float value() {
|
||||
float result = (float)_callable.call().toNumber();
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual void apply(float newValue, float oldValue, const Pointer& source) {
|
||||
_callable.call(QJSValueList({ QJSValue(newValue) }));
|
||||
}
|
||||
|
||||
private:
|
||||
QJSValue _callable;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis 2015/10/23
|
||||
// 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
|
||||
//
|
||||
|
||||
#include "ScriptEndpoint.h"
|
||||
|
||||
#include <QtCore/QThread>
|
||||
|
||||
using namespace controller;
|
||||
|
||||
float ScriptEndpoint::value() {
|
||||
updateValue();
|
||||
return _lastValue;
|
||||
}
|
||||
|
||||
void ScriptEndpoint::updateValue() {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "updateValue", Qt::QueuedConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
_lastValue = (float)_callable.call().toNumber();
|
||||
}
|
||||
|
||||
void ScriptEndpoint::apply(float newValue, float oldValue, const Pointer& source) {
|
||||
internalApply(newValue, oldValue, source->getInput().getID());
|
||||
}
|
||||
|
||||
void ScriptEndpoint::internalApply(float newValue, float oldValue, int sourceID) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "internalApply", Qt::QueuedConnection,
|
||||
Q_ARG(float, newValue),
|
||||
Q_ARG(float, oldValue),
|
||||
Q_ARG(int, sourceID));
|
||||
return;
|
||||
}
|
||||
_callable.call(QScriptValue(),
|
||||
QScriptValueList({ QScriptValue(newValue), QScriptValue(oldValue), QScriptValue(sourceID) }));
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis 2015/10/23
|
||||
// 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_ScriptEndpoint_h
|
||||
#define hifi_Controllers_ScriptEndpoint_h
|
||||
|
||||
#include <QtScript/QScriptValue>
|
||||
|
||||
#include "../Endpoint.h"
|
||||
|
||||
namespace controller {
|
||||
|
||||
class ScriptEndpoint : public Endpoint {
|
||||
Q_OBJECT;
|
||||
public:
|
||||
ScriptEndpoint(const QScriptValue& callable)
|
||||
: Endpoint(Input::INVALID_INPUT), _callable(callable) {
|
||||
}
|
||||
|
||||
virtual float value();
|
||||
virtual void apply(float newValue, float oldValue, const Pointer& source);
|
||||
|
||||
protected:
|
||||
Q_INVOKABLE void updateValue();
|
||||
Q_INVOKABLE virtual void internalApply(float newValue, float oldValue, int sourceID);
|
||||
private:
|
||||
QScriptValue _callable;
|
||||
float _lastValue = 0.0f;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,9 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis 2015/10/23
|
||||
// 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
|
||||
//
|
||||
|
||||
#include "StandardEndpoint.h"
|
|
@ -0,0 +1,60 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis 2015/10/23
|
||||
// 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_StandardEndpoint_h
|
||||
#define hifi_Controllers_StandardEndpoint_h
|
||||
|
||||
#include "../Endpoint.h"
|
||||
|
||||
namespace controller {
|
||||
|
||||
class StandardEndpoint : public VirtualEndpoint {
|
||||
public:
|
||||
StandardEndpoint(const Input& input) : VirtualEndpoint(input) {}
|
||||
virtual bool writeable() const override { return !_written; }
|
||||
virtual bool readable() const override { return !_read; }
|
||||
virtual void reset() override {
|
||||
apply(0.0f, 0.0f, Endpoint::Pointer());
|
||||
apply(Pose(), Pose(), Endpoint::Pointer());
|
||||
_written = _read = false;
|
||||
}
|
||||
|
||||
virtual float value() override {
|
||||
_read = true;
|
||||
return VirtualEndpoint::value();
|
||||
}
|
||||
|
||||
virtual void apply(float newValue, float oldValue, const Pointer& source) override {
|
||||
// For standard endpoints, the first NON-ZERO write counts.
|
||||
if (newValue != 0.0) {
|
||||
_written = true;
|
||||
}
|
||||
VirtualEndpoint::apply(newValue, oldValue, source);
|
||||
}
|
||||
|
||||
virtual Pose pose() override {
|
||||
_read = true;
|
||||
return VirtualEndpoint::pose();
|
||||
}
|
||||
|
||||
virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override {
|
||||
if (newValue != Pose()) {
|
||||
_written = true;
|
||||
}
|
||||
VirtualEndpoint::apply(newValue, oldValue, source);
|
||||
}
|
||||
|
||||
private:
|
||||
bool _written { false };
|
||||
bool _read { false };
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue