summaryrefslogtreecommitdiffstats
path: root/src/quick3d/quick3dscene2d
diff options
context:
space:
mode:
authorAntti Määttä <antti.maatta@qt.io>2017-02-01 14:27:59 +0200
committerAntti Määttä <antti.maatta@qt.io>2017-02-28 09:48:24 +0000
commitdbd24a90610a3a229781edf7c1eb0962b8fb0b20 (patch)
treec29d56e9e8559d4884256f23f3ab39b054a602c7 /src/quick3d/quick3dscene2d
parent154c3a9b44082a176a9700b5086a7bc758155a25 (diff)
Split scene2d implementation to multiple files
Change-Id: I7926898be5409334ec46b59eec76678c613b0d87 Reviewed-by: Tomi Korpipää <tomi.korpipaa@qt.io> Reviewed-by: Kevin Ottens <kevin.ottens@kdab.com>
Diffstat (limited to 'src/quick3d/quick3dscene2d')
-rw-r--r--src/quick3d/quick3dscene2d/items/items.pri8
-rw-r--r--src/quick3d/quick3dscene2d/items/qscene2d.cpp420
-rw-r--r--src/quick3d/quick3dscene2d/items/qscene2d_p.h113
-rw-r--r--src/quick3d/quick3dscene2d/items/scene2d.cpp1
-rw-r--r--src/quick3d/quick3dscene2d/items/scene2d_p.h3
-rw-r--r--src/quick3d/quick3dscene2d/items/scene2dmanager.cpp368
-rw-r--r--src/quick3d/quick3dscene2d/items/scene2dmanager_p.h124
-rw-r--r--src/quick3d/quick3dscene2d/items/scene2dsharedobject.cpp161
-rw-r--r--src/quick3d/quick3dscene2d/items/scene2dsharedobject_p.h131
9 files changed, 793 insertions, 536 deletions
diff --git a/src/quick3d/quick3dscene2d/items/items.pri b/src/quick3d/quick3dscene2d/items/items.pri
index 7a9a641f8..5faa3f729 100644
--- a/src/quick3d/quick3dscene2d/items/items.pri
+++ b/src/quick3d/quick3dscene2d/items/items.pri
@@ -1,10 +1,14 @@
HEADERS += \
$$PWD/scene2d_p.h \
$$PWD/qscene2d_p.h \
- $$PWD/qscene2d.h
+ $$PWD/qscene2d.h \
+ $$PWD/scene2dmanager_p.h \
+ $$PWD/scene2dsharedobject_p.h
SOURCES += \
$$PWD/qscene2d.cpp \
- $$PWD/scene2d.cpp
+ $$PWD/scene2d.cpp \
+ $$PWD/scene2dmanager.cpp \
+ $$PWD/scene2dsharedobject.cpp
INCLUDEPATH += $$PWD
diff --git a/src/quick3d/quick3dscene2d/items/qscene2d.cpp b/src/quick3d/quick3dscene2d/items/qscene2d.cpp
index fa46cd3d2..e70855ce1 100644
--- a/src/quick3d/quick3dscene2d/items/qscene2d.cpp
+++ b/src/quick3d/quick3dscene2d/items/qscene2d.cpp
@@ -37,11 +37,10 @@
#include "qscene2d.h"
#include "qscene2d_p.h"
#include "scene2d_p.h"
+#include "scene2dmanager_p.h"
#include <Qt3DCore/QPropertyUpdatedChange>
-#include <QtGui/QOpenGLContext>
-
QT_BEGIN_NAMESPACE
using namespace Qt3DCore;
@@ -103,423 +102,6 @@ namespace Quick {
Holds whether the source has been loaded.
*/
-class RenderControl : public QQuickRenderControl
-{
-public:
- RenderControl(QWindow *w) : m_window(w) { }
- QWindow *renderWindow(QPoint *offset) Q_DECL_OVERRIDE;
-
-private:
- QWindow *m_window;
-};
-
-QWindow *RenderControl::renderWindow(QPoint *offset)
-{
- if (offset)
- *offset = QPoint(0, 0);
- return m_window;
-}
-
-/*!
- \internal
- Constructs object shared by the front-end and back-end to synchronize the rendering.
- */
-Scene2DSharedObject::Scene2DSharedObject(Scene2DManager *manager)
- : m_quit(false)
- , m_requestSync(false)
- , m_prepared(false)
- , m_initialized(false)
- , m_renderControl(nullptr)
- , m_quickWindow(nullptr)
- , m_renderManager(manager)
- , m_surface(nullptr)
- , m_renderObject(nullptr)
- , m_disallowed(false)
-{
-}
-
-Scene2DSharedObject::~Scene2DSharedObject()
-{
-}
-
-void Scene2DSharedObject::cleanup()
-{
- delete m_renderControl;
- delete m_quickWindow;
- delete m_surface;
- m_renderControl = nullptr;
- m_quickWindow = nullptr;
- m_surface = nullptr;
- m_initialized = false;
-}
-
-bool Scene2DSharedObject::canRender() const
-{
- return m_initialized && m_prepared && !m_disallowed;
-}
-
-bool Scene2DSharedObject::isInitialized() const
-{
- return m_initialized;
-}
-
-void Scene2DSharedObject::disallowRender()
-{
- m_disallowed = true;
-}
-
-void Scene2DSharedObject::setInitialized()
-{
- m_initialized = true;
-}
-
-bool Scene2DSharedObject::isPrepared() const
-{
- return m_prepared;
-}
-
-void Scene2DSharedObject::setPrepared()
-{
- m_prepared = true;
-}
-
-// not protected, call only from main thread
-bool Scene2DSharedObject::isQuit() const
-{
- Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread());
- return m_quit;
-}
-
-// not protected, call only from main thread
-void Scene2DSharedObject::requestQuit()
-{
- Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread());
- m_quit = true;
- QCoreApplication::postEvent(m_renderObject, new QEvent(QUIT));
-}
-
-bool Scene2DSharedObject::isSyncRequested() const
-{
- return m_requestSync;
-}
-
-void Scene2DSharedObject::requestRender(bool sync)
-{
- m_requestSync = sync;
- QCoreApplication::postEvent(m_renderObject, new QEvent(RENDER));
-}
-
-void Scene2DSharedObject::wait()
-{
- m_cond.wait(&m_mutex);
-}
-
-void Scene2DSharedObject::wake()
-{
- m_cond.wakeOne();
-}
-
-void Scene2DSharedObject::clearSyncRequest()
-{
- m_requestSync = false;
-}
-
-/*!
- \internal
- Constructs qml render manager.
- */
-Scene2DManager::Scene2DManager(QScene2DPrivate *priv)
- : m_priv(priv)
- , m_qmlEngine(nullptr)
- , m_qmlComponent(nullptr)
- , m_rootItem(nullptr)
- , m_source(nullptr)
- , m_requested(false)
- , m_initialized(false)
- , m_renderSyncRequested(false)
- , m_sharedObject(new Scene2DSharedObject(this))
- , m_renderPolicy(QScene2D::Continuous)
- , m_backendInitialized(false)
- , m_noSourceMode(false)
- , m_item(nullptr)
- , m_ownEngine(false)
-{
- m_sharedObject->m_surface = new QOffscreenSurface;
- m_sharedObject->m_surface->setFormat(QSurfaceFormat::defaultFormat());
- m_sharedObject->m_surface->create();
-
- // Create render control
- m_sharedObject->m_renderControl = new RenderControl(nullptr);
-
- // Create window to render the QML with
- m_sharedObject->m_quickWindow = new QQuickWindow(m_sharedObject->m_renderControl);
- m_sharedObject->m_quickWindow->setClearBeforeRendering(false);
-
- connect(m_sharedObject->m_renderControl, &QQuickRenderControl::renderRequested,
- this, &Scene2DManager::requestRender);
- connect(m_sharedObject->m_renderControl, &QQuickRenderControl::sceneChanged,
- this, &Scene2DManager::requestRenderSync);
-}
-
-Scene2DManager::~Scene2DManager()
-{
- m_sharedObject = nullptr;
-}
-
-void Scene2DManager::requestRender()
-{
- // Don't request render until the backend is initialized.
- if (m_sharedObject->canRender()) {
- if (!m_requested) {
- m_requested = true;
- QCoreApplication::postEvent(this, new QEvent(RENDER));
- }
- }
-}
-
-void Scene2DManager::requestRenderSync()
-{
- // Don't request render until the backed is initialized.
- if (m_sharedObject->canRender()) {
- if (!m_requested) {
- m_requested = true;
- QCoreApplication::postEvent(this, new QEvent(RENDERSYNC));
- }
- } else {
- m_renderSyncRequested = true;
- }
-}
-
-void Scene2DManager::startIfInitialized()
-{
- if (!m_initialized && m_backendInitialized) {
- if (m_source.isValid() && !m_noSourceMode) {
- // Create a QML engine.
- if (!m_qmlEngine) {
- m_qmlEngine = new QQmlEngine;
- if (!m_qmlEngine->incubationController()) {
- m_qmlEngine->setIncubationController(m_sharedObject->m_quickWindow
- ->incubationController());
- }
- }
-
- // create component
- m_ownEngine = true;
- m_qmlComponent = new QQmlComponent(m_qmlEngine, m_source);
- if (m_qmlComponent->isLoading()) {
- connect(m_qmlComponent, &QQmlComponent::statusChanged,
- this, &Scene2DManager::run);
- } else {
- run();
- }
- } else if (m_item != nullptr) {
- m_rootItem = m_item;
-
- // Associate root item with the window.
- m_rootItem->setParentItem(m_sharedObject->m_quickWindow->contentItem());
-
- // Update window size.
- updateSizes();
-
- m_initialized = true;
- m_sharedObject->setInitialized();
- }
- }
-}
-
-void Scene2DManager::stopAndClean()
-{
- if (m_sharedObject->isInitialized()) {
- QMutexLocker lock(&m_sharedObject->m_mutex);
- m_sharedObject->requestQuit();
- m_sharedObject->wait();
- m_sharedObject->cleanup();
- if (m_ownEngine) {
- QObject::disconnect(m_connection);
- delete m_qmlEngine;
- }
- delete m_qmlComponent;
- m_qmlEngine = nullptr;
- m_qmlComponent = nullptr;
- }
-}
-
-void Scene2DManager::run()
-{
- disconnect(m_qmlComponent, &QQmlComponent::statusChanged, this, &Scene2DManager::run);
-
- if (m_qmlComponent->isError()) {
- QList<QQmlError> errorList = m_qmlComponent->errors();
- for (const QQmlError &error: errorList)
- qWarning() << error.url() << error.line() << error;
- return;
- }
-
- QObject *rootObject = m_qmlComponent->create();
- if (m_qmlComponent->isError()) {
- QList<QQmlError> errorList = m_qmlComponent->errors();
- for (const QQmlError &error: errorList)
- qWarning() << error.url() << error.line() << error;
- return;
- }
-
- m_rootItem = qobject_cast<QQuickItem *>(rootObject);
- if (!m_rootItem) {
- qWarning("QScene2D: Root item is not a QQuickItem.");
- delete rootObject;
- return;
- }
-
- // The root item is ready. Associate it with the window.
- m_rootItem->setParentItem(m_sharedObject->m_quickWindow->contentItem());
-
- // Update window size.
- updateSizes();
-
- m_initialized = true;
- m_sharedObject->setInitialized();
-
- emit onLoadedChanged();
-}
-
-void Scene2DManager::updateSizes()
-{
- const int width = m_rootItem->width();
- const int height = m_rootItem->height();
- if (width == 0 || height == 0) {
- qWarning() << "QScene2D: Root item size not set.";
- return;
- }
- m_sharedObject->m_quickWindow->setGeometry(0, 0, width, height);
-}
-
-void Scene2DManager::setSource(const QUrl &url)
-{
- m_source = url;
- startIfInitialized();
-}
-
-void Scene2DManager::setItem(QQuickItem *item)
-{
- m_noSourceMode = true;
- m_item = item;
- startIfInitialized();
-}
-
-bool Scene2DManager::event(QEvent *e)
-{
- switch (e->type()) {
-
- case RENDER: {
- // just render request, don't need to call sync in render thread
- QMutexLocker lock(&m_sharedObject->m_mutex);
- m_sharedObject->requestRender(false);
- m_requested = false;
- return true;
- }
-
- case RENDERSYNC: {
- // sync and render request, main and render threads must be synchronized
- if (!m_sharedObject->isQuit())
- doRenderSync();
- m_requested = false;
- return true;
- }
-
- case PREPARE: {
- m_sharedObject->m_renderControl->prepareThread(m_sharedObject->m_renderThread);
- m_sharedObject->setPrepared();
-
- if (m_renderSyncRequested) {
- if (!m_requested) {
- m_requested = true;
- QCoreApplication::postEvent(this, new QEvent(RENDERSYNC));
- }
- m_renderSyncRequested = false;
- }
- return true;
- }
-
- case INITIALIZED: {
- // backend is initialized, start the qml
- m_backendInitialized = true;
- startIfInitialized();
- return true;
- }
-
- case RENDERED: {
- // render is done, excellent, now clean anything not needed anymore.
- stopAndClean();
- return true;
- }
-
- default:
- break;
- }
- return QObject::event(e);
-}
-
-bool Scene2DManager::forwardEvent(QEvent *event)
-{
- switch (event->type()) {
-
- case QEvent::MouseMove:
- case QEvent::MouseButtonDblClick:
- case QEvent::MouseButtonPress:
- case QEvent::MouseButtonRelease: {
- QMouseEvent* me = static_cast<QMouseEvent *>(event);
- QPointF pos = me->localPos();
- pos = QPointF(pos.x() * m_rootItem->width(), pos.y() * m_rootItem->height());
- QMouseEvent nme = QMouseEvent(me->type(), pos, pos, pos, me->button(), me->buttons(),
- me->modifiers(), Qt::MouseEventSynthesizedByApplication);
- QCoreApplication::sendEvent(m_sharedObject->m_quickWindow, &nme);
- } break;
-
- case QEvent::KeyPress:
- case QEvent::KeyRelease: {
- QCoreApplication::sendEvent(m_sharedObject->m_quickWindow, event);
- } break;
-
- default:
- break;
- }
- return false;
-}
-
-void Scene2DManager::doRenderSync()
-{
- QMutexLocker lock(&m_sharedObject->m_mutex);
-
- m_sharedObject->requestRender(true);
- m_sharedObject->m_renderControl->polishItems();
-
- // begin waiting render thread
- m_sharedObject->wait();
- m_requested = false;
-}
-
-void Scene2DManager::cleanup()
-{
- stopAndClean();
-}
-
-void Scene2DManager::setEngine(QQmlEngine *engine)
-{
- m_qmlEngine = engine;
- m_ownEngine = false;
- if (engine) {
- m_connection = QObject::connect(engine, &QObject::destroyed,
- this, &Scene2DManager::engineDestroyed);
- }
-}
-
-void Scene2DManager::engineDestroyed()
-{
- QObject::disconnect(m_connection);
- m_qmlEngine = nullptr;
- m_ownEngine = false;
-}
-
QScene2DPrivate::QScene2DPrivate()
: Qt3DCore::QNodePrivate()
diff --git a/src/quick3d/quick3dscene2d/items/qscene2d_p.h b/src/quick3d/quick3dscene2d/items/qscene2d_p.h
index 1aecbedd7..4c9a6a842 100644
--- a/src/quick3d/quick3dscene2d/items/qscene2d_p.h
+++ b/src/quick3d/quick3dscene2d/items/qscene2d_p.h
@@ -48,21 +48,10 @@
// We mean it.
//
-#include <QtQml/QQmlEngine>
-#include <QtQml/QQmlComponent>
-#include <QtQuick/QQuickItem>
-#include <QtQuick/QQuickWindow>
-#include <QtQuick/QQuickRenderControl>
-#include <QtGui/QOffscreenSurface>
-#include <QtCore/QCoreApplication>
-#include <QtCore/QWaitCondition>
-#include <QtCore/QThread>
-
#include <Qt3DQuickScene2D/qscene2d.h>
-#include <Qt3DRender/qabstracttexture.h>
-#include <private/qobject_p.h>
#include <private/qnode_p.h>
+#include <private/scene2dsharedobject_p.h>
QT_BEGIN_NAMESPACE
@@ -90,56 +79,6 @@ static const QEvent::Type RENDERED = QEvent::Type(QEvent::User + 6);
// main thread -> render thread
static const QEvent::Type QUIT = QEvent::Type(QEvent::User + 7);
-class Q_AUTOTEST_EXPORT Scene2DSharedObject
-{
-public:
- Scene2DSharedObject(Scene2DManager *manager);
- ~Scene2DSharedObject();
-
- QQuickRenderControl *m_renderControl;
- QQuickWindow *m_quickWindow;
- Scene2DManager *m_renderManager;
- QOffscreenSurface *m_surface;
-
- QThread *m_renderThread;
- QObject *m_renderObject;
-
- QWaitCondition m_cond;
- QMutex m_mutex;
-
- bool isInitialized() const;
- void setInitialized();
-
- void requestQuit();
- bool isQuit() const;
-
- void requestRender(bool sync);
-
- bool isSyncRequested() const;
- void clearSyncRequest();
-
- void wait();
- void wake();
-
- bool isPrepared() const;
- void setPrepared();
-
- void disallowRender();
- bool canRender() const;
-
- void cleanup();
-
-private:
-
- bool m_disallowed;
- bool m_quit;
- bool m_requestSync;
- bool m_requestRender;
- bool m_prepared;
- bool m_initialized;
-};
-
-typedef QSharedPointer<Scene2DSharedObject> Scene2DSharedObjectPtr;
class Q_AUTOTEST_EXPORT QScene2DPrivate : public Qt3DCore::QNodePrivate
{
@@ -161,59 +100,9 @@ struct QScene2DData
Qt3DCore::QNodeId output;
};
-class Scene2DManager : public QObject
-{
- Q_OBJECT
-public:
- Scene2DManager(QScene2DPrivate *priv);
- ~Scene2DManager();
-
- QQmlEngine *m_qmlEngine;
- QQmlComponent *m_qmlComponent;
- QQuickItem *m_rootItem;
- QQuickItem *m_item;
-
- QScene2DPrivate *m_priv;
- QSharedPointer<Scene2DSharedObject> m_sharedObject;
-
- QUrl m_source;
- Qt3DCore::QNodeId m_id;
- QMetaObject::Connection m_connection;
- QScene2D::RenderPolicy m_renderPolicy;
-
- bool m_requested;
- bool m_initialized;
- bool m_renderSyncRequested;
- bool m_backendInitialized;
- bool m_noSourceMode;
- bool m_ownEngine;
-
- void requestRender();
- void requestRenderSync();
- void doRenderSync();
- void startIfInitialized();
- void stopAndClean();
- void run();
- void updateSizes();
-
- void setSource(const QUrl &url);
- void setItem(QQuickItem *item);
-
- bool event(QEvent *e) Q_DECL_OVERRIDE;
- bool forwardEvent(QEvent *event);
-
- Q_SIGNAL void onLoadedChanged();
-
- void cleanup();
- void setEngine(QQmlEngine *engine);
- void engineDestroyed();
-};
-
} // namespace Quick
} // namespace Qt3DRender
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DRender::Quick::Scene2DSharedObjectPtr)
-
#endif // QT3DRENDER_QUICK3DSCENE2D_QSCENE2D_P_H
diff --git a/src/quick3d/quick3dscene2d/items/scene2d.cpp b/src/quick3d/quick3dscene2d/items/scene2d.cpp
index ef677bab8..fc2cf2c0e 100644
--- a/src/quick3d/quick3dscene2d/items/scene2d.cpp
+++ b/src/quick3d/quick3dscene2d/items/scene2d.cpp
@@ -42,6 +42,7 @@
#include <private/qscene2d_p.h>
#include <private/scene2d_p.h>
+#include <private/scene2dmanager_p.h>
#include <private/graphicscontext_p.h>
#include <private/texture_p.h>
#include <private/nodemanagers_p.h>
diff --git a/src/quick3d/quick3dscene2d/items/scene2d_p.h b/src/quick3d/quick3dscene2d/items/scene2d_p.h
index db32264c0..608ecc5dc 100644
--- a/src/quick3d/quick3dscene2d/items/scene2d_p.h
+++ b/src/quick3d/quick3dscene2d/items/scene2d_p.h
@@ -51,9 +51,6 @@
#include <Qt3DCore/qnodeid.h>
#include <Qt3DQuickScene2D/qscene2d.h>
-#include <QtCore/QCoreApplication>
-#include <QtCore/QSemaphore>
-
#include <private/qscene2d_p.h>
#include <private/qrendertargetoutput_p.h>
#include <private/backendnode_p.h>
diff --git a/src/quick3d/quick3dscene2d/items/scene2dmanager.cpp b/src/quick3d/quick3dscene2d/items/scene2dmanager.cpp
new file mode 100644
index 000000000..10d116127
--- /dev/null
+++ b/src/quick3d/quick3dscene2d/items/scene2dmanager.cpp
@@ -0,0 +1,368 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qscene2d.h"
+#include "qscene2d_p.h"
+#include "scene2d_p.h"
+#include "scene2dmanager_p.h"
+
+#include <Qt3DCore/QPropertyUpdatedChange>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt3DCore;
+
+namespace Qt3DRender {
+
+namespace Quick {
+
+class RenderControl : public QQuickRenderControl
+{
+public:
+ RenderControl(QWindow *w) : m_window(w) { }
+ QWindow *renderWindow(QPoint *offset) Q_DECL_OVERRIDE;
+
+private:
+ QWindow *m_window;
+};
+
+QWindow *RenderControl::renderWindow(QPoint *offset)
+{
+ if (offset)
+ *offset = QPoint(0, 0);
+ return m_window;
+}
+
+/*!
+ \internal
+ Constructs qml render manager.
+ */
+Scene2DManager::Scene2DManager(QScene2DPrivate *priv)
+ : m_priv(priv)
+ , m_qmlEngine(nullptr)
+ , m_qmlComponent(nullptr)
+ , m_rootItem(nullptr)
+ , m_source(nullptr)
+ , m_requested(false)
+ , m_initialized(false)
+ , m_renderSyncRequested(false)
+ , m_sharedObject(new Scene2DSharedObject(this))
+ , m_renderPolicy(QScene2D::Continuous)
+ , m_backendInitialized(false)
+ , m_noSourceMode(false)
+ , m_item(nullptr)
+ , m_ownEngine(false)
+{
+ m_sharedObject->m_surface = new QOffscreenSurface;
+ m_sharedObject->m_surface->setFormat(QSurfaceFormat::defaultFormat());
+ m_sharedObject->m_surface->create();
+
+ // Create render control
+ m_sharedObject->m_renderControl = new RenderControl(nullptr);
+
+ // Create window to render the QML with
+ m_sharedObject->m_quickWindow = new QQuickWindow(m_sharedObject->m_renderControl);
+ m_sharedObject->m_quickWindow->setClearBeforeRendering(false);
+
+ connect(m_sharedObject->m_renderControl, &QQuickRenderControl::renderRequested,
+ this, &Scene2DManager::requestRender);
+ connect(m_sharedObject->m_renderControl, &QQuickRenderControl::sceneChanged,
+ this, &Scene2DManager::requestRenderSync);
+}
+
+Scene2DManager::~Scene2DManager()
+{
+ m_sharedObject = nullptr;
+}
+
+void Scene2DManager::requestRender()
+{
+ // Don't request render until the backend is initialized.
+ if (m_sharedObject->canRender()) {
+ if (!m_requested) {
+ m_requested = true;
+ QCoreApplication::postEvent(this, new QEvent(RENDER));
+ }
+ }
+}
+
+void Scene2DManager::requestRenderSync()
+{
+ // Don't request render until the backed is initialized.
+ if (m_sharedObject->canRender()) {
+ if (!m_requested) {
+ m_requested = true;
+ QCoreApplication::postEvent(this, new QEvent(RENDERSYNC));
+ }
+ } else {
+ m_renderSyncRequested = true;
+ }
+}
+
+void Scene2DManager::startIfInitialized()
+{
+ if (!m_initialized && m_backendInitialized) {
+ if (m_source.isValid() && !m_noSourceMode) {
+ // Create a QML engine.
+ if (!m_qmlEngine) {
+ m_qmlEngine = new QQmlEngine;
+ if (!m_qmlEngine->incubationController()) {
+ m_qmlEngine->setIncubationController(m_sharedObject->m_quickWindow
+ ->incubationController());
+ }
+ }
+
+ // create component
+ m_ownEngine = true;
+ m_qmlComponent = new QQmlComponent(m_qmlEngine, m_source);
+ if (m_qmlComponent->isLoading()) {
+ connect(m_qmlComponent, &QQmlComponent::statusChanged,
+ this, &Scene2DManager::run);
+ } else {
+ run();
+ }
+ } else if (m_item != nullptr) {
+ m_rootItem = m_item;
+
+ // Associate root item with the window.
+ m_rootItem->setParentItem(m_sharedObject->m_quickWindow->contentItem());
+
+ // Update window size.
+ updateSizes();
+
+ m_initialized = true;
+ m_sharedObject->setInitialized();
+ }
+ }
+}
+
+void Scene2DManager::stopAndClean()
+{
+ if (m_sharedObject->isInitialized()) {
+ QMutexLocker lock(&m_sharedObject->m_mutex);
+ m_sharedObject->requestQuit();
+ m_sharedObject->wait();
+ m_sharedObject->cleanup();
+ if (m_ownEngine) {
+ QObject::disconnect(m_connection);
+ delete m_qmlEngine;
+ }
+ delete m_qmlComponent;
+ m_qmlEngine = nullptr;
+ m_qmlComponent = nullptr;
+ }
+}
+
+void Scene2DManager::run()
+{
+ disconnect(m_qmlComponent, &QQmlComponent::statusChanged, this, &Scene2DManager::run);
+
+ if (m_qmlComponent->isError()) {
+ QList<QQmlError> errorList = m_qmlComponent->errors();
+ for (const QQmlError &error: errorList)
+ qWarning() << error.url() << error.line() << error;
+ return;
+ }
+
+ QObject *rootObject = m_qmlComponent->create();
+ if (m_qmlComponent->isError()) {
+ QList<QQmlError> errorList = m_qmlComponent->errors();
+ for (const QQmlError &error: errorList)
+ qWarning() << error.url() << error.line() << error;
+ return;
+ }
+
+ m_rootItem = qobject_cast<QQuickItem *>(rootObject);
+ if (!m_rootItem) {
+ qWarning("QScene2D: Root item is not a QQuickItem.");
+ delete rootObject;
+ return;
+ }
+
+ // The root item is ready. Associate it with the window.
+ m_rootItem->setParentItem(m_sharedObject->m_quickWindow->contentItem());
+
+ // Update window size.
+ updateSizes();
+
+ m_initialized = true;
+ m_sharedObject->setInitialized();
+
+ emit onLoadedChanged();
+}
+
+void Scene2DManager::updateSizes()
+{
+ const int width = m_rootItem->width();
+ const int height = m_rootItem->height();
+ if (width == 0 || height == 0) {
+ qWarning() << "QScene2D: Root item size not set.";
+ return;
+ }
+ m_sharedObject->m_quickWindow->setGeometry(0, 0, width, height);
+}
+
+void Scene2DManager::setSource(const QUrl &url)
+{
+ m_source = url;
+ startIfInitialized();
+}
+
+void Scene2DManager::setItem(QQuickItem *item)
+{
+ m_noSourceMode = true;
+ m_item = item;
+ startIfInitialized();
+}
+
+bool Scene2DManager::event(QEvent *e)
+{
+ switch (e->type()) {
+
+ case RENDER: {
+ // just render request, don't need to call sync in render thread
+ QMutexLocker lock(&m_sharedObject->m_mutex);
+ m_sharedObject->requestRender(false);
+ m_requested = false;
+ return true;
+ }
+
+ case RENDERSYNC: {
+ // sync and render request, main and render threads must be synchronized
+ if (!m_sharedObject->isQuit())
+ doRenderSync();
+ m_requested = false;
+ return true;
+ }
+
+ case PREPARE: {
+ m_sharedObject->m_renderControl->prepareThread(m_sharedObject->m_renderThread);
+ m_sharedObject->setPrepared();
+
+ if (m_renderSyncRequested) {
+ if (!m_requested) {
+ m_requested = true;
+ QCoreApplication::postEvent(this, new QEvent(RENDERSYNC));
+ }
+ m_renderSyncRequested = false;
+ }
+ return true;
+ }
+
+ case INITIALIZED: {
+ // backend is initialized, start the qml
+ m_backendInitialized = true;
+ startIfInitialized();
+ return true;
+ }
+
+ case RENDERED: {
+ // render is done, excellent, now clean anything not needed anymore.
+ stopAndClean();
+ return true;
+ }
+
+ default:
+ break;
+ }
+ return QObject::event(e);
+}
+
+bool Scene2DManager::forwardEvent(QEvent *event)
+{
+ switch (event->type()) {
+
+ case QEvent::MouseMove:
+ case QEvent::MouseButtonDblClick:
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease: {
+ QMouseEvent* me = static_cast<QMouseEvent *>(event);
+ QPointF pos = me->localPos();
+ pos = QPointF(pos.x() * m_rootItem->width(), pos.y() * m_rootItem->height());
+ QMouseEvent nme = QMouseEvent(me->type(), pos, pos, pos, me->button(), me->buttons(),
+ me->modifiers(), Qt::MouseEventSynthesizedByApplication);
+ QCoreApplication::sendEvent(m_sharedObject->m_quickWindow, &nme);
+ } break;
+
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease: {
+ QCoreApplication::sendEvent(m_sharedObject->m_quickWindow, event);
+ } break;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+void Scene2DManager::doRenderSync()
+{
+ QMutexLocker lock(&m_sharedObject->m_mutex);
+
+ m_sharedObject->requestRender(true);
+ m_sharedObject->m_renderControl->polishItems();
+
+ // begin waiting render thread
+ m_sharedObject->wait();
+ m_requested = false;
+}
+
+void Scene2DManager::cleanup()
+{
+ stopAndClean();
+}
+
+void Scene2DManager::setEngine(QQmlEngine *engine)
+{
+ m_qmlEngine = engine;
+ m_ownEngine = false;
+ if (engine) {
+ m_connection = QObject::connect(engine, &QObject::destroyed,
+ this, &Scene2DManager::engineDestroyed);
+ }
+}
+
+void Scene2DManager::engineDestroyed()
+{
+ QObject::disconnect(m_connection);
+ m_qmlEngine = nullptr;
+ m_ownEngine = false;
+}
+
+} // namespace Quick
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/quick3d/quick3dscene2d/items/scene2dmanager_p.h b/src/quick3d/quick3dscene2d/items/scene2dmanager_p.h
new file mode 100644
index 000000000..4b3eeceec
--- /dev/null
+++ b/src/quick3d/quick3dscene2d/items/scene2dmanager_p.h
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_QUICK3DRENDER_SCENE2DMANAGER_P_H
+#define QT3DRENDER_QUICK3DRENDER_SCENE2DMANAGER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <Qt3DQuickScene2D/qt3dquickscene2d_global.h>
+#include <Qt3DQuickScene2D/qscene2d.h>
+
+#include <QtQml/QQmlEngine>
+#include <QtQml/QQmlComponent>
+#include <QtQuick/QQuickItem>
+
+#include <private/qnode_p.h>
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Quick {
+
+class QScene2DPrivate;
+class Scene2DSharedObject;
+
+class Scene2DManager : public QObject
+{
+ Q_OBJECT
+public:
+ Scene2DManager(QScene2DPrivate *priv);
+ ~Scene2DManager();
+
+ QQmlEngine *m_qmlEngine;
+ QQmlComponent *m_qmlComponent;
+ QQuickItem *m_rootItem;
+ QQuickItem *m_item;
+
+ QScene2DPrivate *m_priv;
+ QSharedPointer<Scene2DSharedObject> m_sharedObject;
+
+ QUrl m_source;
+ Qt3DCore::QNodeId m_id;
+ QMetaObject::Connection m_connection;
+ QScene2D::RenderPolicy m_renderPolicy;
+
+ bool m_requested;
+ bool m_initialized;
+ bool m_renderSyncRequested;
+ bool m_backendInitialized;
+ bool m_noSourceMode;
+ bool m_ownEngine;
+
+ void requestRender();
+ void requestRenderSync();
+ void doRenderSync();
+ void startIfInitialized();
+ void stopAndClean();
+ void run();
+ void updateSizes();
+
+ void setSource(const QUrl &url);
+ void setItem(QQuickItem *item);
+
+ bool event(QEvent *e) Q_DECL_OVERRIDE;
+ bool forwardEvent(QEvent *event);
+
+ Q_SIGNAL void onLoadedChanged();
+
+ void cleanup();
+ void setEngine(QQmlEngine *engine);
+ void engineDestroyed();
+};
+
+} // namespace Quick
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QUICK3DRENDER_SCENE2DMANAGER_P_H
diff --git a/src/quick3d/quick3dscene2d/items/scene2dsharedobject.cpp b/src/quick3d/quick3dscene2d/items/scene2dsharedobject.cpp
new file mode 100644
index 000000000..5e91d9a11
--- /dev/null
+++ b/src/quick3d/quick3dscene2d/items/scene2dsharedobject.cpp
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qscene2d.h"
+#include "qscene2d_p.h"
+#include "scene2d_p.h"
+#include "scene2dmanager_p.h"
+#include "scene2dsharedobject_p.h"
+
+#include <Qt3DCore/QPropertyUpdatedChange>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt3DCore;
+
+namespace Qt3DRender {
+
+namespace Quick {
+
+
+/*!
+ \internal
+ Constructs object shared by the front-end and back-end to synchronize the rendering.
+ */
+Scene2DSharedObject::Scene2DSharedObject(Scene2DManager *manager)
+ : m_quit(false)
+ , m_requestSync(false)
+ , m_prepared(false)
+ , m_initialized(false)
+ , m_renderControl(nullptr)
+ , m_quickWindow(nullptr)
+ , m_renderManager(manager)
+ , m_surface(nullptr)
+ , m_renderObject(nullptr)
+ , m_disallowed(false)
+{
+}
+
+Scene2DSharedObject::~Scene2DSharedObject()
+{
+}
+
+void Scene2DSharedObject::cleanup()
+{
+ delete m_renderControl;
+ delete m_quickWindow;
+ delete m_surface;
+ m_renderControl = nullptr;
+ m_quickWindow = nullptr;
+ m_surface = nullptr;
+ m_initialized = false;
+}
+
+bool Scene2DSharedObject::canRender() const
+{
+ return m_initialized && m_prepared && !m_disallowed;
+}
+
+bool Scene2DSharedObject::isInitialized() const
+{
+ return m_initialized;
+}
+
+void Scene2DSharedObject::disallowRender()
+{
+ m_disallowed = true;
+}
+
+void Scene2DSharedObject::setInitialized()
+{
+ m_initialized = true;
+}
+
+bool Scene2DSharedObject::isPrepared() const
+{
+ return m_prepared;
+}
+
+void Scene2DSharedObject::setPrepared()
+{
+ m_prepared = true;
+}
+
+// not protected, call only from main thread
+bool Scene2DSharedObject::isQuit() const
+{
+ Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread());
+ return m_quit;
+}
+
+// not protected, call only from main thread
+void Scene2DSharedObject::requestQuit()
+{
+ Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread());
+ m_quit = true;
+ QCoreApplication::postEvent(m_renderObject, new QEvent(QUIT));
+}
+
+bool Scene2DSharedObject::isSyncRequested() const
+{
+ return m_requestSync;
+}
+
+void Scene2DSharedObject::requestRender(bool sync)
+{
+ m_requestSync = sync;
+ QCoreApplication::postEvent(m_renderObject, new QEvent(RENDER));
+}
+
+void Scene2DSharedObject::wait()
+{
+ m_cond.wait(&m_mutex);
+}
+
+void Scene2DSharedObject::wake()
+{
+ m_cond.wakeOne();
+}
+
+void Scene2DSharedObject::clearSyncRequest()
+{
+ m_requestSync = false;
+}
+
+} // namespace Quick
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/quick3d/quick3dscene2d/items/scene2dsharedobject_p.h b/src/quick3d/quick3dscene2d/items/scene2dsharedobject_p.h
new file mode 100644
index 000000000..bac6fb555
--- /dev/null
+++ b/src/quick3d/quick3dscene2d/items/scene2dsharedobject_p.h
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_QUICK3DRENDER_SCENE2DSHAREDOBJECT_P_H
+#define QT3DRENDER_QUICK3DRENDER_SCENE2DSHAREDOBJECT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <Qt3DQuickScene2D/qt3dquickscene2d_global.h>
+#include <Qt3DQuickScene2D/qscene2d.h>
+
+#include <QtQuick/QQuickWindow>
+#include <QtQuick/QQuickRenderControl>
+#include <QtGui/QOffscreenSurface>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QWaitCondition>
+#include <QtCore/QThread>
+
+#include <private/qnode_p.h>
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Quick {
+
+class Scene2DManager;
+
+class Q_AUTOTEST_EXPORT Scene2DSharedObject
+{
+public:
+ Scene2DSharedObject(Scene2DManager *manager);
+ ~Scene2DSharedObject();
+
+ QQuickRenderControl *m_renderControl;
+ QQuickWindow *m_quickWindow;
+ Scene2DManager *m_renderManager;
+ QOffscreenSurface *m_surface;
+
+ QThread *m_renderThread;
+ QObject *m_renderObject;
+
+ QWaitCondition m_cond;
+ QMutex m_mutex;
+
+ bool isInitialized() const;
+ void setInitialized();
+
+ void requestQuit();
+ bool isQuit() const;
+
+ void requestRender(bool sync);
+
+ bool isSyncRequested() const;
+ void clearSyncRequest();
+
+ void wait();
+ void wake();
+
+ bool isPrepared() const;
+ void setPrepared();
+
+ void disallowRender();
+ bool canRender() const;
+
+ void cleanup();
+
+private:
+
+ bool m_disallowed;
+ bool m_quit;
+ bool m_requestSync;
+ bool m_requestRender;
+ bool m_prepared;
+ bool m_initialized;
+};
+
+typedef QSharedPointer<Scene2DSharedObject> Scene2DSharedObjectPtr;
+
+} // namespace Quick
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(Qt3DRender::Quick::Scene2DSharedObjectPtr)
+
+#endif // QT3DRENDER_QUICK3DRENDER_SCENE2DSHAREDOBJECT_P_H