3
0
Fork 0
mirror of https://github.com/lubosz/overte.git synced 2025-04-27 11:55:25 +02:00

Working on controller refactoring

This commit is contained in:
Brad Davis 2015-10-10 03:05:42 -07:00
parent c2da6600f5
commit 9e4a7a6226
15 changed files with 701 additions and 98 deletions

View file

@ -13,6 +13,8 @@
#include <list>
#include <memory>
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<Endpoint>;
using List = std::list<Pointer>;
static const List& getHardwareEndpoints();
static Pointer getEndpoint(const QScriptValue& value);
};
}

View file

@ -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();

View file

@ -12,6 +12,10 @@
#include <list>
#include <memory>
#include <numeric>
#include <functional>
#include <QtCore/QEasingCurve>
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<Filter>;
using List = std::list<Pointer>;
using Lambda = std::function<float(float)>;
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<float>::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

View file

@ -2,3 +2,62 @@
namespace Controllers {
}
// 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,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 <map>
#include <QtCore/QString>
@ -14,6 +26,8 @@ namespace Controllers {
public:
// Map of source channels to route lists
using Map = std::map<Endpoint::Pointer, Route::List>;
using Pointer = std::shared_ptr<Mapping>;
using List = std::list<Pointer>;
Map _channelMappings;
ValueMap _lastValues;
@ -22,62 +36,6 @@ namespace Controllers {
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;
// }
// }
// };
}
#endif

View file

@ -0,0 +1,125 @@
#include "NewControllerScriptingInterface.h"
#include <mutex>
#include <QtScript/QScriptValue>
#include "GLMHelpers.h"
#include "impl/MappingBuilderProxy.h"
namespace Controllers {
QObject* NewControllerScriptingInterface::newMapping() {
qDebug() << "Creating new Mapping proxy";
return new MappingBuilderProxy(std::make_shared<Mapping>());
}
float NewControllerScriptingInterface::getValue(const QScriptValue& source) {
return 0;
}
} // namespace controllers
// 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;
// }
// }
// };
//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"

View file

@ -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 <QtCore/QObject>
#include <QtCore/QVariant>
#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

View file

@ -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 <QtCore/QHash>
#include <QtCore/QDebug>
#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<QString, Endpoint::Pointer> ENDPOINTS;
if (!ENDPOINTS.contains(endpoint)) {
ENDPOINTS[endpoint] = std::make_shared<Endpoint>();
}
return ENDPOINTS[endpoint];
}
}

View file

@ -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 <QtCore/QObject>
#include <QtCore/QString>
#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

View file

@ -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 <QtCore/QDebug>
#include <GLMHelpers.h>
#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);
}
}

View file

@ -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 <QtCore/QObject>
#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

View file

@ -15,6 +15,7 @@
#include <cstring>
#include <cctype>
#include <time.h>
#include <mutex>
#ifdef _WIN32
#include <windows.h>
@ -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;
}

View file

@ -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);

View file

@ -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");
}
}
}
}

View file

@ -27,12 +27,73 @@
#include <QtGui/QGuiApplication>
#include <QtGui/QImage>
#include <QtQuick/QQuickItem>
#include <QtQml/QQmlApplicationEngine>
#include <QtQml/QQmlContext>
#include <controllers/NewControllerScriptingInterface.h>
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<AppHook>("com.highfidelity.test", 1, 0, "AppHook");
//qmlRegisterType<NewControllerScriptingInterface>("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<QQuickWindow *>(topLevel);
//
//QSurfaceFormat surfaceFormat = window->requestedFormat();
//window->setFormat(surfaceFormat);
//window->show();
//
//rc = app.exec();
//
//delete component;
//return rc;
//}
#include "main.moc"