diff --git a/libraries/controllers/src/controllers/Endpoint.h b/libraries/controllers/src/controllers/Endpoint.h index 7361c15706..48cdf015fa 100644 --- a/libraries/controllers/src/controllers/Endpoint.h +++ b/libraries/controllers/src/controllers/Endpoint.h @@ -13,6 +13,8 @@ #include #include +class QScriptValue; + namespace Controllers { /* * Encapsulates a particular input / output, @@ -20,13 +22,14 @@ namespace Controllers { */ class Endpoint { public: - virtual float value() = 0; - virtual void apply(float newValue, float oldValue, const Endpoint& source) = 0; + virtual float value() { return 0; } // = 0; + virtual void apply(float newValue, float oldValue, const Endpoint& source) {} // = 0; using Pointer = std::shared_ptr; using List = std::list; static const List& getHardwareEndpoints(); + static Pointer getEndpoint(const QScriptValue& value); }; } diff --git a/libraries/controllers/src/controllers/Filter.cpp b/libraries/controllers/src/controllers/Filter.cpp index 6733ddc3e9..e0c6adfcac 100644 --- a/libraries/controllers/src/controllers/Filter.cpp +++ b/libraries/controllers/src/controllers/Filter.cpp @@ -13,30 +13,6 @@ 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 }; - }; - - Filter::Pointer Filter::parse(const QJsonObject& json) { // FIXME parse the json object and determine the instance type to create return Filter::Pointer(); diff --git a/libraries/controllers/src/controllers/Filter.h b/libraries/controllers/src/controllers/Filter.h index a2921ee47d..de58dc3647 100644 --- a/libraries/controllers/src/controllers/Filter.h +++ b/libraries/controllers/src/controllers/Filter.h @@ -12,6 +12,10 @@ #include #include +#include +#include + +#include class QJsonObject; @@ -20,14 +24,155 @@ namespace Controllers { // Encapsulates part of a filter chain class Filter { public: - virtual float apply(float newValue, float oldValue) = 0; + virtual float apply(float value) const = 0; using Pointer = std::shared_ptr; using List = std::list; + using Lambda = std::function; static Filter::Pointer parse(const QJsonObject& json); }; + + class LambdaFilter : public Filter { + public: + LambdaFilter(Lambda f) : _function(f) {}; + + virtual float apply(float value) const { + return _function(value); + } + + private: + Lambda _function; + }; + + class ScriptFilter : public Filter { + public: + + }; + + //class ScaleFilter : public Filter { + //public: + // ScaleFilter(float scale); + // virtual float apply(float scale) const override { + // return value * _scale; + // } + + //private: + // const float _scale; + //}; + + //class AbstractRangeFilter : public Filter { + //public: + // RangeFilter(float min, float max) : _min(min), _max(max) {} + + //protected: + // const float _min; + // const float _max; + //}; + + ///* + //* Constrains will emit the input value on the first call, and every *interval* seconds, otherwise returns 0 + //*/ + //class PulseFilter : public Filter { + //public: + // PulseFilter(float interval); + // virtual float apply(float value) const override; + + //private: + // float _lastEmitTime{ -std::numeric_limits::max() }; + // const float _interval; + //}; + + ////class DeadzoneFilter : public AbstractRangeFilter { + ////public: + //// DeadzoneFilter(float min, float max = 1.0f); + //// virtual float apply(float newValue, float oldValue) override; + ////}; + + //class EasingFilter : public Filter { + //public: + // virtual float apply(float value) const override; + + //private: + // QEasingCurve _curve; + //}; + + //// GLSL style filters + //class StepFilter : public Filter { + //public: + // StepFilter(float edge) : _edge(edge) {}; + // virtual float apply(float value) const override; + + //private: + // const float _edge; + //}; + + //class PowFilter : public Filter { + //public: + // PowFilter(float exponent) : _exponent(exponent) {}; + // virtual float apply(float value) const override; + + //private: + // const float _exponent; + //}; + + //class ClampFilter : public RangeFilter { + //public: + // ClampFilter(float min = 0.0, float max = 1.0) : RangeFilter(min, max) {}; + // virtual float apply(float value) const override; + //}; + + //class AbsFilter : public Filter { + //public: + // virtual float apply(float value) const override; + //}; + + //class SignFilter : public Filter { + //public: + // virtual float apply(float value) const override; + //}; + + //class FloorFilter : public Filter { + //public: + // virtual float apply(float value) const override { + // return floor(newValue); + // } + //}; + + //class CeilFilter : public Filter { + //public: + // virtual float apply(float value) const override { + // return ceil(newValue); + // } + //}; + + //class FractFilter : public Filter { + //public: + // virtual float apply(float value) const override { + // return fract(newValue); + // } + //}; + + //class MinFilter : public Filter { + //public: + // MinFilter(float mine) : _min(min) {}; + + // virtual float apply(float value) const override { + // return glm::min(_min, newValue); + // } + + //private: + // const float _min; + //}; + + //class MaxFilter : public Filter { + //public: + // MaxFilter(float max) : _max(max) {}; + // virtual float apply(float newValue, float oldValue) override; + //private: + // const float _max; + //}; } #endif diff --git a/libraries/controllers/src/controllers/Mapping.cpp b/libraries/controllers/src/controllers/Mapping.cpp index 3fdbd71d1c..dd1ec14d1e 100644 --- a/libraries/controllers/src/controllers/Mapping.cpp +++ b/libraries/controllers/src/controllers/Mapping.cpp @@ -2,3 +2,62 @@ namespace Controllers { } + +// class MappingsStack { +// std::list _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; +// } +// } +// }; diff --git a/libraries/controllers/src/controllers/Mapping.h b/libraries/controllers/src/controllers/Mapping.h index 6f843a7b23..4154701478 100644 --- a/libraries/controllers/src/controllers/Mapping.h +++ b/libraries/controllers/src/controllers/Mapping.h @@ -1,3 +1,15 @@ +// +// 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_Mapping_h +#define hifi_Controllers_Mapping_h + #include #include @@ -14,6 +26,8 @@ namespace Controllers { public: // Map of source channels to route lists using Map = std::map; + using Pointer = std::shared_ptr; + using List = std::list; Map _channelMappings; ValueMap _lastValues; @@ -22,62 +36,6 @@ namespace Controllers { QString serialize(); }; -// class MappingsStack { -// std::list _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; -// } -// } -// }; } + +#endif \ No newline at end of file diff --git a/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp b/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp new file mode 100644 index 0000000000..b8d5c851f5 --- /dev/null +++ b/libraries/controllers/src/controllers/NewControllerScriptingInterface.cpp @@ -0,0 +1,125 @@ +#include "NewControllerScriptingInterface.h" + +#include + +#include + +#include "GLMHelpers.h" + +#include "impl/MappingBuilderProxy.h" + +namespace Controllers { + +QObject* NewControllerScriptingInterface::newMapping() { + qDebug() << "Creating new Mapping proxy"; + return new MappingBuilderProxy(std::make_shared()); +} + +float NewControllerScriptingInterface::getValue(const QScriptValue& source) { + return 0; +} + +} // namespace controllers + + + + +// class MappingsStack { +// std::list _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; +// } +// } +// }; +//var mapping = Controller.newMapping(); +//mapping.map(hydra.LeftButton0, actions.ContextMenu); +//mapping.map(hydra.LeftButton0).to(xbox.RT); +//mapping.from(xbox.RT).constrainToBoolean().invert().to(actions.Foo) +// mapping.from(xbox.RY).invert().deadZone(0.2).to(actions.Pitch) +// mapping.from(xbox.RY).filter(function(newValue, oldValue) { +// return newValue * 2.0 +//}).to(actions.Pitch) + +//mapping.from(function(time) { +// return Math.cos(time); +// }).to(actions.Pitch); + +// mapping.mapFromFunction(function() { +// return x; +// }, actions.ContextMenu); + +// mapping.from(xbox.LY).clamp(0, 1).to(actions.Forward); +// mapping.from(xbox.LY).clamp(-1, 0).to(actions.Backward); +// mapping.from(xbox.RY).clamp(0, 1).to(actions.Forward); +// mapping.from(xbox.RS).to(); +// mapping.from(xbox.ALL).to(); + +// mapping.from(xbox.RY).to(function(...) { ... }); +// mapping.from(xbox.RY).pass(); + +// mapping.suppress() ≅ mapping.to(null) +// mapping.pass() ≅ mapping.to(fromControl) + +// mapping.from(keyboard.RightParen).invert().to(actions.Yaw) +// mapping.from(keyboard.LeftParen).to(actions.Yaw) + +// mapping.from(hydra.LX).pulse(MIN_SNAP_TIME, 3.0).to(Actions.Yaw) + +// mapping.from(keyboard.LeftParen).pulse(MIN_SNAP_TIME).to(Actions.Yaw) +// // Enable and disable as above + +// mappingSnap.from(hydra.LX).to(function(newValue, oldValue) { +// timeSinceLastYaw += deltaTime + +#include "NewControllerScriptingInterface.moc" diff --git a/libraries/controllers/src/controllers/NewControllerScriptingInterface.h b/libraries/controllers/src/controllers/NewControllerScriptingInterface.h new file mode 100644 index 0000000000..8730c2da89 --- /dev/null +++ b/libraries/controllers/src/controllers/NewControllerScriptingInterface.h @@ -0,0 +1,31 @@ +// +// 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_NewControllerScriptingInterface_h +#define hifi_Controllers_NewControllerScriptingInterface_h + +#include +#include + +#include "Mapping.h" + +class QScriptValue; + +namespace Controllers { + class NewControllerScriptingInterface : public QObject { + Q_OBJECT + + public: + Q_INVOKABLE QObject* newMapping(); + Q_INVOKABLE float getValue(const QScriptValue& source); + }; +} + + +#endif diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp new file mode 100644 index 0000000000..e16fa511db --- /dev/null +++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.cpp @@ -0,0 +1,33 @@ +// +// 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 "MappingBuilderProxy.h" + +#include +#include + +#include "RouteBuilderProxy.h" + +namespace Controllers { + +QObject* MappingBuilderProxy::from(const QString& source) { + qDebug() << "Creating new Route builder proxy from " << source; + auto route = Route::Pointer(new Route()); + route->_source = endpointFor(source); + return new RouteBuilderProxy(this, route); +} + +Endpoint::Pointer MappingBuilderProxy::endpointFor(const QString& endpoint) { + static QHash ENDPOINTS; + if (!ENDPOINTS.contains(endpoint)) { + ENDPOINTS[endpoint] = std::make_shared(); + } + return ENDPOINTS[endpoint]; +} + +} diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h new file mode 100644 index 0000000000..6dac38b21e --- /dev/null +++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h @@ -0,0 +1,35 @@ +// +// 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_Impl_MappingBuilderProxy_h +#define hifi_Controllers_Impl_MappingBuilderProxy_h + +#include +#include + +#include "../Mapping.h" + +namespace Controllers { + +class MappingBuilderProxy : public QObject { + Q_OBJECT +public: + MappingBuilderProxy(Mapping::Pointer mapping) + : _mapping(mapping) { } + + Q_INVOKABLE QObject* from(const QString& fromEndpoint); + +protected: + friend class RouteBuilderProxy; + Endpoint::Pointer endpointFor(const QString& endpoint); + Mapping::Pointer _mapping; +}; + +} + +#endif diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp new file mode 100644 index 0000000000..d1659573e4 --- /dev/null +++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp @@ -0,0 +1,80 @@ +// +// 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 "RouteBuilderProxy.h" + +#include + +#include + +#include "MappingBuilderProxy.h" + +namespace Controllers { + +void RouteBuilderProxy::to(const QString& destination) { + qDebug() << "Completed route: " << destination; + auto sourceEndpoint = _route->_source; + auto& mapping = _parent->_mapping; + mapping->_channelMappings[sourceEndpoint].push_back(_route); + deleteLater(); +} + +QObject* RouteBuilderProxy::clamp(float min, float max) { + addFilter([=](float value) { + return glm::clamp(value, min, max); + }); + return this; +} + +QObject* RouteBuilderProxy::scale(float multiplier) { + addFilter([=](float value) { + return value * multiplier; + }); + return this; +} + +QObject* RouteBuilderProxy::invert() { + return scale(-1.0f); +} + +QObject* RouteBuilderProxy::deadZone(float min) { + assert(min < 1.0f); + float scale = 1.0f / (1.0f - min); + addFilter([=](float value) { + if (value < min) { + return 0.0f; + } + return (value - min) * scale; + }); + + return this; +} + +QObject* RouteBuilderProxy::constrainToInteger() { + addFilter([=](float value) { + return glm::sign(value); + }); + return this; +} + +QObject* RouteBuilderProxy::constrainToPositiveInteger() { + addFilter([=](float value) { + return (value <= 0.0f) ? 0.0f : 1.0f; + }); + return this; +} + +void RouteBuilderProxy::addFilter(Filter::Lambda lambda) { + Filter::Pointer filterPointer = std::make_shared < LambdaFilter > (lambda); + addFilter(filterPointer); +} + +void RouteBuilderProxy::addFilter(Filter::Pointer filter) { + _route->_filters.push_back(filter); +} + +} diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h new file mode 100644 index 0000000000..516712b969 --- /dev/null +++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h @@ -0,0 +1,42 @@ +// +// 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_Impl_RouteBuilderProxy_h +#define hifi_Controllers_Impl_RouteBuilderProxy_h + +#include +#include "../Filter.h" +#include "../Route.h" + +namespace Controllers { + +class MappingBuilderProxy; + +class RouteBuilderProxy : public QObject { + Q_OBJECT + public: + RouteBuilderProxy(MappingBuilderProxy* parent, Route::Pointer route) + : _parent(parent), _route(route) { } + + Q_INVOKABLE void to(const QString& destination); + Q_INVOKABLE QObject* clamp(float min, float max); + Q_INVOKABLE QObject* scale(float multiplier); + Q_INVOKABLE QObject* invert(); + Q_INVOKABLE QObject* deadZone(float min); + Q_INVOKABLE QObject* constrainToInteger(); + Q_INVOKABLE QObject* constrainToPositiveInteger(); + + private: + void addFilter(Filter::Lambda lambda); + void addFilter(Filter::Pointer filter); + Route::Pointer _route; + MappingBuilderProxy* _parent; + }; + +} +#endif diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index f78c8c47e0..ccb6533dd7 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #ifdef _WIN32 #include @@ -39,30 +40,29 @@ void usecTimestampNowForceClockSkew(int clockSkew) { ::usecTimestampNowAdjust = clockSkew; } +static qint64 TIME_REFERENCE = 0; // in usec +static std::once_flag usecTimestampNowIsInitialized; +static QElapsedTimer timestampTimer; + quint64 usecTimestampNow(bool wantDebug) { - static bool usecTimestampNowIsInitialized = false; - static qint64 TIME_REFERENCE = 0; // in usec - static QElapsedTimer timestampTimer; - - if (!usecTimestampNowIsInitialized) { - TIME_REFERENCE = QDateTime::currentMSecsSinceEpoch() * 1000; // ms to usec + std::call_once(usecTimestampNowIsInitialized, [&] { + TIME_REFERENCE = QDateTime::currentMSecsSinceEpoch() * USECS_PER_MSEC; // ms to usec timestampTimer.start(); - usecTimestampNowIsInitialized = true; - } + }); quint64 now; quint64 nsecsElapsed = timestampTimer.nsecsElapsed(); - quint64 usecsElapsed = nsecsElapsed / 1000; // nsec to usec + quint64 usecsElapsed = nsecsElapsed / NSECS_PER_USEC; // nsec to usec // QElapsedTimer may not advance if the CPU has gone to sleep. In which case it // will begin to deviate from real time. We detect that here, and reset if necessary quint64 msecsCurrentTime = QDateTime::currentMSecsSinceEpoch(); - quint64 msecsEstimate = (TIME_REFERENCE + usecsElapsed) / 1000; // usecs to msecs + quint64 msecsEstimate = (TIME_REFERENCE + usecsElapsed) / USECS_PER_MSEC; // usecs to msecs int possibleSkew = msecsEstimate - msecsCurrentTime; - const int TOLERANCE = 10000; // up to 10 seconds of skew is tolerated + const int TOLERANCE = 10 * MSECS_PER_SECOND; // up to 10 seconds of skew is tolerated if (abs(possibleSkew) > TOLERANCE) { // reset our TIME_REFERENCE and timer - TIME_REFERENCE = QDateTime::currentMSecsSinceEpoch() * 1000; // ms to usec + TIME_REFERENCE = QDateTime::currentMSecsSinceEpoch() * USECS_PER_MSEC; // ms to usec timestampTimer.restart(); now = TIME_REFERENCE + ::usecTimestampNowAdjust; @@ -118,6 +118,13 @@ quint64 usecTimestampNow(bool wantDebug) { return now; } +float secTimestampNow() { + static const auto START_TIME = usecTimestampNow(); + const auto nowUsecs = usecTimestampNow(); + const auto nowMsecs = nowUsecs / USECS_PER_MSEC; + return (float)nowMsecs / MSECS_PER_SECOND; +} + float randFloat() { return (rand() % 10000)/10000.0f; } diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 4967778cb4..98bc95cf6f 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -65,9 +65,14 @@ inline bool operator!=(const xColor& lhs, const xColor& rhs) // Use a custom User-Agent to avoid ModSecurity filtering, e.g. by hosting providers. const QByteArray HIGH_FIDELITY_USER_AGENT = "Mozilla/5.0 (HighFidelityInterface)"; +// Equivalent to time_t but in usecs instead of secs quint64 usecTimestampNow(bool wantDebug = false); void usecTimestampNowForceClockSkew(int clockSkew); +// Number of seconds expressed since the first call to this function, expressed as a float +// Maximum accuracy in msecs +float ssecTimestampNow(); + float randFloat(); int randIntInRange (int min, int max); float randFloatInRange (float min,float max); diff --git a/tests/controllers/qml/main.qml b/tests/controllers/qml/main.qml new file mode 100644 index 0000000000..9f660e5d35 --- /dev/null +++ b/tests/controllers/qml/main.qml @@ -0,0 +1,43 @@ +import QtQuick 2.1 +import QtQuick.Controls 1.0 +import QtQuick.Layouts 1.0 +import QtQuick.Dialogs 1.0 +import com.highfidelity.test 1.0 + +ApplicationWindow { + id: window + visible: true + + AppHook { + + } + +// NewControllers { +// id: newControllers +// } + + Rectangle { + id: page + width: 320; height: 480 + color: "lightgray" + Text { + id: helloText + text: "Hello world!" + y: 30 + anchors.horizontalCenter: page.horizontalCenter + font.pointSize: 24; font.bold: true + } + + MouseArea { + anchors.fill: parent + onClicked: { + var newMapping = NewControllers.newMapping(); + console.log("Mapping Object " + newMapping); + var routeBuilder = newMapping.from("Hello"); + console.log("Route Builder " + routeBuilder); + routeBuilder.clamp(0, 1).clamp(0, 1).to("Goodbye"); + } + } + } + +} diff --git a/tests/controllers/src/main.cpp b/tests/controllers/src/main.cpp index 88d29214d3..8311b26dab 100644 --- a/tests/controllers/src/main.cpp +++ b/tests/controllers/src/main.cpp @@ -27,12 +27,73 @@ #include #include +#include +#include +#include + +#include + +const QString& getQmlDir() { + static QString dir; + if (dir.isEmpty()) { + QDir path(__FILE__); + path.cdUp(); + dir = path.cleanPath(path.absoluteFilePath("../qml/")) + "/"; + qDebug() << "Qml Path: " << dir; + } + return dir; +} + +class AppHook : public QQuickItem { + Q_OBJECT + +public: + AppHook() { + qDebug() << "Hook Created"; + } +}; + +using namespace Controllers; + int main(int argc, char** argv) { + // Register our component type with QML. + qmlRegisterType("com.highfidelity.test", 1, 0, "AppHook"); + //qmlRegisterType("com.highfidelity.test", 1, 0, "NewControllers"); QGuiApplication app(argc, argv); - QWindow window; + QQmlApplicationEngine engine(getQmlDir() + "main.qml"); + engine.rootContext()->setContextProperty("NewControllers", new NewControllerScriptingInterface()); app.exec(); return 0; } + + +//QQmlEngine engine; +//QQmlComponent *component = new QQmlComponent(&engine); +// +//QObject::connect(&engine, SIGNAL(quit()), QCoreApplication::instance(), SLOT(quit())); +// +//component->loadUrl(QUrl("main.qml")); +// +//if (!component->isReady()) { +// qWarning("%s", qPrintable(component->errorString())); +// return -1; +//} +// +//QObject *topLevel = component->create(); +//QQuickWindow *window = qobject_cast(topLevel); +// +//QSurfaceFormat surfaceFormat = window->requestedFormat(); +//window->setFormat(surfaceFormat); +//window->show(); +// +//rc = app.exec(); +// +//delete component; +//return rc; +//} + + + #include "main.moc"