/**************************************************************************** ** ** 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 "scene2devent_p.h" 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) 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_rootItem(nullptr) , m_item(nullptr) , m_priv(priv) , m_sharedObject(new Scene2DSharedObject(this)) , m_renderPolicy(QScene2D::Continuous) , m_requested(false) , m_initialized(false) , m_renderSyncRequested(false) , m_backendInitialized(false) , m_mouseEnabled(true) { 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(true); m_sharedObject->m_quickWindow->setColor(Qt::transparent); 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 Scene2DEvent(Scene2DEvent::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 Scene2DEvent(Scene2DEvent::RenderSync)); } } else { m_renderSyncRequested = true; } } void Scene2DManager::startIfInitialized() { if (!m_initialized && m_backendInitialized && 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(); // Request render if we have already been requested and preparation has already been done if (m_sharedObject->isPrepared() && m_renderSyncRequested) { if (!m_requested) { m_requested = true; QCoreApplication::postEvent(this, new Scene2DEvent(Scene2DEvent::RenderSync)); } m_renderSyncRequested = false; } } } void Scene2DManager::stopAndClean() { if (m_sharedObject->isInitialized()) { QMutexLocker lock(&m_sharedObject->m_mutex); m_sharedObject->requestQuit(); m_sharedObject->wait(); m_sharedObject->cleanup(); } } 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::setItem(QQuickItem *item) { m_item = item; startIfInitialized(); } bool Scene2DManager::event(QEvent *e) { switch (static_cast(e->type())) { case Scene2DEvent::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 Scene2DEvent::RenderSync: { // sync and render request, main and render threads must be synchronized if (!m_sharedObject->isQuit()) doRenderSync(); m_requested = false; return true; } case Scene2DEvent::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 Scene2DEvent(Scene2DEvent::RenderSync)); } m_renderSyncRequested = false; } return true; } case Scene2DEvent::Initialized: { // backend is initialized, start the qml m_backendInitialized = true; startIfInitialized(); return true; } case Scene2DEvent::Rendered: { // render is done, excellent, now clean anything not needed anymore. stopAndClean(); return true; } default: break; } return QObject::event(e); } 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(); } } // namespace Quick } // namespace Qt3DRender QT_END_NAMESPACE