mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-11 00:26:35 +02:00
Prototyping controllers
This commit is contained in:
parent
1dfafec5af
commit
184e9a2209
4 changed files with 243 additions and 1 deletions
|
@ -118,7 +118,8 @@ target_link_libraries(${TARGET_NAME} ${BULLET_LIBRARIES})
|
|||
link_hifi_libraries(shared octree environment gpu procedural model render fbx networking model-networking entities avatars
|
||||
audio audio-client animation script-engine physics
|
||||
render-utils entities-renderer ui auto-updater
|
||||
plugins display-plugins input-plugins)
|
||||
plugins display-plugins input-plugins
|
||||
controllers)
|
||||
|
||||
add_dependency_external_projects(sdl2)
|
||||
|
||||
|
|
149
libraries/controllers/src/controllers/ControllerMapping.h
Normal file
149
libraries/controllers/src/controllers/ControllerMapping.h
Normal file
|
@ -0,0 +1,149 @@
|
|||
#include <map>
|
||||
#include <list>
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtScript/QScriptValue>
|
||||
|
||||
extern float currentTime();
|
||||
|
||||
namespace Controllers {
|
||||
|
||||
|
||||
/*
|
||||
* A function which provides input
|
||||
*/
|
||||
class FunctionEndpoint : public Endpoint {
|
||||
public:
|
||||
|
||||
virtual float value() override {
|
||||
float now = currentTime();
|
||||
float delta = now - _lastCalled;
|
||||
float result = _inputFunction.call(_object, QScriptValue(delta)).toNumber();
|
||||
_lastCalled = now;
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual void apply(float newValue, float oldValue, const Endpoint& source) override {
|
||||
if (newValue != oldValue) {
|
||||
//_outputFunction.call(newValue, oldValue, source);
|
||||
}
|
||||
}
|
||||
|
||||
float _lastValue{ NAN };
|
||||
float _lastCalled{ 0 };
|
||||
QScriptValue _outputFunction;
|
||||
QScriptValue _inputFunction;
|
||||
QScriptValue _object;
|
||||
};
|
||||
|
||||
|
||||
// Encapsulates part of a filter chain
|
||||
class Filter {
|
||||
public:
|
||||
virtual float apply(float newValue, float oldValue) = 0;
|
||||
};
|
||||
|
||||
class ScaleFilter : public Filter {
|
||||
public:
|
||||
virtual float apply(float newValue, float oldValue) {
|
||||
return newValue * _scale;
|
||||
}
|
||||
|
||||
float _scale{ 1.0 };
|
||||
};
|
||||
|
||||
class PulseFilter : public Filter {
|
||||
public:
|
||||
virtual float apply(float newValue, float oldValue) {
|
||||
// ???
|
||||
}
|
||||
|
||||
float _lastEmitValue{ 0 };
|
||||
float _lastEmitTime{ 0 };
|
||||
float _interval{ -1.0f };
|
||||
};
|
||||
|
||||
using FilterList = std::list<Filter*>;
|
||||
|
||||
/*
|
||||
* encapsulates a source, destination and filters to apply
|
||||
*/
|
||||
class Route {
|
||||
public:
|
||||
Endpoint* _source;
|
||||
Endpoint* _destination;
|
||||
FilterList _filters;
|
||||
};
|
||||
|
||||
using ValueMap = std::map<Endpoint*, float>;
|
||||
|
||||
class Mapping {
|
||||
public:
|
||||
// List of routes
|
||||
using List = std::list<Route>;
|
||||
// Map of source channels to route lists
|
||||
using Map = std::map<Endpoint*, List>;
|
||||
|
||||
Map _channelMappings;
|
||||
ValueMap _lastValues;
|
||||
};
|
||||
|
||||
class MappingsStack {
|
||||
std::list<Mapping> _stack;
|
||||
ValueMap _lastValues;
|
||||
|
||||
void update() {
|
||||
EndpointList hardwareInputs = getHardwareEndpoints();
|
||||
ValueMap currentValues;
|
||||
|
||||
for (auto input : hardwareInputs) {
|
||||
currentValues[input] = input->value();
|
||||
}
|
||||
|
||||
// Now process the current values for each level of the stack
|
||||
for (auto& mapping : _stack) {
|
||||
update(mapping, currentValues);
|
||||
}
|
||||
|
||||
_lastValues = currentValues;
|
||||
}
|
||||
|
||||
void update(Mapping& mapping, ValueMap& values) {
|
||||
ValueMap updates;
|
||||
EndpointList consumedEndpoints;
|
||||
for (const auto& entry : values) {
|
||||
Endpoint* endpoint = entry.first;
|
||||
if (!mapping._channelMappings.count(endpoint)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Mapping::List& routes = mapping._channelMappings[endpoint];
|
||||
consumedEndpoints.push_back(endpoint);
|
||||
for (const auto& route : routes) {
|
||||
float lastValue = 0;
|
||||
if (mapping._lastValues.count(endpoint)) {
|
||||
lastValue = mapping._lastValues[endpoint];
|
||||
}
|
||||
float value = entry.second;
|
||||
for (const auto& filter : route._filters) {
|
||||
value = filter->apply(value, lastValue);
|
||||
}
|
||||
updates[route._destination] = value;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the last seen values
|
||||
mapping._lastValues = values;
|
||||
|
||||
// Remove all the consumed inputs
|
||||
for (auto endpoint : consumedEndpoints) {
|
||||
values.erase(endpoint);
|
||||
}
|
||||
|
||||
// Add all the updates (may restore some of the consumed data if a passthrough was created (i.e. source == dest)
|
||||
for (const auto& entry : updates) {
|
||||
values[entry.first] = entry.second;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
58
libraries/controllers/src/controllers/Endpoint.cpp
Normal file
58
libraries/controllers/src/controllers/Endpoint.cpp
Normal file
|
@ -0,0 +1,58 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis 2015/10/09
|
||||
// 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 "Endpoint.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <input-plugins/UserInputMapper.h>
|
||||
|
||||
namespace Controllers {
|
||||
|
||||
// FIXME how do we handle dynamic changes in connected hardware?
|
||||
const Endpoint::List& Endpoint::getHardwareEndpoints() {
|
||||
static Endpoint::List ACTIVE_HARDWARE;
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&] {
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
// TODO populate ACTIVE_HARDWARE with all the connected devices
|
||||
// For each connected device
|
||||
// for each input channel
|
||||
// build a HardwareEndpoint instance around the input channel and add it to the list
|
||||
});
|
||||
}
|
||||
|
||||
// Ex: xbox.RY, xbox.A ....
|
||||
class HardwareEndpoint : public Endpoint {
|
||||
public:
|
||||
virtual float value() override {
|
||||
// ...
|
||||
}
|
||||
|
||||
virtual void apply(float newValue, float oldValue, const Endpoint& source) override {
|
||||
// Default does nothing, but in theory this could be something like vibration
|
||||
// mapping.from(xbox.X).to(xbox.Vibrate)
|
||||
}
|
||||
};
|
||||
|
||||
// Ex: Standard.RY, Action.Yaw
|
||||
class VirtualEndpoint : public Endpoint {
|
||||
public:
|
||||
virtual void apply(float newValue) {
|
||||
if (newValue != _lastValue) {
|
||||
_lastValue = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
virtual float value() {
|
||||
return _lastValue;
|
||||
}
|
||||
|
||||
float _lastValue;
|
||||
};
|
||||
|
||||
}
|
34
libraries/controllers/src/controllers/Endpoint.h
Normal file
34
libraries/controllers/src/controllers/Endpoint.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis 2015/10/09
|
||||
// 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_Endpoint_h
|
||||
#define hifi_Controllers_Endpoint_h
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
|
||||
namespace Controllers {
|
||||
/*
|
||||
* Encapsulates a particular input / output,
|
||||
* i.e. Hydra.Button0, Standard.X, Action.Yaw
|
||||
*/
|
||||
class Endpoint {
|
||||
public:
|
||||
virtual float value() = 0;
|
||||
virtual void apply(float newValue, float oldValue, const Endpoint& source) = 0;
|
||||
|
||||
using Pointer = std::shared_ptr<Endpoint>;
|
||||
using List = std::list<Pointer>;
|
||||
|
||||
static const List& getHardwareEndpoints();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue