Splitting files, adding test skeleton

This commit is contained in:
Brad Davis 2015-10-09 17:23:52 -07:00
parent 184e9a2209
commit c3775623aa
10 changed files with 295 additions and 352 deletions

View file

@ -1,190 +0,0 @@
#include <map>
#include <list>
#include <QtCore/QObject>
#include <QtScript/QScriptValue>
extern float currentTime();
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 EndpointList = std::list<Endpoint*>;
const EndpointList& getHardwareEndpoints();
// 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)
}
};
class VirtualEndpoint : public Endpoint {
public:
virtual void apply(float newValue) {
if (newValue != _lastValue) {
_lastValue = newValue;
}
}
virtual float value() {
return _lastValue;
}
float _lastValue;
};
/*
* 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;
}
}
};
}

View file

@ -1,149 +0,0 @@
#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;
}
}
};
}

View file

@ -13,19 +13,6 @@
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:
@ -55,4 +42,50 @@ namespace Controllers {
float _lastValue;
};
float currentTime() {
return 0;
}
/*
* 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;
};
// FIXME how do we handle dynamic changes in connected hardware?
const Endpoint::List& Endpoint::getHardwareEndpoints() {
static Endpoint::List ACTIVE_HARDWARE_ENDPOINTS;
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
});
return ACTIVE_HARDWARE_ENDPOINTS;
}
}

View file

@ -0,0 +1,41 @@
//
// 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 "Filter.h"
#include <QtCore/QObject>
#include <QtScript/QScriptValue>
namespace Controllers {
class ScaleFilter : public Filter {
public:
virtual float apply(float newValue, float oldValue) {
return newValue * _scale;
}
private:
float _scale{ 1.0 };
};
class PulseFilter : public Filter {
public:
virtual float apply(float newValue, float oldValue) {
// ???
}
private:
float _lastEmitValue{ 0 };
float _lastEmitTime{ 0 };
float _interval{ -1.0f };
};
}

View file

@ -0,0 +1,29 @@
//
// 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_Filter_h
#define hifi_Controllers_Filter_h
#include <list>
#include <memory>
namespace Controllers {
// Encapsulates part of a filter chain
class Filter {
public:
virtual float apply(float newValue, float oldValue) = 0;
using Pointer = std::shared_ptr<Filter>;
using List = std::list<Pointer>;
};
}
#endif

View file

@ -0,0 +1,9 @@
#include "Mapping.h"
#include <QtCore/QObject>
#include <QtScript/QScriptValue>
extern float currentTime();
namespace Controllers {
}

View file

@ -0,0 +1,87 @@
#include <map>
#include <list>
#include <QtCore/QObject>
#include <QtScript/QScriptValue>
extern float currentTime();
#include "Endpoint.h"
#include "Filter.h"
#include "Route.h"
namespace Controllers {
using ValueMap = std::map<Endpoint::Pointer, float>;
class Mapping {
public:
// Map of source channels to route lists
using Map = std::map<Endpoint::Pointer, Route::List>;
Map _channelMappings;
ValueMap _lastValues;
void parse(const QString& json);
QString serialize();
};
// 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;
// }
// }
// };
}

View file

@ -0,0 +1,32 @@
//
// 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_Route_h
#define hifi_Controllers_Route_h
#include "Endpoint.h"
#include "Filter.h"
namespace Controllers {
/*
* encapsulates a source, destination and filters to apply
*/
class Route {
public:
Endpoint::Pointer _source;
Endpoint::Pointer _destination;
Filter::List _filters;
using Pointer = std::shared_ptr<Route>;
using List = std::list<Pointer>;
};
}
#endif

View file

@ -0,0 +1,13 @@
set(TARGET_NAME controllers-test)
AUTOSCRIBE_SHADER_LIB(gpu model render-utils )
# This is not a testcase -- just set it up as a regular hifi project
setup_hifi_project(Script)
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
# link in the shared libraries
link_hifi_libraries(shared script-engine input-plugins controllers)
copy_dlls_beside_windows_executable()

View file

@ -0,0 +1,38 @@
//
// main.cpp
// tests/gpu-test/src
//
// 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 <unordered_map>
#include <memory>
#include <cstdio>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <QtCore/QTime>
#include <QtCore/QTimer>
#include <QtCore/QDir>
#include <QtCore/QElapsedTimer>
#include <QtCore/QFile>
#include <QtCore/QLoggingCategory>
#include <QtGui/QResizeEvent>
#include <QtGui/QWindow>
#include <QtGui/QGuiApplication>
#include <QtGui/QImage>
int main(int argc, char** argv) {
QGuiApplication app(argc, argv);
QWindow window;
app.exec();
return 0;
}
#include "main.moc"