diff options
author | Sean Harmer <sean.harmer@kdab.com> | 2017-01-28 15:56:26 +0000 |
---|---|---|
committer | Sean Harmer <sean.harmer@kdab.com> | 2017-01-29 10:17:49 +0000 |
commit | 8ef8c094dd55d198c5601689e0f1cc9fcc14274b (patch) | |
tree | fbdd6c1e35a6f2606286752a98a9018213fdb789 /src | |
parent | 9c5bf588ab310e274fddffb252962e8abfa66bd2 (diff) | |
parent | 2f3cfb7f19911f29e6ea7c0528b26f9263d38121 (diff) |
Merge branch 'wip/qtquickintegration' into dev
Conflicts:
src/quick3d/imports/render/qt3dquick3drenderplugin.cpp
src/render/backend/triangleboundingvolume.cpp
src/render/backend/triangleboundingvolume_p.h
src/render/frontend/qrenderaspect.cpp
src/render/frontend/sphere.cpp
src/render/frontend/sphere_p.h
src/render/jobs/pickboundingvolumejob.cpp
src/render/jobs/pickboundingvolumejob_p.h
src/render/picking/objectpicker.cpp
src/render/raycasting/qcollisionqueryresult_p.h
src/render/render.pro
src/src.pro
tests/auto/render/objectpicker/tst_objectpicker.cpp
tests/auto/render/render.pro
Change-Id: I95717c7855887850d5c90e7ad8f19f1ffb37a545
Diffstat (limited to 'src')
74 files changed, 4030 insertions, 78 deletions
diff --git a/src/core/aspects/qabstractaspect.cpp b/src/core/aspects/qabstractaspect.cpp index c049d3503..8f1afb30e 100644 --- a/src/core/aspects/qabstractaspect.cpp +++ b/src/core/aspects/qabstractaspect.cpp @@ -157,6 +157,12 @@ void QAbstractAspect::registerBackendType(const QMetaObject &obj, const QBackend d->m_backendCreatorFunctors.insert(&obj, functor); } +void QAbstractAspect::unregisterBackendType(const QMetaObject &obj) +{ + Q_D(QAbstractAspect); + d->m_backendCreatorFunctors.remove(&obj); +} + void QAbstractAspectPrivate::sceneNodeAdded(QSceneChangePtr &change) { QNodeCreatedChangeBasePtr creationChange = qSharedPointerCast<QNodeCreatedChangeBase>(change); diff --git a/src/core/aspects/qabstractaspect.h b/src/core/aspects/qabstractaspect.h index 86938d2d2..a4ad68c1d 100644 --- a/src/core/aspects/qabstractaspect.h +++ b/src/core/aspects/qabstractaspect.h @@ -76,6 +76,9 @@ protected: template<class Frontend> void registerBackendType(const QBackendNodeMapperPtr &functor); void registerBackendType(const QMetaObject &, const QBackendNodeMapperPtr &functor); + template<class Frontend> + void unregisterBackendType(); + void unregisterBackendType(const QMetaObject &); private: virtual QVariant executeCommand(const QStringList &args); @@ -99,6 +102,12 @@ void QAbstractAspect::registerBackendType(const QBackendNodeMapperPtr &functor) registerBackendType(Frontend::staticMetaObject, functor); } +template<class Frontend> +void QAbstractAspect::unregisterBackendType() +{ + unregisterBackendType(Frontend::staticMetaObject); +} + } // namespace Qt3DCore QT_END_NAMESPACE diff --git a/src/plugins/renderplugins/renderplugins.pro b/src/plugins/renderplugins/renderplugins.pro new file mode 100644 index 000000000..1bc2f6c6c --- /dev/null +++ b/src/plugins/renderplugins/renderplugins.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS += scene2d diff --git a/src/plugins/renderplugins/scene2d/main.cpp b/src/plugins/renderplugins/scene2d/main.cpp new file mode 100644 index 000000000..00a3db734 --- /dev/null +++ b/src/plugins/renderplugins/scene2d/main.cpp @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "scene2dplugin.h" + +#include <private/qrenderpluginfactoryif_p.h> +#include <private/qrenderplugin_p.h> + +QT_BEGIN_NAMESPACE + +class Scene2DPlugin : public Qt3DRender::Render::QRenderPluginFactoryIf +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QRenderPluginFactoryInterface_iid FILE "scene2dplugin.json") + + Qt3DRender::Render::QRenderPlugin *create(const QString &key, + const QStringList ¶mList) Q_DECL_OVERRIDE + { + Q_UNUSED(key) + Q_UNUSED(paramList) + return new Qt3DRender::Render::Scene2DPlugin(); + } +}; + +QT_END_NAMESPACE + +#include "main.moc" diff --git a/src/plugins/renderplugins/scene2d/scene2d.pro b/src/plugins/renderplugins/scene2d/scene2d.pro new file mode 100644 index 000000000..dbf9c3e36 --- /dev/null +++ b/src/plugins/renderplugins/scene2d/scene2d.pro @@ -0,0 +1,21 @@ +TARGET = scene2d +QT += core-private 3dcore 3dcore-private 3drender 3drender-private 3dextras 3dquickrender 3dquickrender-private + +# Qt3D is free of Q_FOREACH - make sure it stays that way: +DEFINES += QT_NO_FOREACH + +HEADERS += \ + scene2dplugin.h +# scene2dnode_p.h + +SOURCES += \ + main.cpp \ + scene2dplugin.cpp +# scene2dnode.cpp + +DISTFILES += \ + scene2dplugin.json + +PLUGIN_TYPE = renderplugins +PLUGIN_CLASS_NAME = Scene2DPlugin +load(qt_plugin) diff --git a/src/plugins/renderplugins/scene2d/scene2dplugin.cpp b/src/plugins/renderplugins/scene2d/scene2dplugin.cpp new file mode 100644 index 000000000..5621858ea --- /dev/null +++ b/src/plugins/renderplugins/scene2d/scene2dplugin.cpp @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "scene2dplugin.h" + +#include <Qt3DRender/qrenderaspect.h> +#include <Qt3DQuickRender/qscene2d.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Render { + +template <typename Backend> +class Scene2DBackendNodeMapper : public Qt3DCore::QBackendNodeMapper +{ +public: + explicit Scene2DBackendNodeMapper(Render::AbstractRenderer *renderer, + Render::Scene2DNodeManager *manager) + : m_manager(manager) + , m_renderer(renderer) + { + } + + Qt3DCore::QBackendNode *create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const Q_DECL_FINAL + { + Backend *backend = m_manager->getOrCreateResource(change->subjectId()); + backend->setRenderer(m_renderer); + return backend; + } + + Qt3DCore::QBackendNode *get(Qt3DCore::QNodeId id) const Q_DECL_FINAL + { + return m_manager->lookupResource(id); + } + + void destroy(Qt3DCore::QNodeId id) const Q_DECL_FINAL + { + m_manager->releaseResource(id); + } + +private: + Render::Scene2DNodeManager *m_manager; + Render::AbstractRenderer *m_renderer; +}; + +Scene2DPlugin::Scene2DPlugin() + : m_scene2dNodeManager(new Render::Scene2DNodeManager()) +{ + +} + +Scene2DPlugin::~Scene2DPlugin() +{ + delete m_scene2dNodeManager; +} + +bool Scene2DPlugin::registerBackendTypes(QRenderAspect *aspect, + AbstractRenderer *renderer) +{ + registerBackendType(aspect, Qt3DRender::Quick::QScene2D::staticMetaObject, + QSharedPointer<Scene2DBackendNodeMapper<Render::Quick::Scene2D> > + ::create(renderer, m_scene2dNodeManager)); + return true; +} +bool Scene2DPlugin::unregisterBackendTypes(QRenderAspect *aspect) +{ + unregisterBackendType(aspect, Qt3DRender::Quick::QScene2D::staticMetaObject); + return true; +} + +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/plugins/renderplugins/scene2d/scene2dplugin.h b/src/plugins/renderplugins/scene2d/scene2dplugin.h new file mode 100644 index 000000000..f19093c7e --- /dev/null +++ b/src/plugins/renderplugins/scene2d/scene2dplugin.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_SCENE2DPLUGIN_H +#define QT3DRENDER_SCENE2DPLUGIN_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 <private/qrenderaspect_p.h> +#include <private/qrenderplugin_p.h> +#include <private/abstractrenderer_p.h> +#include <private/qresourcemanager_p.h> +#include <private/scene2d_p.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Render { + +class Scene2DNode; + +class Scene2DNodeManager : public Qt3DCore::QResourceManager< + Render::Quick::Scene2D, + Qt3DCore::QNodeId, + 16, + Qt3DCore::ArrayAllocatingPolicy, + Qt3DCore::ObjectLevelLockingPolicy> +{ +}; + +class Scene2DPlugin : public QRenderPlugin +{ +public: + Scene2DPlugin(); + ~Scene2DPlugin(); + bool registerBackendTypes(QRenderAspect *aspect, AbstractRenderer *renderer) Q_DECL_OVERRIDE; + bool unregisterBackendTypes(QRenderAspect *aspect) Q_DECL_OVERRIDE; +private: + Render::Scene2DNodeManager *m_scene2dNodeManager; +}; + +} // Render +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_SCENE2DPLUGIN_H diff --git a/src/plugins/renderplugins/scene2d/scene2dplugin.json b/src/plugins/renderplugins/scene2d/scene2dplugin.json new file mode 100644 index 000000000..2eece1046 --- /dev/null +++ b/src/plugins/renderplugins/scene2d/scene2dplugin.json @@ -0,0 +1,3 @@ +{ + "Keys": ["scene2d"] +} diff --git a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp index c6831dbce..bb0ac249c 100644 --- a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp +++ b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp @@ -103,8 +103,11 @@ #include <Qt3DRender/qcamera.h> #include <Qt3DRender/qrendersettings.h> #include <Qt3DRender/qpickingsettings.h> +#include <Qt3DRender/qeventforward.h> #include <Qt3DRender/qrendercapture.h> #include <Qt3DRender/qmemorybarrier.h> + +#include <Qt3DQuickRender/qscene2d.h> #include <Qt3DQuickRender/private/quick3dlayerfilter_p.h> #include <Qt3DQuickRender/private/quick3dtechnique_p.h> #include <Qt3DQuickRender/private/quick3dmaterial_p.h> @@ -205,6 +208,7 @@ void Qt3DQuick3DRenderPlugin::registerTypes(const char *uri) // Picking qmlRegisterType<Qt3DRender::QObjectPicker>(uri, 2, 0, "ObjectPicker"); + qmlRegisterType<Qt3DRender::QEventForward>(uri, 2, 2, "EventForward"); qmlRegisterUncreatableType<Qt3DRender::QPickEvent>(uri, 2, 0, "PickEvent", QStringLiteral("Events cannot be created")); // Compute Job @@ -269,6 +273,9 @@ void Qt3DQuick3DRenderPlugin::registerTypes(const char *uri) qmlRegisterType<Qt3DRender::QSeamlessCubemap>(uri, 2, 0, "SeamlessCubemap"); qmlRegisterType<Qt3DRender::QStencilOperation>(uri, 2, 0, "StencilOperation"); qmlRegisterType<Qt3DRender::QStencilMask>(uri, 2, 0, "StencilMask"); + + // Scene2D + Qt3DRender::Quick::registerType<Qt3DRender::Quick::QScene2D>("QScene2D", "Qt3D.Render/Scene2D", uri, 2, 2, "Scene2D"); } QT_END_NAMESPACE diff --git a/src/quick3d/quick3drender/qt3dquickrender_logging.cpp b/src/quick3d/quick3drender/qt3dquickrender_logging.cpp new file mode 100644 index 000000000..b9e5d2e08 --- /dev/null +++ b/src/quick3d/quick3drender/qt3dquickrender_logging.cpp @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** 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 "qt3dquickrender_logging_p.h" + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Quick { + +Q_LOGGING_CATEGORY(Scene2D, "Qt3D.Scene2D") + +} // Quick +} // Qt3DRender + +QT_END_NAMESPACE diff --git a/src/quick3d/quick3drender/qt3dquickrender_logging_p.h b/src/quick3d/quick3drender/qt3dquickrender_logging_p.h new file mode 100644 index 000000000..c34abfdd3 --- /dev/null +++ b/src/quick3d/quick3drender/qt3dquickrender_logging_p.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** 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 QT3DQUICKRENDER_LOGGING_P_H +#define QT3DQUICKRENDER_LOGGING_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QLoggingCategory> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Quick { + +Q_DECLARE_LOGGING_CATEGORY(Scene2D) + +} // Quick +} // Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DQUICKRENDER_LOGGING_P_H diff --git a/src/quick3d/quick3drender/quick3drender.pro b/src/quick3d/quick3drender/quick3drender.pro index 88d7a9556..b1b904e12 100644 --- a/src/quick3d/quick3drender/quick3drender.pro +++ b/src/quick3d/quick3drender/quick3drender.pro @@ -14,16 +14,19 @@ gcov { SOURCES += \ qt3dquickrender_global.cpp \ - qt3dquickrendernodefactory.cpp + qt3dquickrendernodefactory.cpp \ + qt3dquickrender_logging.cpp HEADERS += \ qt3dquickrendernodefactory_p.h \ qt3dquickrender_global_p.h \ - qt3dquickrender_global.h + qt3dquickrender_global.h \ + qt3dquickrender_logging_p.h # otherwise mingw headers do not declare common functions like ::strcasecmp win32-g++*:QMAKE_CXXFLAGS_CXX11 = -std=gnu++0x include(./items/items.pri) +include(./scene2d/scene2d.pri) load(qt_module) diff --git a/src/quick3d/quick3drender/scene2d/qscene2d.cpp b/src/quick3d/quick3drender/scene2d/qscene2d.cpp new file mode 100644 index 000000000..fa46cd3d2 --- /dev/null +++ b/src/quick3d/quick3drender/scene2d/qscene2d.cpp @@ -0,0 +1,697 @@ +/**************************************************************************** +** +** 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 <Qt3DCore/QPropertyUpdatedChange> + +#include <QtGui/QOpenGLContext> + +QT_BEGIN_NAMESPACE + +using namespace Qt3DCore; + +namespace Qt3DRender { + +namespace Quick { + +/*! + \class Qt3DRender::QScene2D + \inmodule Qt3DRender + + \brief This class enables rendering qml into a texture, which then can be + used as a part of 3D scene. + + The component uses QQuickRenderControl to render the given QML source into an + offscreen surface, which is attached to a texture provided by the user. This allows the + component to directly render into the texture without intermediate copy and the user to + freely specify how the texture is used in the 3D scene. + + \since 5.9 +*/ + +/*! + \qmltype Scene2D + \inqmlmodule Qt3D.Render + \since + \ingroup + \instantiates Qt3DRender::QScene2D + \brief Scene2D + */ + +/*! + \enum QScene2D::RenderPolicy + + This enum type describes types of render policies available. + \value Continuous The Scene2D is rendering continuously. This is the default render policy. + \value SingleShot The Scene2D renders to the texture only once after which the resources + allocated for rendering are released. +*/ + +/*! + \qmlproperty RenderTargetOutput Qt3D.Render::Scene2D::output + Holds the RenderTargetOutput, which specifies where the Scene2D is rendering to. + */ + +/*! + \qmlproperty QUrl Qt3D.Render::Scene2D::source + Holds the qml source url. + */ + +/*! + \qmlproperty enumeration Qt3D.Render::Scene2D::renderPolicy + Holds the render policy of this Scene2D. + */ + +/*! + \qmlproperty bool Qt3D.Render::Scene2D::loaded + 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() + , m_renderManager(new Scene2DManager(this)) + , m_output(nullptr) +{ +} + +QScene2DPrivate::~QScene2DPrivate() +{ + m_renderManager->cleanup(); + delete m_renderManager; +} + + +/*! + The constructor creates a new QScene2D instance with the specified \a parent. + */ +QScene2D::QScene2D(Qt3DCore::QNode *parent) + : Qt3DCore::QNode(*new QScene2DPrivate, parent) +{ + Q_D(QScene2D); + connect(d->m_renderManager, &Scene2DManager::onLoadedChanged, + this, &QScene2D::sourceLoaded); +} + +QScene2D::QScene2D(QQmlEngine *engine, Qt3DCore::QNode *parent) + : Qt3DCore::QNode(*new QScene2DPrivate, parent) +{ + Q_D(QScene2D); + connect(d->m_renderManager, &Scene2DManager::onLoadedChanged, + this, &QScene2D::sourceLoaded); + d->m_renderManager->setEngine(engine); +} + +QScene2D::~QScene2D() +{ +} + +bool QScene2D::loaded() const +{ + Q_D(const QScene2D); + return d->m_renderManager->m_initialized; +} + +/*! + \property QScene2D::source + \brief Specifies the url for the qml. + + This property specifies the url to the qml being rendered to the texture. + The source must specify QQuickItem as a root. The item must specify width + and height. The rendered qml is scaled to the texture size. + The property can not be changed after the rendering has been initialized. + */ +QUrl QScene2D::source() const +{ + Q_D(const QScene2D); + return d->m_renderManager->m_source; +} + +void QScene2D::setSource(const QUrl &url) +{ + Q_D(QScene2D); + if (d->m_renderManager->m_initialized) { + qWarning() << "Unable to set source after initialization."; + return; + } + if (d->m_renderManager->m_source != url) { + d->m_renderManager->setSource(url); + emit sourceChanged(url); + } +} + +QQuickItem* QScene2D::item() const +{ + Q_D(const QScene2D); + return d->m_renderManager->m_item; +} + +void QScene2D::setItem(QQuickItem *item) +{ + Q_D(QScene2D); + if (d->m_renderManager->m_initialized) { + qWarning() << "Unable to set item after initialization."; + return; + } + if (d->m_renderManager->m_item != item) { + d->m_renderManager->setItem(item); + emit itemChanged(item); + } +} + +/*! + \property QScene2D::renderPolicy + + Holds the render policy of this Scene2D. + */ +QScene2D::RenderPolicy QScene2D::renderPolicy() const +{ + Q_D(const QScene2D); + return d->m_renderManager->m_renderPolicy; +} + +void QScene2D::setRenderPolicy(QScene2D::RenderPolicy renderPolicy) +{ + Q_D(const QScene2D); + if (d->m_renderManager->m_renderPolicy != renderPolicy) { + d->m_renderManager->m_renderPolicy = renderPolicy; + emit renderPolicyChanged(renderPolicy); + } +} + +/*! + \property QScene2D::output + Holds the QRenderTargetOutput, which specifies where the QScene2D is + rendering to. + */ +Qt3DRender::QRenderTargetOutput *QScene2D::output() const +{ + Q_D(const QScene2D); + return d->m_output; +} + +void QScene2D::setOutput(Qt3DRender::QRenderTargetOutput *output) +{ + Q_D(QScene2D); + if (d->m_output != output) { + if (d->m_output) + d->unregisterDestructionHelper(d->m_output); + d->m_output = output; + if (output) + d->registerDestructionHelper(output, &QScene2D::setOutput, d->m_output); + emit outputChanged(output); + } +} + +Qt3DCore::QNodeCreatedChangeBasePtr QScene2D::createNodeCreationChange() const +{ + auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QScene2DData>::create(this); + auto &data = creationChange->data; + Q_D(const QScene2D); + data.renderPolicy = d->m_renderManager->m_renderPolicy; + data.sharedObject = d->m_renderManager->m_sharedObject; + data.output = d->m_output ? d->m_output->id() : Qt3DCore::QNodeId(); + return creationChange; +} + +bool QScene2D::event(QEvent *event) +{ + Q_D(QScene2D); + d->m_renderManager->forwardEvent(event); + return true; +} + +/*! + Returns the qml engine used by the QScene2D. + */ +QQmlEngine *QScene2D::engine() const +{ + Q_D(const QScene2D); + return d->m_renderManager->m_qmlEngine; +} + +/*! + \internal + */ +void QScene2D::sourceLoaded() +{ + emit loadedChanged(true); +} + +} // namespace Quick +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/quick3d/quick3drender/scene2d/qscene2d.h b/src/quick3d/quick3drender/scene2d/qscene2d.h new file mode 100644 index 000000000..0a7e943d6 --- /dev/null +++ b/src/quick3d/quick3drender/scene2d/qscene2d.h @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** 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_QSCENE2D_H +#define QT3DRENDER_QUICK3DRENDER_QSCENE2D_H + +#include <Qt3DQuickRender/qt3dquickrender_global.h> +#include <Qt3DRender/qrendertargetoutput.h> + +#include <QtCore/QUrl> +#include <QtCore/QEvent> + +#include <Qt3DCore/qnode.h> + +#include <QtQuick/qquickitem.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Quick { + +class QScene2DPrivate; + +class QT3DQUICKRENDERSHARED_EXPORT QScene2D : public Qt3DCore::QNode +{ + Q_OBJECT + + Q_PROPERTY(Qt3DRender::QRenderTargetOutput *output READ output WRITE setOutput NOTIFY outputChanged) + Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(QScene2D::RenderPolicy renderPolicy READ renderPolicy WRITE setRenderPolicy NOTIFY renderPolicyChanged) + Q_PROPERTY(bool loaded READ loaded NOTIFY loadedChanged) + Q_PROPERTY(QQuickItem *item READ item WRITE setItem NOTIFY itemChanged) + + Q_CLASSINFO("DefaultProperty", "item") + +public: + + enum RenderPolicy { + Continuous, + SingleShot + }; + Q_ENUM(RenderPolicy) + + explicit QScene2D(Qt3DCore::QNode *parent = nullptr); + QScene2D(QQmlEngine *engine, Qt3DCore::QNode *parent = nullptr); + ~QScene2D(); + + Qt3DRender::QRenderTargetOutput *output() const; + QUrl source() const; + bool loaded() const; + QScene2D::RenderPolicy renderPolicy() const; + QQuickItem *item() const; + QQmlEngine *engine() const; + bool event(QEvent *event) Q_DECL_OVERRIDE; + +public Q_SLOTS: + void setOutput(Qt3DRender::QRenderTargetOutput *output); + void setSource(const QUrl &url); + void setRenderPolicy(QScene2D::RenderPolicy policy); + void setItem(QQuickItem *item); + +Q_SIGNALS: + void outputChanged(Qt3DRender::QRenderTargetOutput *output); + void sourceChanged(const QUrl &url); + void loadedChanged(bool loaded); + void renderPolicyChanged(QScene2D::RenderPolicy policy); + void itemChanged(QQuickItem *item); + +protected: + Q_DECLARE_PRIVATE(QScene2D) + +private: + Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE; + + void sourceLoaded(); +}; + +} // namespace Quick +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_QUICK3DRENDER_QSCENE2D_H diff --git a/src/quick3d/quick3drender/scene2d/qscene2d_p.h b/src/quick3d/quick3drender/scene2d/qscene2d_p.h new file mode 100644 index 000000000..34b54b231 --- /dev/null +++ b/src/quick3d/quick3drender/scene2d/qscene2d_p.h @@ -0,0 +1,219 @@ +/**************************************************************************** +** +** 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_QSCENE2D_P_H +#define QT3DRENDER_QUICK3DRENDER_QSCENE2D_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 <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 <Qt3DQuickRender/qscene2d.h> +#include <Qt3DRender/qabstracttexture.h> + +#include <private/qobject_p.h> +#include <private/qnode_p.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Quick { + +class QScene2D; +class Scene2DManager; + +// render thread -> render thread +static const QEvent::Type INITIALIZE = QEvent::Type(QEvent::User + 1); + +// main thread -> main thread, render thread +static const QEvent::Type RENDER = QEvent::Type(QEvent::User + 2); + +// main thread -> main thread +static const QEvent::Type RENDERSYNC = QEvent::Type(QEvent::User + 3); + +// render thread -> main thread +static const QEvent::Type PREPARE = QEvent::Type(QEvent::User + 4); +static const QEvent::Type INITIALIZED = QEvent::Type(QEvent::User + 5); +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 +{ +public: + Q_DECLARE_PUBLIC(QScene2D) + + QScene2DPrivate(); + ~QScene2DPrivate(); + + Scene2DManager *m_renderManager; + QMetaObject::Connection m_textureDestroyedConnection; + Qt3DRender::QRenderTargetOutput *m_output; +}; + +struct QScene2DData +{ + QScene2D::RenderPolicy renderPolicy; + Scene2DSharedObjectPtr sharedObject; + 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_QUICK3DRENDER_QSCENE2D_P_H diff --git a/src/quick3d/quick3drender/scene2d/scene2d.cpp b/src/quick3d/quick3drender/scene2d/scene2d.cpp new file mode 100644 index 000000000..227829f3e --- /dev/null +++ b/src/quick3d/quick3drender/scene2d/scene2d.cpp @@ -0,0 +1,363 @@ +/**************************************************************************** +** +** 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 <Qt3DCore/qpropertyupdatedchange.h> +#include <Qt3DQuickRender/qscene2d.h> + +#include <QtCore/qthread.h> +#include <QtCore/qatomic.h> + +#include <private/qscene2d_p.h> +#include <private/scene2d_p.h> +#include <private/graphicscontext_p.h> +#include <private/texture_p.h> +#include <private/nodemanagers_p.h> +#include <private/resourceaccessor_p.h> +#include <private/attachmentpack_p.h> +#include <private/qt3dquickrender_logging_p.h> + +QT_BEGIN_NAMESPACE + +#ifndef GL_DEPTH24_STENCIL8 +#define GL_DEPTH24_STENCIL8 0x88F0 +#endif + +using namespace Qt3DRender::Quick; + +namespace Qt3DRender { + +namespace Render { + +namespace Quick { + +Q_GLOBAL_STATIC(QThread, renderThread) +Q_GLOBAL_STATIC(QAtomicInt, renderThreadClientCount) + +#ifndef GL_DEPTH24_STENCIL8 +#define GL_DEPTH24_STENCIL8 0x88F0 +#endif + +RenderQmlEventHandler::RenderQmlEventHandler(Scene2D *node) + : QObject() + , m_node(node) +{ +} + +// Event handler for the RenderQmlToTexture::renderThread +bool RenderQmlEventHandler::event(QEvent *e) +{ + switch (e->type()) { + + case RENDER: { + m_node->render(); + return true; + } + + case INITIALIZE: { + m_node->initializeRender(); + return true; + } + + case QUIT: { + m_node->cleanup(); + return true; + } + + default: + break; + } + return QObject::event(e); +} + +Scene2D::Scene2D() + : m_context(nullptr) + , m_shareContext(nullptr) + , m_sharedObject(nullptr) + , m_renderThread(nullptr) + , m_initialized(false) + , m_renderInitialized(false) + , m_renderPolicy(Qt3DRender::Quick::QScene2D::Continuous) + , m_fbo(0) + , m_rbo(0) +{ + renderThreadClientCount->fetchAndAddAcquire(1); +} + +Scene2D::~Scene2D() +{ + // this gets called from aspect thread. Wait for the render thread then delete it. + // TODO: render thread deletion +// if (m_renderThread) { +// m_renderThread->wait(1000); +// delete m_renderThread; +// } +} + +void Scene2D::setOutput(Qt3DCore::QNodeId outputId) +{ + m_outputId = outputId; +} + +void Scene2D::initializeSharedObject() +{ + if (!m_initialized) { + + renderThread->setObjectName(QStringLiteral("Scene2D::renderThread")); + m_renderThread = renderThread; + m_sharedObject->m_renderThread = m_renderThread; + + // Create event handler for the render thread + m_sharedObject->m_renderObject = new RenderQmlEventHandler(this); + m_sharedObject->m_renderObject->moveToThread(m_sharedObject->m_renderThread); + if (!m_sharedObject->m_renderThread->isRunning()) + m_sharedObject->m_renderThread->start(); + + // Notify main thread we have been initialized + if (m_sharedObject->m_renderManager) + QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(INITIALIZED)); + + // Initialize render thread + QCoreApplication::postEvent(m_sharedObject->m_renderObject, new QEvent(INITIALIZE)); + + m_initialized = true; + } +} + +void Scene2D::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) +{ + const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QScene2DData>>(change); + const auto &data = typedChange->data; + m_renderPolicy = data.renderPolicy; + setSharedObject(data.sharedObject); + setOutput(data.output); + m_shareContext = renderer()->shareContext(); +} + +void Scene2D::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) +{ + if (e->type() == Qt3DCore::PropertyUpdated) { + Qt3DCore::QPropertyUpdatedChangePtr propertyChange + = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(e); + if (propertyChange->propertyName() == QByteArrayLiteral("renderPolicy")) { + m_renderPolicy = propertyChange->value().value<QScene2D::RenderPolicy>(); + } else if (propertyChange->propertyName() == QByteArrayLiteral("output")) { + Qt3DCore::QNodeId outputId = propertyChange->value().value<Qt3DCore::QNodeId>(); + setOutput(outputId); + } else if (propertyChange->propertyName() == QByteArrayLiteral("sharedObject")) { + const Scene2DSharedObjectPtr sharedObject + = propertyChange->value().value<Scene2DSharedObjectPtr>(); + setSharedObject(sharedObject); + } + } + BackendNode::sceneChangeEvent(e); +} + +void Scene2D::setSharedObject(Qt3DRender::Quick::Scene2DSharedObjectPtr sharedObject) +{ + m_sharedObject = sharedObject; + if (!m_initialized) + initializeSharedObject(); +} + +void Scene2D::initializeRender() +{ + if (!m_renderInitialized && m_sharedObject.data() != nullptr) { + + QSurfaceFormat format; + format.setDepthBufferSize(24); + format.setStencilBufferSize(8); + + m_context = new QOpenGLContext(); + m_context->setFormat(format); + m_context->setShareContext(m_shareContext); + m_context->create(); + + m_context->makeCurrent(m_sharedObject->m_surface); + m_sharedObject->m_renderControl->initialize(m_context); + m_context->doneCurrent(); + + QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(PREPARE)); + m_renderInitialized = true; + } +} + +bool Scene2D::updateFbo(QOpenGLTexture *texture) +{ + QOpenGLFunctions *gl = m_context->functions(); + if (m_fbo == 0) { + gl->glGenFramebuffers(1, &m_fbo); + gl->glGenRenderbuffers(1, &m_rbo); + } + // TODO: Add another codepath when GL_DEPTH24_STENCIL8 is not supported + gl->glBindRenderbuffer(GL_RENDERBUFFER, m_rbo); + gl->glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, + m_textureSize.width(), m_textureSize.height()); + gl->glBindRenderbuffer(GL_RENDERBUFFER, 0); + + gl->glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); + gl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, texture->textureId(), 0); + gl->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_rbo); + GLenum status = gl->glCheckFramebufferStatus(GL_FRAMEBUFFER); + gl->glBindFramebuffer(GL_FRAMEBUFFER, 0); + + if (status != GL_FRAMEBUFFER_COMPLETE) + return false; + return true; +} + +void Scene2D::syncRenderControl() +{ + if (m_sharedObject->isSyncRequested()) { + + m_sharedObject->clearSyncRequest(); + + m_sharedObject->m_renderControl->sync(); + + // gui thread can now continue + m_sharedObject->wake(); + } +} + +void Scene2D::render() +{ + if (m_initialized && m_renderInitialized && m_sharedObject.data() != nullptr) { + + QMutexLocker lock(&m_sharedObject->m_mutex); + + QOpenGLTexture *texture = nullptr; + const Qt3DRender::Render::Attachment *attachmentData = nullptr; + QMutex *textureLock = nullptr; + + m_context->makeCurrent(m_sharedObject->m_surface); + + if (resourceAccessor()->accessResource(m_outputId, (void**)&attachmentData, nullptr)) { + if (!resourceAccessor()->accessResource(attachmentData->m_textureUuid, + (void**)&texture, &textureLock)) { + // Need to call sync even if the texture is not in use + syncRenderControl(); + m_context->doneCurrent(); + qCWarning(Qt3DRender::Quick::Scene2D) << Q_FUNC_INFO << "Texture not in use."; + QCoreApplication::postEvent(m_sharedObject->m_renderObject, new QEvent(RENDER)); + return; + } + textureLock->lock(); + const QSize textureSize = QSize(texture->width(), texture->height()); + if (m_attachmentData.m_textureUuid != attachmentData->m_textureUuid + || m_attachmentData.m_point != attachmentData->m_point + || m_attachmentData.m_face != attachmentData->m_face + || m_attachmentData.m_layer != attachmentData->m_layer + || m_attachmentData.m_mipLevel != attachmentData->m_mipLevel + || m_textureSize != textureSize) { + m_textureSize = textureSize; + m_attachmentData = *attachmentData; + if (!updateFbo(texture)) { + // Need to call sync even if the fbo is not usable + syncRenderControl(); + textureLock->unlock(); + m_context->doneCurrent(); + qCWarning(Qt3DRender::Quick::Scene2D) << Q_FUNC_INFO << "Fbo not initialized."; + return; + } + } + } + + if (m_fbo != m_sharedObject->m_quickWindow->renderTargetId()) + m_sharedObject->m_quickWindow->setRenderTarget(m_fbo, m_textureSize); + + // Call disallow rendering while mutex is locked + if (m_renderPolicy == QScene2D::SingleShot) + m_sharedObject->disallowRender(); + + // Sync + if (m_sharedObject->isSyncRequested()) { + + m_sharedObject->clearSyncRequest(); + + m_sharedObject->m_renderControl->sync(); + } + + // Render + m_sharedObject->m_renderControl->render(); + + // Tell main thread we are done so it can begin cleanup if this is final frame + if (m_renderPolicy == QScene2D::SingleShot) + QCoreApplication::postEvent(m_sharedObject->m_renderManager, new QEvent(RENDERED)); + + m_sharedObject->m_quickWindow->resetOpenGLState(); + m_context->functions()->glFlush(); + if (texture->isAutoMipMapGenerationEnabled()) + texture->generateMipMaps(); + textureLock->unlock(); + m_context->doneCurrent(); + + // gui thread can now continue + m_sharedObject->wake(); + } +} + +// this function gets called while the main thread is waiting +void Scene2D::cleanup() +{ + if (m_renderInitialized && m_initialized) { + m_context->makeCurrent(m_sharedObject->m_surface); + m_sharedObject->m_renderControl->invalidate(); + m_context->functions()->glDeleteFramebuffers(1, &m_fbo); + m_context->functions()->glDeleteRenderbuffers(1, &m_rbo); + m_context->doneCurrent(); + m_renderInitialized = false; + } + if (m_initialized) { + delete m_sharedObject->m_renderObject; + m_sharedObject->m_renderObject = nullptr; + delete m_context; + m_context = nullptr; + m_initialized = false; + } + // wake up the main thread + m_sharedObject->wake(); + m_sharedObject = nullptr; + + renderThreadClientCount->fetchAndSubAcquire(1); + if (renderThreadClientCount->load() == 0) + renderThread->quit(); +} + +} // namespace Quick +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/quick3d/quick3drender/scene2d/scene2d.pri b/src/quick3d/quick3drender/scene2d/scene2d.pri new file mode 100644 index 000000000..4635c43e1 --- /dev/null +++ b/src/quick3d/quick3drender/scene2d/scene2d.pri @@ -0,0 +1,10 @@ +HEADERS += \ + $$PWD/qscene2d.h \ + $$PWD/qscene2d_p.h \ + $$PWD/scene2d_p.h + +SOURCES += \ + $$PWD/qscene2d.cpp \ + $$PWD/scene2d.cpp + +INCLUDEPATH += $$PWD diff --git a/src/quick3d/quick3drender/scene2d/scene2d_p.h b/src/quick3d/quick3drender/scene2d/scene2d_p.h new file mode 100644 index 000000000..3a8ccf531 --- /dev/null +++ b/src/quick3d/quick3drender/scene2d/scene2d_p.h @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** 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_RENDER_QUICK_SCENE2D_P_H +#define QT3DRENDER_RENDER_QUICK_SCENE2D_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 <Qt3DCore/qnodeid.h> +#include <Qt3DQuickRender/qscene2d.h> + +#include <QtCore/QCoreApplication> +#include <QtCore/QSemaphore> + +#include <private/qscene2d_p.h> +#include <private/qrendertargetoutput_p.h> +#include <private/backendnode_p.h> +#include <private/attachmentpack_p.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +class GraphicsContext; + +namespace Quick { + +class Scene2D; + +class RenderQmlEventHandler : public QObject +{ + Q_OBJECT +public: + RenderQmlEventHandler(Scene2D *node); + bool event(QEvent *e) Q_DECL_OVERRIDE; + +private: + Scene2D *m_node; +}; + +class QT3DQUICKRENDERSHARED_EXPORT Scene2D : public Qt3DRender::Render::BackendNode +{ +public: + Scene2D(); + ~Scene2D(); + + void render(); + void initializeRender(); + void setSharedObject(Qt3DRender::Quick::Scene2DSharedObjectPtr sharedObject); + void cleanup(); + void setOutput(Qt3DCore::QNodeId outputId); + void initializeSharedObject(); + + void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_OVERRIDE; + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; + + bool updateFbo(QOpenGLTexture *texture); + void syncRenderControl(); + + QOpenGLContext *m_context; + QOpenGLContext *m_shareContext; + QThread *m_renderThread; + Qt3DCore::QNodeId m_outputId; + QSharedPointer<Qt3DRender::Quick::Scene2DSharedObject> m_sharedObject; + Qt3DCore::QNodeId m_peerId; + Qt3DRender::Render::Attachment m_attachmentData; + + GLuint m_fbo; + GLuint m_rbo; + QSize m_textureSize; + + bool m_initialized; + bool m_renderInitialized; + Qt3DRender::Quick::QScene2D::RenderPolicy m_renderPolicy; +}; + +} // Quick +} // Render +} // Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_RENDER_QUICK_SCENE2D_P_H diff --git a/src/render/backend/abstractrenderer_p.h b/src/render/backend/abstractrenderer_p.h index 8b17cbf45..f8d9850e7 100644 --- a/src/render/backend/abstractrenderer_p.h +++ b/src/render/backend/abstractrenderer_p.h @@ -56,6 +56,8 @@ #include <Qt3DCore/qnodeid.h> #include <QtGui/qsurfaceformat.h> +#include <QtGui/qopenglcontext.h> + QT_BEGIN_NAMESPACE class QSurface; @@ -153,6 +155,7 @@ public: virtual void setOffscreenSurfaceHelper(OffscreenSurfaceHelper *helper) = 0; virtual QSurfaceFormat format() = 0; + virtual QOpenGLContext *shareContext() const = 0; }; Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractRenderer::BackendNodeDirtySet) diff --git a/src/render/backend/attachmentpack.cpp b/src/render/backend/attachmentpack.cpp index d2bb5ee9a..6dee7587b 100644 --- a/src/render/backend/attachmentpack.cpp +++ b/src/render/backend/attachmentpack.cpp @@ -60,7 +60,7 @@ AttachmentPack::AttachmentPack(const RenderTargetSelector *selector, const Rende for (Qt3DCore::QNodeId outputId : outputIds) { const RenderTargetOutput *output = attachmentManager->lookupResource(outputId); if (output) - m_attachments.append(output->attachment()); + m_attachments.append(*output->attachment()); } // Create actual DrawBuffers list that is used for glDrawBuffers diff --git a/src/render/backend/backendnode.cpp b/src/render/backend/backendnode.cpp index 7054db6a4..0dc8da237 100644 --- a/src/render/backend/backendnode.cpp +++ b/src/render/backend/backendnode.cpp @@ -37,7 +37,10 @@ ** ****************************************************************************/ -#include "backendnode_p.h" +#include <private/backendnode_p.h> +#include <private/renderer_p.h> +#include <private/resourceaccessor_p.h> +#include <private/nodemanagers_p.h> QT_BEGIN_NAMESPACE @@ -61,12 +64,23 @@ void BackendNode::setRenderer(AbstractRenderer *renderer) m_renderer = renderer; } +AbstractRenderer *BackendNode::renderer() const +{ + return m_renderer; +} + void BackendNode::markDirty(AbstractRenderer::BackendNodeDirtySet changes) { Q_ASSERT(m_renderer); m_renderer->markDirty(changes, this); } +QSharedPointer<RenderBackendResourceAccessor> BackendNode::resourceAccessor() +{ + Render::Renderer *r = static_cast<Render::Renderer *>(renderer()); + return r->nodeManagers()->resourceAccessor(); +} + } // namespace Render } // namespace Qt3DRender diff --git a/src/render/backend/backendnode_p.h b/src/render/backend/backendnode_p.h index 5688c2412..8db68b11d 100644 --- a/src/render/backend/backendnode_p.h +++ b/src/render/backend/backendnode_p.h @@ -54,6 +54,7 @@ #include <Qt3DRender/qt3drender_global.h> #include <Qt3DCore/qbackendnode.h> #include <Qt3DRender/private/abstractrenderer_p.h> +#include <private/qt3drender_global_p.h> QT_BEGIN_NAMESPACE @@ -61,13 +62,18 @@ namespace Qt3DRender { namespace Render { -class Q_AUTOTEST_EXPORT BackendNode : public Qt3DCore::QBackendNode +class RenderBackendResourceAccessor; + +class QT3DRENDERSHARED_PRIVATE_EXPORT BackendNode : public Qt3DCore::QBackendNode { public: BackendNode(Qt3DCore::QBackendNode::Mode mode = ReadOnly); ~BackendNode(); void setRenderer(AbstractRenderer *renderer); + AbstractRenderer *renderer() const; + + QSharedPointer<RenderBackendResourceAccessor> resourceAccessor(); protected: void markDirty(AbstractRenderer::BackendNodeDirtySet changes); diff --git a/src/render/backend/managers_p.h b/src/render/backend/managers_p.h index ce6767958..d9e46db45 100644 --- a/src/render/backend/managers_p.h +++ b/src/render/backend/managers_p.h @@ -78,6 +78,7 @@ #include <Qt3DRender/private/openglvertexarrayobject_p.h> #include <Qt3DRender/private/light_p.h> #include <Qt3DRender/private/computecommand_p.h> +#include <Qt3DRender/private/eventforward_p.h> QT_BEGIN_NAMESPACE @@ -359,6 +360,15 @@ class ObjectPickerManager : public Qt3DCore::QResourceManager< { }; +class EventForwardManager : public Qt3DCore::QResourceManager< + EventForward, + Qt3DCore::QNodeId, + 8, + Qt3DCore::ArrayAllocatingPolicy, + Qt3DCore::NonLockingPolicy> +{ +}; + #if 0 class BoundingVolumeDebugManager : public Qt3DCore::QResourceManager< BoundingVolumeDebug, diff --git a/src/render/backend/nodemanagers.cpp b/src/render/backend/nodemanagers.cpp index d83623ce2..f6a3441c2 100644 --- a/src/render/backend/nodemanagers.cpp +++ b/src/render/backend/nodemanagers.cpp @@ -46,6 +46,7 @@ #include <Qt3DRender/private/texturedatamanager_p.h> #include <Qt3DRender/private/geometryrenderermanager_p.h> #include <Qt3DRender/private/techniquemanager_p.h> +#include <private/resourceaccessor_p.h> #include <QOpenGLVertexArrayObject> @@ -90,6 +91,8 @@ NodeManagers::NodeManagers() , m_lightManager(new LightManager()) , m_computeJobManager(new ComputeCommandManager()) , m_renderStateManager(new RenderStateManager()) + , m_eventForwardManager(new EventForwardManager()) + , m_resourceAccessor(new ResourceAccessor(this)) { } @@ -129,6 +132,12 @@ NodeManagers::~NodeManagers() delete m_computeJobManager; delete m_renderStateManager; delete m_renderNodesManager; + delete m_eventForwardManager; +} + +QSharedPointer<ResourceAccessor> NodeManagers::resourceAccessor() +{ + return m_resourceAccessor; } template<> @@ -323,6 +332,12 @@ RenderStateManager *NodeManagers::manager<RenderStateNode>() const Q_DECL_NOTHRO return m_renderStateManager; } +template<> +EventForwardManager *NodeManagers::manager<EventForward>() const Q_DECL_NOTHROW +{ + return m_eventForwardManager; +} + } // Render } // Qt3DRender diff --git a/src/render/backend/nodemanagers_p.h b/src/render/backend/nodemanagers_p.h index b1ea2a0de..993e6f5cc 100644 --- a/src/render/backend/nodemanagers_p.h +++ b/src/render/backend/nodemanagers_p.h @@ -98,6 +98,7 @@ class LevelOfDetailManager; class LightManager; class ComputeCommandManager; class RenderStateManager; +class EventForwardManager; class FrameGraphNode; class Entity; @@ -125,12 +126,15 @@ class Attribute; class Geometry; class GeometryRenderer; class ObjectPicker; +class EventForward; //class BoundingVolumeDebug; class Light; class ComputeCommand; class RenderStateNode; class OpenGLVertexArrayObject; +class ResourceAccessor; + class QT3DRENDERSHARED_PRIVATE_EXPORT NodeManagers { public: @@ -205,6 +209,9 @@ public: inline LightManager *lightManager() const Q_DECL_NOEXCEPT { return m_lightManager; } inline ComputeCommandManager *computeJobManager() const Q_DECL_NOEXCEPT { return m_computeJobManager; } inline RenderStateManager *renderStateManager() const Q_DECL_NOEXCEPT { return m_renderStateManager; } + inline EventForwardManager *eventForwardManager() const Q_DECL_NOEXCEPT { return m_eventForwardManager; } + + QSharedPointer<ResourceAccessor> resourceAccessor(); private: CameraManager *m_cameraManager; @@ -241,6 +248,9 @@ private: LightManager *m_lightManager; ComputeCommandManager *m_computeJobManager; RenderStateManager *m_renderStateManager; + EventForwardManager *m_eventForwardManager; + + QSharedPointer<ResourceAccessor> m_resourceAccessor; }; // Specializations @@ -329,6 +339,9 @@ QT3DRENDERSHARED_PRIVATE_EXPORT GeometryRendererManager *NodeManagers::manager<G template<> QT3DRENDERSHARED_PRIVATE_EXPORT ObjectPickerManager *NodeManagers::manager<ObjectPicker>() const Q_DECL_NOEXCEPT; +template<> +QT3DRENDERSHARED_PRIVATE_EXPORT EventForwardManager *NodeManagers::manager<EventForward>() const Q_DECL_NOEXCEPT; + //template<> //QT3DRENDERSHARED_PRIVATE_EXPORT BoundingVolumeDebugManager *NodeManagers::manager<BoundingVolumeDebug>() const Q_DECL_NOEXCEPT; @@ -341,6 +354,9 @@ QT3DRENDERSHARED_PRIVATE_EXPORT ComputeCommandManager *NodeManagers::manager<Com template<> QT3DRENDERSHARED_PRIVATE_EXPORT RenderStateManager *NodeManagers::manager<RenderStateNode>() const Q_DECL_NOEXCEPT; +template<> +QT3DRENDERSHARED_PRIVATE_EXPORT EventForwardManager *NodeManagers::manager<EventForward>() const Q_DECL_NOEXCEPT; + } // Render } // Qt3DRender diff --git a/src/render/backend/render-backend.pri b/src/render/backend/render-backend.pri index 93e323caa..1cd911df8 100644 --- a/src/render/backend/render-backend.pri +++ b/src/render/backend/render-backend.pri @@ -41,7 +41,8 @@ HEADERS += \ $$PWD/shaderparameterpack_p.h \ $$PWD/renderviewbuilder_p.h \ $$PWD/frameprofiler_p.h \ - $$PWD/offscreensurfacehelper_p.h + $$PWD/offscreensurfacehelper_p.h \ + $$PWD/resourceaccessor_p.h SOURCES += \ $$PWD/renderthread.cpp \ @@ -75,5 +76,6 @@ SOURCES += \ $$PWD/uniform.cpp \ $$PWD/shaderparameterpack.cpp \ $$PWD/renderviewbuilder.cpp \ - $$PWD/offscreensurfacehelper.cpp + $$PWD/offscreensurfacehelper.cpp \ + $$PWD/resourceaccessor.cpp diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp index bc9dde83e..1c8875b58 100644 --- a/src/render/backend/renderer.cpp +++ b/src/render/backend/renderer.cpp @@ -154,6 +154,7 @@ Renderer::Renderer(QRenderAspect::RenderType type) , m_waitForInitializationToBeCompleted(0) , m_pickEventFilter(new PickEventFilter()) , m_exposed(0) + , m_shareContext(nullptr) , m_changeSet(0) , m_lastFrameCorrect(0) , m_glContext(nullptr) @@ -273,6 +274,17 @@ NodeManagers *Renderer::nodeManagers() const return m_nodesManager; } +/*! + \internal + + Return context which can be used to share resources safely + with qt3d main render context. +*/ +QOpenGLContext *Renderer::shareContext() const +{ + return m_shareContext ? m_shareContext : m_graphicsContext->openGLContext(); +} + void Renderer::setOpenGLContext(QOpenGLContext *context) { m_glContext = context; @@ -314,6 +326,10 @@ void Renderer::initialize() // Context is not owned by us, so we need to know if it gets destroyed m_contextConnection = QObject::connect(m_glContext, &QOpenGLContext::aboutToBeDestroyed, [this] { releaseGraphicsResources(); }); + m_shareContext = new QOpenGLContext; + m_shareContext->setFormat(m_glContext->format()); + m_shareContext->setShareContext(m_glContext); + m_shareContext->create(); } // Note: we don't have a surface at this point @@ -412,6 +428,8 @@ void Renderer::releaseGraphicsResources() if (m_ownedContext) delete context; + if (m_shareContext) + delete m_shareContext; m_graphicsContext.reset(nullptr); qCDebug(Backend) << Q_FUNC_INFO << "Renderer properly shutdown"; @@ -1686,7 +1704,12 @@ void Renderer::cleanGraphicsResources() QList<QMouseEvent> Renderer::pendingPickingEvents() const { - return m_pickEventFilter->pendingEvents(); + return m_pickEventFilter->pendingMouseEvents(); +} + +QList<QKeyEvent> Renderer::pendingKeyEvents() const +{ + return m_pickEventFilter->pendingKeyEvents(); } const GraphicsApiFilterData *Renderer::contextInfo() const diff --git a/src/render/backend/renderer_p.h b/src/render/backend/renderer_p.h index 9b5c35ed1..079d30e23 100644 --- a/src/render/backend/renderer_p.h +++ b/src/render/backend/renderer_p.h @@ -209,6 +209,7 @@ public: virtual void setSettings(RenderSettings *settings) Q_DECL_OVERRIDE; virtual RenderSettings *settings() const Q_DECL_OVERRIDE; + QOpenGLContext *shareContext() const Q_DECL_OVERRIDE; void updateGLResources(); void updateTexture(Texture *texture); @@ -230,8 +231,8 @@ public: inline RenderStateSet *defaultRenderState() const { return m_defaultRenderStateSet; } - QList<QMouseEvent> pendingPickingEvents() const; + QList<QKeyEvent> pendingKeyEvents() const; void addRenderCaptureSendRequest(Qt3DCore::QNodeId nodeId); const QVector<Qt3DCore::QNodeId> takePendingRenderCaptureSendRequests(); @@ -300,6 +301,7 @@ private: BackendNodeDirtySet m_changeSet; QAtomicInt m_lastFrameCorrect; QOpenGLContext *m_glContext; + QOpenGLContext *m_shareContext; PickBoundingVolumeJobPtr m_pickBoundingVolumeJob; qint64 m_time; diff --git a/src/render/backend/rendertargetoutput.cpp b/src/render/backend/rendertargetoutput.cpp index faebfacb6..cba92596d 100644 --- a/src/render/backend/rendertargetoutput.cpp +++ b/src/render/backend/rendertargetoutput.cpp @@ -121,9 +121,14 @@ void RenderTargetOutput::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) BackendNode::sceneChangeEvent(e); } -Attachment RenderTargetOutput::attachment() const +Qt3DRender::Render::Attachment *RenderTargetOutput::attachment() { - return m_attachmentData; + return &m_attachmentData; +} + +const Attachment *RenderTargetOutput::attachment() const +{ + return &m_attachmentData; } } // namespace Render diff --git a/src/render/backend/rendertargetoutput_p.h b/src/render/backend/rendertargetoutput_p.h index 14daa84e9..b7867c2cb 100644 --- a/src/render/backend/rendertargetoutput_p.h +++ b/src/render/backend/rendertargetoutput_p.h @@ -77,7 +77,8 @@ public: QAbstractTexture::CubeMapFace face() const; QRenderTargetOutput::AttachmentPoint point() const; void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; - Attachment attachment() const; + Attachment *attachment(); + const Attachment *attachment() const; private: void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; diff --git a/src/render/backend/resourceaccessor.cpp b/src/render/backend/resourceaccessor.cpp new file mode 100644 index 000000000..c02130aa9 --- /dev/null +++ b/src/render/backend/resourceaccessor.cpp @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** 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 "resourceaccessor_p.h" + +#include <Qt3DRender/qrendertargetoutput.h> + +#include <private/qrendertargetoutput_p.h> +#include <private/nodemanagers_p.h> +#include <private/texture_p.h> +#include <private/rendertargetoutput_p.h> +#include <private/texturedatamanager_p.h> +#include <private/gltexturemanager_p.h> +#include <private/managers_p.h> +#include <private/gltexture_p.h> + +#include <QtCore/qmutex.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Render { + +ResourceAccessor::ResourceAccessor(NodeManagers *mgr) + : m_textureManager(mgr->textureManager()) + , m_attachmentManager(mgr->attachmentManager()) + , m_glTextureManager(mgr->glTextureManager()) +{ + +} + +// called by render plugins from arbitrary thread +bool ResourceAccessor::accessResource(Qt3DCore::QNodeId nodeId, void **handle, QMutex **lock) +{ + Texture *tex = m_textureManager->lookupResource(nodeId); + if (!tex) { + RenderTargetOutput *output = m_attachmentManager->lookupResource(nodeId); + if (!output) + return false; + + Attachment **attachmentData = reinterpret_cast<Attachment **>(handle); + *attachmentData = output->attachment(); + return true; + } + GLTexture *glTex = m_glTextureManager->lookupResource(tex->peerId()); + if (!glTex) + return false; + + if (glTex->isDirty()) + return false; + + QOpenGLTexture** glTextureHandle = reinterpret_cast<QOpenGLTexture **>(handle); + *glTextureHandle = glTex->getOrCreateGLTexture(); + *lock = glTex->textureLock(); + return true; +} + +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/backend/resourceaccessor_p.h b/src/render/backend/resourceaccessor_p.h new file mode 100644 index 000000000..653a8adda --- /dev/null +++ b/src/render/backend/resourceaccessor_p.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_RENDER_RESOURCEACCESSOR_P_H +#define QT3DRENDER_RENDER_RESOURCEACCESSOR_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 <Qt3DCore/qnodeid.h> + +#include <private/qt3drender_global_p.h> + +QT_BEGIN_NAMESPACE + +class QMutex; + +namespace Qt3DRender +{ +namespace Render { + +class TextureManager; +class AttachmentManager; +class GLTextureManager; +class NodeManagers; + +class RenderBackendResourceAccessor +{ +public: + virtual bool accessResource(Qt3DCore::QNodeId nodeId, void **handle, QMutex **lock) = 0; +}; + +class QT3DRENDERSHARED_PRIVATE_EXPORT ResourceAccessor : public RenderBackendResourceAccessor +{ +public: + ResourceAccessor(NodeManagers *mgr); + bool accessResource(Qt3DCore::QNodeId nodeId, void **handle, QMutex **lock) Q_DECL_FINAL; +private: + GLTextureManager *m_glTextureManager; + TextureManager *m_textureManager; + AttachmentManager *m_attachmentManager; +}; + +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_RENDER_RESOURCEACCESSOR_P_H diff --git a/src/render/backend/triangleboundingvolume.cpp b/src/render/backend/triangleboundingvolume.cpp index 80a23572c..ca2d26897 100644 --- a/src/render/backend/triangleboundingvolume.cpp +++ b/src/render/backend/triangleboundingvolume.cpp @@ -112,15 +112,18 @@ Qt3DCore::QNodeId TriangleBoundingVolume::id() const return m_id; } -bool TriangleBoundingVolume::intersects(const RayCasting::QRay3D &ray, QVector3D *q) const +bool TriangleBoundingVolume::intersects(const RayCasting::QRay3D &ray, QVector3D *q, QVector3D *uvw) const { float t = 0.0f; - QVector3D uvw; - const bool intersected = intersectsSegmentTriangle(ray, m_c, m_b, m_a, uvw, t); - - if (intersected && q != nullptr) - *q = ray.point(t * ray.distance()); - + QVector3D uvwr; + const float intersected = intersectsSegmentTriangle(ray, m_c, m_b, m_a, uvwr, t); + + if (intersected) { + if (q != nullptr) + *q = ray.point(t); + if (uvw != nullptr) + *uvw = uvwr; + } return intersected; } diff --git a/src/render/backend/triangleboundingvolume_p.h b/src/render/backend/triangleboundingvolume_p.h index 1163efc46..3192ad456 100644 --- a/src/render/backend/triangleboundingvolume_p.h +++ b/src/render/backend/triangleboundingvolume_p.h @@ -78,7 +78,7 @@ public: const QVector3D &c); Qt3DCore::QNodeId id() const Q_DECL_FINAL; - bool intersects(const RayCasting::QRay3D &ray, QVector3D *q) const Q_DECL_FINAL; + bool intersects(const RayCasting::QRay3D &ray, QVector3D *q, QVector3D *uvw) const Q_DECL_FINAL; Type type() const Q_DECL_FINAL; QVector3D a() const; diff --git a/src/render/backend/trianglesvisitor.cpp b/src/render/backend/trianglesvisitor.cpp index 35cdecc29..5453661e0 100644 --- a/src/render/backend/trianglesvisitor.cpp +++ b/src/render/backend/trianglesvisitor.cpp @@ -71,24 +71,6 @@ bool isTriangleBased(Qt3DRender::QGeometryRenderer::PrimitiveType type) Q_DECL_N } } -struct BufferInfo -{ - BufferInfo() - : type(QAttribute::VertexBaseType::Float) - , dataSize(0) - , count(0) - , byteStride(0) - , byteOffset(0) - {} - - QByteArray data; - QAttribute::VertexBaseType type; - uint dataSize; - uint count; - uint byteStride; - uint byteOffset; -}; - // TO DO: Add methods for triangle strip adjacency // What about primitive restart ? @@ -328,6 +310,17 @@ void traverseTriangleAdjacency(Vertex *vertices, } } +template<typename Coordinate> +QVector4D readCoordinate(const BufferInfo &info, Coordinate *coordinates, uint index) +{ + const uint stride = info.byteStride / sizeof(Coordinate); + QVector4D ret(0, 0, 0, 1.0f); + coordinates += stride * index; + for (uint e = 0; e < info.dataSize; ++e) + ret[e] = coordinates[e]; + return ret; +} + template <QAttribute::VertexBaseType> struct EnumToType; template <> struct EnumToType<QAttribute::Byte> { typedef const char type; }; @@ -370,6 +363,31 @@ void processBuffer(const BufferInfo &info, Func &f) } } +QVector4D readBuffer(const BufferInfo &info, uint index) +{ + switch (info.type) { + case QAttribute::Byte: + return readCoordinate(info, castToType<QAttribute::Byte>(info.data, info.byteOffset), index); + case QAttribute::UnsignedByte: + return readCoordinate(info, castToType<QAttribute::UnsignedByte>(info.data, info.byteOffset), index); + case QAttribute::Short: + return readCoordinate(info, castToType<QAttribute::Short>(info.data, info.byteOffset), index); + case QAttribute::UnsignedShort: + return readCoordinate(info, castToType<QAttribute::UnsignedShort>(info.data, info.byteOffset), index); + case QAttribute::Int: + return readCoordinate(info, castToType<QAttribute::Int>(info.data, info.byteOffset), index); + case QAttribute::UnsignedInt: + return readCoordinate(info, castToType<QAttribute::UnsignedInt>(info.data, info.byteOffset), index); + case QAttribute::Float: + return readCoordinate(info, castToType<QAttribute::Float>(info.data, info.byteOffset), index); + case QAttribute::Double: + return readCoordinate(info, castToType<QAttribute::Double>(info.data, info.byteOffset), index); + default: + break; + } + return QVector4D(); +} + template<typename Index> struct IndexedVertexExecutor { @@ -530,6 +548,53 @@ void TrianglesVisitor::apply(const GeometryRenderer *renderer, const Qt3DCore::Q } } +bool CoordinateReader::setGeometry(const GeometryRenderer *renderer, const QString &attributeName) +{ + if (renderer == nullptr || renderer->instanceCount() != 1 + || !isTriangleBased(renderer->primitiveType())) { + return false; + } + + Geometry *geom = m_manager->lookupResource<Geometry, GeometryManager>(renderer->geometryId()); + + if (!geom) + return false; + + Attribute *attribute = nullptr; + + const auto attrIds = geom->attributes(); + for (const Qt3DCore::QNodeId attrId : attrIds) { + attribute = m_manager->lookupResource<Attribute, AttributeManager>(attrId); + if (attribute){ + if (attribute->name() == attributeName + || (attributeName == QStringLiteral("default") + && attribute->name() == QAttribute::defaultTextureCoordinateAttributeName())) { + break; + } + } + attribute = nullptr; + } + + if (!attribute) + return false; + + m_attribute = attribute; + m_buffer = m_manager->lookupResource<Buffer, BufferManager>(attribute->bufferId()); + + m_bufferInfo.data = m_buffer->data(); + m_bufferInfo.type = m_attribute->vertexBaseType(); + m_bufferInfo.byteOffset = m_attribute->byteOffset(); + m_bufferInfo.byteStride = m_attribute->byteStride(); + m_bufferInfo.dataSize = m_attribute->vertexSize(); + m_bufferInfo.count = m_attribute->count(); + return true; +} + +QVector4D CoordinateReader::getCoordinate(uint vertexIndex) +{ + return readBuffer(m_bufferInfo, vertexIndex); +} + } // namespace Render } // namespace Qt3DRender diff --git a/src/render/backend/trianglesvisitor_p.h b/src/render/backend/trianglesvisitor_p.h index 5f7cff9c0..a0fa89efb 100644 --- a/src/render/backend/trianglesvisitor_p.h +++ b/src/render/backend/trianglesvisitor_p.h @@ -52,6 +52,7 @@ // #include <Qt3DCore/qnodeid.h> +#include <Qt3DRender/QAttribute> QT_BEGIN_NAMESPACE @@ -65,6 +66,26 @@ namespace Render { class GeometryRenderer; class NodeManagers; +class Attribute; +class Buffer; + +struct BufferInfo +{ + BufferInfo() + : type(QAttribute::VertexBaseType::Float) + , dataSize(0) + , count(0) + , byteStride(0) + , byteOffset(0) + {} + + QByteArray data; + QAttribute::VertexBaseType type; + uint dataSize; + uint count; + uint byteStride; + uint byteOffset; +}; class Q_AUTOTEST_EXPORT TrianglesVisitor { @@ -84,6 +105,27 @@ protected: Qt3DCore::QNodeId m_nodeId; }; +class Q_AUTOTEST_EXPORT CoordinateReader +{ +public: + explicit CoordinateReader(NodeManagers *manager) + : m_manager(manager) + , m_attribute(nullptr) + , m_buffer(nullptr) + { + } + + bool setGeometry(const GeometryRenderer *renderer, const QString &attributeName); + + QVector4D getCoordinate(uint vertexIndex); + +protected: + NodeManagers *m_manager; + Attribute *m_attribute; + Buffer *m_buffer; + BufferInfo m_bufferInfo; +}; + } // namespace Render } // namespace Qt3DRender diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp index d9b45b7a7..0eb180650 100644 --- a/src/render/frontend/qrenderaspect.cpp +++ b/src/render/frontend/qrenderaspect.cpp @@ -81,6 +81,8 @@ #include <Qt3DRender/qrendersettings.h> #include <Qt3DRender/qrendercapture.h> #include <Qt3DRender/qmemorybarrier.h> +#include <Qt3DRender/qeventforward.h> + #include <Qt3DRender/private/cameraselectornode_p.h> #include <Qt3DRender/private/layerfilternode_p.h> #include <Qt3DRender/private/filterkey_p.h> @@ -127,6 +129,10 @@ #include <Qt3DRender/private/technique_p.h> #include <Qt3DRender/private/offscreensurfacehelper_p.h> #include <Qt3DRender/private/memorybarrier_p.h> +#include <Qt3DRender/private/eventforward_p.h> + +#include <private/qrenderpluginfactory_p.h> +#include <private/qrenderplugin_p.h> #include <Qt3DCore/qentity.h> #include <Qt3DCore/qtransform.h> @@ -162,8 +168,8 @@ QRenderAspectPrivate::QRenderAspectPrivate(QRenderAspect::RenderType type) , m_renderType(type) , m_offscreenHelper(nullptr) { - // Load the scene parsers loadSceneParsers(); + loadRenderPlugins(); } /*! \internal */ @@ -242,11 +248,17 @@ void QRenderAspectPrivate::registerBackendTypes() // Picking q->registerBackendType<QObjectPicker>(QSharedPointer<Render::NodeFunctor<Render::ObjectPicker, Render::ObjectPickerManager> >::create(m_renderer)); + q->registerBackendType<QEventForward>(QSharedPointer<Render::NodeFunctor<Render::EventForward, Render::EventForwardManager> >::create(m_renderer)); + + // Plugins + for (Render::QRenderPlugin *plugin : m_renderPlugins) + plugin->registerBackendTypes(q, m_renderer); } /*! \internal */ void QRenderAspectPrivate::unregisterBackendTypes() { + Q_Q(QRenderAspect); unregisterBackendType<Qt3DCore::QEntity>(); unregisterBackendType<Qt3DCore::QTransform>(); @@ -299,6 +311,18 @@ void QRenderAspectPrivate::unregisterBackendTypes() // Picking unregisterBackendType<QObjectPicker>(); + unregisterBackendType<QEventForward>(); + + // Plugins + for (Render::QRenderPlugin *plugin : m_renderPlugins) + plugin->unregisterBackendTypes(q); +} + +void QRenderAspectPrivate::registerBackendType(const QMetaObject &obj, + const QBackendNodeMapperPtr &functor) +{ + Q_Q(QRenderAspect); + q->registerBackendType(obj, functor); } /*! @@ -537,6 +561,16 @@ void QRenderAspectPrivate::loadSceneParsers() } } +void QRenderAspectPrivate::loadRenderPlugins() +{ + const QStringList keys = Render::QRenderPluginFactory::keys(); + for (const QString &key : keys) { + Render::QRenderPlugin *plugin = Render::QRenderPluginFactory::create(key, QStringList()); + if (plugin != nullptr) + m_renderPlugins.append(plugin); + } +} + } // namespace Qt3DRender QT_END_NAMESPACE diff --git a/src/render/frontend/qrenderaspect.h b/src/render/frontend/qrenderaspect.h index 72e8e4bdb..48ef5b164 100644 --- a/src/render/frontend/qrenderaspect.h +++ b/src/render/frontend/qrenderaspect.h @@ -56,6 +56,7 @@ class TestAspect; namespace Render { class Renderer; +class QRenderPlugin; } class QRenderAspectPrivate; @@ -92,6 +93,7 @@ private: void onEngineStartup() Q_DECL_OVERRIDE; friend class Render::Renderer; + friend class Render::QRenderPlugin; #if defined(QT_BUILD_INTERNAL) friend class QRenderAspectTester; friend class TestAspect; diff --git a/src/render/frontend/qrenderaspect_p.h b/src/render/frontend/qrenderaspect_p.h index 72183ef87..1fa0b26df 100644 --- a/src/render/frontend/qrenderaspect_p.h +++ b/src/render/frontend/qrenderaspect_p.h @@ -62,9 +62,11 @@ class QSurface; namespace Qt3DRender { class QSceneImporter; + namespace Render { class AbstractRenderer; class NodeManagers; +class QRenderPlugin; } namespace Render { @@ -82,9 +84,11 @@ public: void registerBackendTypes(); void unregisterBackendTypes(); void loadSceneParsers(); + void loadRenderPlugins(); void renderInitialize(QOpenGLContext *context); void renderSynchronous(); void renderShutdown(); + void registerBackendType(const QMetaObject &, const Qt3DCore::QBackendNodeMapperPtr &functor); QVector<Qt3DCore::QAspectJobPtr> createGeometryRendererJobs(); Render::NodeManagers *m_nodeManagers; @@ -92,6 +96,7 @@ public: bool m_initialized; QList<QSceneImporter *> m_sceneImporter; + QVector<Render::QRenderPlugin *> m_renderPlugins; QRenderAspect::RenderType m_renderType; Render::OffscreenSurfaceHelper *m_offscreenHelper; }; diff --git a/src/render/frontend/qrenderplugin_p.h b/src/render/frontend/qrenderplugin_p.h new file mode 100644 index 000000000..5144448c1 --- /dev/null +++ b/src/render/frontend/qrenderplugin_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** 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_RENDER_QRENDERPLUGIN_P_H +#define QT3DRENDER_RENDER_QRENDERPLUGIN_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 <private/qt3drender_global_p.h> + +#include <Qt3DCore/qbackendnode.h> +#include <Qt3DRender/qrenderaspect.h> + +#include <QtCore/qobject.h> +#include <QtCore/qstringlist.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +class AbstractRenderer; + +class QT3DRENDERSHARED_PRIVATE_EXPORT QRenderPlugin +{ +public: + virtual bool registerBackendTypes(QRenderAspect *aspect, AbstractRenderer *renderer) = 0; + virtual bool unregisterBackendTypes(QRenderAspect *aspect) = 0; + +protected: + void registerBackendType(QRenderAspect *aspect, const QMetaObject &obj, const Qt3DCore::QBackendNodeMapperPtr &functor) + { + aspect->registerBackendType(obj, functor); + } + void unregisterBackendType(QRenderAspect *aspect, const QMetaObject &obj) + { + aspect->unregisterBackendType(obj); + } +}; + +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_RENDER_QRENDERPLUGIN_P_H diff --git a/src/render/frontend/qrenderpluginfactory.cpp b/src/render/frontend/qrenderpluginfactory.cpp new file mode 100644 index 000000000..51fa068c6 --- /dev/null +++ b/src/render/frontend/qrenderpluginfactory.cpp @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** 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 "qrenderpluginfactory_p.h" +#include "qrenderpluginfactoryif_p.h" +#include "qrenderplugin_p.h" + +#include <QtCore/qcoreapplication.h> +#include <QtCore/qdir.h> + +#include <private/qfactoryloader_p.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Render { + +#ifndef QT_NO_LIBRARY +Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, (QRenderPluginFactoryInterface_iid, QLatin1String("/renderplugins"), Qt::CaseInsensitive)) +Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, directLoader, (QRenderPluginFactoryInterface_iid, QLatin1String(""), Qt::CaseInsensitive)) +#endif + +QStringList QRenderPluginFactory::keys(const QString &pluginPath) +{ +#ifndef QT_NO_LIBRARY + QStringList list; + if (!pluginPath.isEmpty()) { + QCoreApplication::addLibraryPath(pluginPath); + list = directLoader()->keyMap().values(); + if (!list.isEmpty()) { + const QString postFix = QLatin1String(" (from ") + + QDir::toNativeSeparators(pluginPath) + + QLatin1Char(')'); + const QStringList::iterator end = list.end(); + for (QStringList::iterator it = list.begin(); it != end; ++it) + (*it).append(postFix); + } + } + list.append(loader()->keyMap().values()); + return list; +#else + return QStringList(); +#endif +} + +QRenderPlugin *QRenderPluginFactory::create(const QString &name, const QStringList &args, + const QString &pluginPath) +{ +#ifndef QT_NO_LIBRARY + if (!pluginPath.isEmpty()) { + QCoreApplication::addLibraryPath(pluginPath); + if (QRenderPlugin *ret + = qLoadPlugin<QRenderPlugin, QRenderPluginFactoryIf>(directLoader(), name, args)) { + return ret; + } + } + if (QRenderPlugin *ret = qLoadPlugin<QRenderPlugin, QRenderPluginFactoryIf>(loader(), name, args)) + return ret; +#endif + return nullptr; +} + +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/frontend/qrenderpluginfactory_p.h b/src/render/frontend/qrenderpluginfactory_p.h new file mode 100644 index 000000000..9cffd500a --- /dev/null +++ b/src/render/frontend/qrenderpluginfactory_p.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** 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_RENDER_QRENDERPLUGINFACTORY_P_H +#define QT3DRENDER_RENDER_QRENDERPLUGINFACTORY_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 <private/qt3drender_global_p.h> + +#include <QtCore/qstringlist.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Render { + +class QRenderPlugin; + +class QT3DRENDERSHARED_PRIVATE_EXPORT QRenderPluginFactory +{ +public: + static QStringList keys(const QString &pluginPath = QString()); + static QRenderPlugin *create(const QString &name, const QStringList &args, + const QString &pluginPath = QString()); +}; + +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_RENDER_QRENDERPLUGINFACTORY_P_H diff --git a/src/render/frontend/qrenderpluginfactoryif.cpp b/src/render/frontend/qrenderpluginfactoryif.cpp new file mode 100644 index 000000000..af567084c --- /dev/null +++ b/src/render/frontend/qrenderpluginfactoryif.cpp @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** 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 "qrenderpluginfactoryif_p.h" + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Render { + +QRenderPluginFactoryIf::QRenderPluginFactoryIf(QObject *parent) + : QObject(parent) +{ + +} + +QRenderPluginFactoryIf::~QRenderPluginFactoryIf() +{ + +} + +QRenderPlugin *QRenderPluginFactoryIf::create(const QString &key, const QStringList ¶mList) +{ + Q_UNUSED(key) + Q_UNUSED(paramList) + return nullptr; +} + +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/frontend/qrenderpluginfactoryif_p.h b/src/render/frontend/qrenderpluginfactoryif_p.h new file mode 100644 index 000000000..d5f0008d2 --- /dev/null +++ b/src/render/frontend/qrenderpluginfactoryif_p.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** 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_RENDER_QRENDERPLUGINFACTORYIF_P_H +#define QT3DRENDER_RENDER_QRENDERPLUGINFACTORYIF_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 <QtCore/qobject.h> +#include <QtCore/qplugin.h> +#include <QtCore/qfactoryinterface.h> + +#include <private/qt3drender_global_p.h> + + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Render { + +#define QRenderPluginFactoryInterface_iid "org.qt-project.Qt3DRender.QRenderPluginFactoryInterface 5.9" + +class QRenderPlugin; + +class QT3DRENDERSHARED_PRIVATE_EXPORT QRenderPluginFactoryIf : public QObject +{ + Q_OBJECT +public: + explicit QRenderPluginFactoryIf(QObject *parent = nullptr); + ~QRenderPluginFactoryIf(); + + virtual QRenderPlugin *create(const QString &key, const QStringList ¶mList); +}; + +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_QRENDERPLUGINFACTORYIF_P_H diff --git a/src/render/frontend/render-frontend.pri b/src/render/frontend/render-frontend.pri index 0e78f9cff..7a27ba095 100644 --- a/src/render/frontend/render-frontend.pri +++ b/src/render/frontend/render-frontend.pri @@ -26,7 +26,10 @@ HEADERS += \ $$PWD/qpickingsettings.h \ $$PWD/qpickingsettings_p.h \ $$PWD/qcomputecommand_p.h \ - $$PWD/qcomputecommand.h + $$PWD/qcomputecommand.h \ + $$PWD/qrenderplugin_p.h \ + $$PWD/qrenderpluginfactory_p.h \ + $$PWD/qrenderpluginfactoryif_p.h SOURCES += \ $$PWD/qabstractfunctor.cpp \ @@ -43,5 +46,7 @@ SOURCES += \ $$PWD/qrendersettings.cpp \ $$PWD/qpickingsettings.cpp \ $$PWD/qrendertargetoutput.cpp \ - $$PWD/qcomputecommand.cpp + $$PWD/qcomputecommand.cpp \ + $$PWD/qrenderpluginfactory.cpp \ + $$PWD/qrenderpluginfactoryif.cpp diff --git a/src/render/frontend/sphere.cpp b/src/render/frontend/sphere.cpp index 80926efb9..2c22e0da4 100644 --- a/src/render/frontend/sphere.cpp +++ b/src/render/frontend/sphere.cpp @@ -223,8 +223,9 @@ Qt3DCore::QNodeId Sphere::id() const return m_id; } -bool Sphere::intersects(const RayCasting::QRay3D &ray, QVector3D *q) const +bool Sphere::intersects(const RayCasting::QRay3D &ray, QVector3D *q, QVector3D *uvw) const { + Q_UNUSED(uvw); return intersectRaySphere(ray, *this, q); } diff --git a/src/render/frontend/sphere_p.h b/src/render/frontend/sphere_p.h index 1defbf059..1587aecab 100644 --- a/src/render/frontend/sphere_p.h +++ b/src/render/frontend/sphere_p.h @@ -106,7 +106,7 @@ public: } Qt3DCore::QNodeId id() const Q_DECL_FINAL; - bool intersects(const RayCasting::QRay3D &ray, QVector3D *q) const Q_DECL_FINAL; + bool intersects(const RayCasting::QRay3D &ray, QVector3D *q, QVector3D *uvw = nullptr) const Q_DECL_FINAL; Type type() const Q_DECL_FINAL; static Sphere fromPoints(const QVector<QVector3D> &points); diff --git a/src/render/jobs/pickboundingvolumejob.cpp b/src/render/jobs/pickboundingvolumejob.cpp index 6b8b93647..7285bcfb7 100644 --- a/src/render/jobs/pickboundingvolumejob.cpp +++ b/src/render/jobs/pickboundingvolumejob.cpp @@ -59,6 +59,8 @@ namespace Render { namespace { +typedef PickingUtils::AbstractCollisionGathererFunctor::result_type HitList; + void setEventButtonAndModifiers(const QMouseEvent &event, QPickEvent::Buttons &eventButton, int &eventButtons, int &eventModifiers) { switch (event.button()) { @@ -120,6 +122,11 @@ void PickBoundingVolumeJob::setMouseEvents(const QList<QMouseEvent> &pendingEven m_pendingMouseEvents = pendingEvents; } +void PickBoundingVolumeJob::setKeyEvents(const QList<QKeyEvent> &pendingEvents) +{ + m_pendingKeyEvents = pendingEvents; +} + void PickBoundingVolumeJob::setFrameGraphRoot(FrameGraphNode *frameGraphRoot) { m_frameGraphRoot = frameGraphRoot; @@ -148,9 +155,10 @@ bool PickBoundingVolumeJob::runHelper() // Move to clear the events so that we don't process them several times // if run is called several times const auto mouseEvents = std::move(m_pendingMouseEvents); + const auto keyEvents = std::move(m_pendingKeyEvents); // If we have no events return early - if (mouseEvents.empty()) + if (mouseEvents.empty() && keyEvents.empty()) return false; // Quickly look which picker settings we've got @@ -219,6 +227,23 @@ bool PickBoundingVolumeJob::runHelper() // that the tree structure has changed PickingUtils::EntityGatherer entitiesGatherer(m_node); + // Forward keyboard events + if (keyEvents.size() > 0) { + for (Entity *e : entitiesGatherer.entities()) { + ObjectPicker *picker = e->renderComponent<ObjectPicker>(); + if (picker != nullptr) { + if (picker->isEventForwardingEnabled()) { + EventForward *eventForward + = m_manager->eventForwardManager()->lookupResource(picker->eventForward()); + if (eventForward->focus() && eventForward->forwardKeyboardEvents()) { + eventForward->forward(keyEvents); + break; + } + } + } + } + } + // Store the reducer function which varies depending on the picking settings set on the renderer using ReducerFunction = PickingUtils::CollisionVisitor::HitList (*)(PickingUtils::CollisionVisitor::HitList &results, const PickingUtils::CollisionVisitor::HitList &intermediate); @@ -244,7 +269,6 @@ bool PickBoundingVolumeJob::runHelper() // For each triplet of Viewport / Camera and Area for (const PickingUtils::ViewportCameraAreaTriplet &vca : vcaTriplets) { - typedef PickingUtils::AbstractCollisionGathererFunctor::result_type HitList; HitList sphereHits; QRay3D ray = rayForViewportAndCamera(vca.area, event.pos(), vca.viewport, vca.cameraId); if (trianglePickingRequested) { @@ -262,7 +286,8 @@ bool PickBoundingVolumeJob::runHelper() } // Dispatch events based on hit results - dispatchPickEvents(event, sphereHits, eventButton, eventButtons, eventModifiers, trianglePickingRequested, allHitsRequested); + dispatchPickEvents(event, sphereHits, eventButton, eventButtons, eventModifiers, + trianglePickingRequested, allHitsRequested, ray); } } @@ -296,7 +321,8 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event, int eventButtons, int eventModifiers, bool trianglePickingRequested, - bool allHitsRequested) + bool allHitsRequested, + const RayCasting::QRay3D &ray) { ObjectPicker *lastCurrentPicker = m_manager->objectPickerManager()->data(m_currentPicker); // If we have hits @@ -389,6 +415,49 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event, default: break; } + if (objectPicker->isEventForwardingEnabled()) { + EventForward *eventForward + = m_manager->eventForwardManager()->lookupResource(objectPicker->eventForward()); + QCollisionQueryResult::Hit triangleHit = hit; + bool valid = true; + if (eventForward->isEnabled() && eventForward->forwardMouseEvents()) { + if (!trianglePickingRequested) { + // Triangle picking is not enables so the triangle is not already in the + // query results. We need to redo the picking to get the triangle. + Qt3DRender::QRayCastingService rayCasting; + PickingUtils::TriangleCollisionGathererFunctor gathererFunctor; + const bool frontFaceRequested = + m_renderSettings->faceOrientationPickingMode() != QPickingSettings::BackFace; + const bool backFaceRequested = + m_renderSettings->faceOrientationPickingMode() != QPickingSettings::FrontFace; + gathererFunctor.m_frontFaceRequested = frontFaceRequested; + gathererFunctor.m_backFaceRequested = backFaceRequested; + gathererFunctor.m_manager = m_manager; + gathererFunctor.m_ray = ray; + + // The bounding method is inaccurate so the triangle picking doesn't + // necessarely produce any results + HitList hitlist = gathererFunctor.pick(&rayCasting, entity); + if (hitlist.size() > 0) + triangleHit = hitlist.at(0); + else + valid = false; + } + if (valid) { + CoordinateReader reader(m_manager); + if (reader.setGeometry(entity->renderComponent<GeometryRenderer>(), + eventForward->coordinateAttribute())) { + QVector4D c0 = reader.getCoordinate(triangleHit.m_vertexIndex[0]); + QVector4D c1 = reader.getCoordinate(triangleHit.m_vertexIndex[1]); + QVector4D c2 = reader.getCoordinate(triangleHit.m_vertexIndex[2]); + QVector4D ci = c2 * triangleHit.m_uvw.x() + + c1 * triangleHit.m_uvw.y() + c0 * triangleHit.m_uvw.z(); + ci.setW(1.0f); + eventForward->forward(event, ci); + } + } + } + } } // The ObjectPicker was hit -> it is still being hovered diff --git a/src/render/jobs/pickboundingvolumejob_p.h b/src/render/jobs/pickboundingvolumejob_p.h index 9f52943d1..cd8b9a95d 100644 --- a/src/render/jobs/pickboundingvolumejob_p.h +++ b/src/render/jobs/pickboundingvolumejob_p.h @@ -59,6 +59,7 @@ #include <Qt3DRender/private/pickboundingvolumeutils_p.h> #include <Qt3DRender/qpickevent.h> #include <QMouseEvent> +#include <QKeyEvent> #include <QSharedPointer> QT_BEGIN_NAMESPACE @@ -82,6 +83,7 @@ public: void setRoot(Entity *root); void setMouseEvents(const QList<QMouseEvent> &pendingEvents); + void setKeyEvents(const QList<QKeyEvent> &pendingEvents); void setFrameGraphRoot(FrameGraphNode *frameGraphRoot); void setRenderSettings(RenderSettings *settings); void setManagers(NodeManagers *manager); @@ -102,8 +104,11 @@ protected: void run() Q_DECL_FINAL; void dispatchPickEvents(const QMouseEvent &event, const PickingUtils::CollisionVisitor::HitList &sphereHits, QPickEvent::Buttons eventButton, - int eventButtons, int eventModifiers, - bool trianglePickingRequested, bool allHitsRequested); + int eventButtons, + int eventModifiers, + bool trianglePickingRequested, + bool allHitsRequested, + const RayCasting::QRay3D &ray); private: NodeManagers *m_manager; @@ -115,6 +120,8 @@ private: bool m_oneEnabledAtLeast; bool m_oneHoverAtLeast; + QList<QKeyEvent> m_pendingKeyEvents; + void viewMatrixForCamera(Qt3DCore::QNodeId cameraId, QMatrix4x4 &viewMatrix, QMatrix4x4 &projectionMatrix) const; diff --git a/src/render/jobs/pickboundingvolumeutils.cpp b/src/render/jobs/pickboundingvolumeutils.cpp index 1573aa112..8609906e9 100644 --- a/src/render/jobs/pickboundingvolumeutils.cpp +++ b/src/render/jobs/pickboundingvolumeutils.cpp @@ -175,6 +175,7 @@ bool CollisionVisitor::intersectsSegmentTriangle(uint andx, const QVector3D &a, queryResult.m_vertexIndex[0] = andx; queryResult.m_vertexIndex[1] = bndx; queryResult.m_vertexIndex[2] = cndx; + queryResult.m_uvw = uvw; queryResult.m_intersection = m_ray.point(t * m_ray.distance()); queryResult.m_distance = m_ray.projectedDistance(queryResult.m_intersection); hits.push_back(queryResult); diff --git a/src/render/picking/eventforward.cpp b/src/render/picking/eventforward.cpp new file mode 100644 index 000000000..0216542bd --- /dev/null +++ b/src/render/picking/eventforward.cpp @@ -0,0 +1,196 @@ +/**************************************************************************** +** +** 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 <Qt3DRender/qeventforward.h> +#include <Qt3DRender/qattribute.h> +#include <Qt3DCore/qpropertyupdatedchange.h> + +#include <private/qeventforward_p.h> +#include <private/eventforward_p.h> +#include <private/posteventstofrontend_p.h> + +#include <QtGui/qevent.h> +#include <QtCore/qcoreapplication.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +EventForward::EventForward() + : BackendNode(QBackendNode::ReadWrite) + , m_forwardMouseEvents(false) + , m_forwardKeyboardEvents(false) + , m_focus(false) +{ + +} + +EventForward::~EventForward() +{ + +} + +void EventForward::cleanup() +{ + setEnabled(false); + m_coordinateAttribute = ""; + m_coordinateTransform.setToIdentity(); + m_forwardMouseEvents = false; + m_forwardKeyboardEvents = false; + m_focus = false; +} + +QString EventForward::coordinateAttribute() const +{ + return m_coordinateAttribute; +} + +QMatrix4x4 EventForward::coordinateTransform() const +{ + return m_coordinateTransform; +} + +bool EventForward::forwardMouseEvents() const +{ + return m_forwardMouseEvents; +} + +bool EventForward::forwardKeyboardEvents() const +{ + return m_forwardKeyboardEvents; +} + +bool EventForward::focus() const +{ + return m_focus; +} + +void EventForward::setCoordinateTransform(const QMatrix4x4 &transform) +{ + m_coordinateTransform = transform; +} + +void EventForward::setCoordinateAttribute(const QString &attribute) +{ + m_coordinateAttribute = attribute; +} + +void EventForward::setForwardMouseEvents(bool enabled) +{ + m_forwardMouseEvents = enabled; +} + +void EventForward::setForwardKeyboardEvents(bool enabled) +{ + m_forwardKeyboardEvents = enabled; +} + +void EventForward::setFocus(bool focus) +{ + m_focus = focus; +} + +void EventForward::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) +{ + const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QEventForwardData>>(change); + const auto &data = typedChange->data; + setCoordinateAttribute(data.coordinateAttribute); + setCoordinateTransform(data.coordinateTransform); + setForwardMouseEvents(data.forwardMouseEvents); + setForwardKeyboardEvents(data.forwardKeyboardEvents); + setFocus(data.focus); +} + +void EventForward::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) +{ + if (e->type() == Qt3DCore::PropertyUpdated) { + const Qt3DCore::QPropertyUpdatedChangePtr propertyChange + = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(e); + + if (propertyChange->propertyName() == QByteArrayLiteral("coordinateTransform")) + setCoordinateTransform(propertyChange->value().value<QMatrix4x4>()); + else if (propertyChange->propertyName() == QByteArrayLiteral("coordinateAttribute")) + setCoordinateAttribute(propertyChange->value().toString()); + else if (propertyChange->propertyName() == QByteArrayLiteral("forwardMouseEvents")) + setForwardMouseEvents(propertyChange->value().toBool()); + else if (propertyChange->propertyName() == QByteArrayLiteral("forwardKeyboardEvents")) + setForwardKeyboardEvents(propertyChange->value().toBool()); + else if (propertyChange->propertyName() == QByteArrayLiteral("focus")) + setFocus(propertyChange->value().toBool()); + } + + BackendNode::sceneChangeEvent(e); +} + +void EventForward::forward(const QMouseEvent &event, const QVector4D &coordinate) +{ + const QVector4D transformedCoordinate = m_coordinateTransform * coordinate; + const QPointF local = QPointF(transformedCoordinate.x(), transformedCoordinate.y()); + QMouseEvent *mouseEvent = new QMouseEvent(event.type(), local, local, local, event.button(), + event.buttons(), event.modifiers(), + Qt::MouseEventSynthesizedByApplication); + + PostEventsToFrontendPtr events = PostEventsToFrontendPtr::create(mouseEvent); + + auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId()); + e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + e->setPropertyName("events"); + e->setValue(QVariant::fromValue(events)); + notifyObservers(e); +} + +void EventForward::forward(const QList<QKeyEvent> &keyEvents) +{ + QVector<QEvent *> eventsToSend; + for (const QKeyEvent &e : keyEvents) { + QKeyEvent *keyEvent = new QKeyEvent(e.type(), e.key(), e.modifiers(), e.nativeScanCode(), + e.nativeVirtualKey(), e.nativeModifiers()); + eventsToSend.append(keyEvent); + } + PostEventsToFrontendPtr events = PostEventsToFrontendPtr::create(eventsToSend); + auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId()); + e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + e->setPropertyName("events"); + e->setValue(QVariant::fromValue(events)); + notifyObservers(e); +} + +} // Render +} // Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/picking/eventforward_p.h b/src/render/picking/eventforward_p.h new file mode 100644 index 000000000..663298e40 --- /dev/null +++ b/src/render/picking/eventforward_p.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** 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_RENDER_EVENTFORWARD_P_H +#define QT3DRENDER_RENDER_EVENTFORWARD_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 <private/backendnode_p.h> + +#include <QtGui/qmatrix4x4.h> +#include <QtGui/qevent.h> +#include <QtCore/qstring.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +class Q_AUTOTEST_EXPORT EventForward : public BackendNode +{ +public: + EventForward(); + ~EventForward(); + + void cleanup(); + + QString coordinateAttribute() const; + QMatrix4x4 coordinateTransform() const; + bool forwardMouseEvents() const; + bool forwardKeyboardEvents() const; + bool focus() const; + + void setTarget(QObject *target); + void setCoordinateTransform(const QMatrix4x4 &transform); + void setCoordinateAttribute(const QString &attribute); + void setForwardMouseEvents(bool enabled); + void setForwardKeyboardEvents(bool enabled); + void setFocus(bool focus); + + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_FINAL; + + void forward(const QMouseEvent &event, const QVector4D &coordinate); + void forward(const QList<QKeyEvent> &keyEvents); + +private: + void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; + + QString m_coordinateAttribute; + QMatrix4x4 m_coordinateTransform; + bool m_forwardMouseEvents; + bool m_forwardKeyboardEvents; + bool m_focus; +}; + +} // Render +} // Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_RENDER_EVENTFORWARD_P_H diff --git a/src/render/picking/objectpicker.cpp b/src/render/picking/objectpicker.cpp index b85bdc723..6d84ec2a0 100644 --- a/src/render/picking/objectpicker.cpp +++ b/src/render/picking/objectpicker.cpp @@ -70,6 +70,7 @@ void ObjectPicker::cleanup() m_isPressed = false; m_hoverEnabled = false; m_dragEnabled = false; + m_eventForward = Qt3DCore::QNodeId(); notifyJob(); } @@ -79,6 +80,7 @@ void ObjectPicker::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr const auto &data = typedChange->data; m_hoverEnabled = data.hoverEnabled; m_dragEnabled = data.dragEnabled; + m_eventForward = data.eventForward; notifyJob(); } @@ -92,17 +94,13 @@ void ObjectPicker::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) { if (e->type() == Qt3DCore::PropertyUpdated) { const Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(e); - bool notifyPickJob = false; if (propertyChange->propertyName() == QByteArrayLiteral("hoverEnabled")) { m_hoverEnabled = propertyChange->value().toBool(); - notifyPickJob = true; } else if (propertyChange->propertyName() == QByteArrayLiteral("dragEnabled")) { m_dragEnabled = propertyChange->value().toBool(); - notifyPickJob = true; - } else if (propertyChange->propertyName() == QByteArrayLiteral("enabled")) { - notifyPickJob = true; - // actual value change handled in BackendNode::sceneChangeEvent + } else if (propertyChange->propertyName() == QByteArrayLiteral("eventForward")) { + m_eventForward = propertyChange->value().value<Qt3DCore::QNodeId>(); } markDirty(AbstractRenderer::AllDirty); @@ -127,6 +125,16 @@ bool ObjectPicker::isDragEnabled() const return m_dragEnabled; } +bool ObjectPicker::isEventForwardingEnabled() const +{ + return Qt3DCore::QNodeId() != m_eventForward; +} + +Qt3DCore::QNodeId ObjectPicker::eventForward() const +{ + return m_eventForward; +} + void ObjectPicker::onClicked(QPickEventPtr event) { auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId()); diff --git a/src/render/picking/objectpicker_p.h b/src/render/picking/objectpicker_p.h index 2c2cc361e..68231073d 100644 --- a/src/render/picking/objectpicker_p.h +++ b/src/render/picking/objectpicker_p.h @@ -73,6 +73,8 @@ public: bool isPressed() const; bool isHoverEnabled() const; bool isDragEnabled() const; + bool isEventForwardingEnabled() const; + Qt3DCore::QNodeId eventForward() const; void onClicked(QPickEventPtr event); void onMoved(QPickEventPtr event); @@ -88,6 +90,7 @@ private: bool m_isPressed; bool m_hoverEnabled; bool m_dragEnabled; + Qt3DCore::QNodeId m_eventForward; }; } // Render diff --git a/src/render/picking/pickeventfilter.cpp b/src/render/picking/pickeventfilter.cpp index a1ae52068..19d3b6b6e 100644 --- a/src/render/picking/pickeventfilter.cpp +++ b/src/render/picking/pickeventfilter.cpp @@ -61,11 +61,19 @@ PickEventFilter::~PickEventFilter() Called from a worker thread in the thread pool so be sure to mutex protect the data. */ -QList<QMouseEvent> PickEventFilter::pendingEvents() +QList<QMouseEvent> PickEventFilter::pendingMouseEvents() { QMutexLocker locker(&m_mutex); - QList<QMouseEvent> pendingEvents(m_pendingEvents); - m_pendingEvents.clear(); + QList<QMouseEvent> pendingEvents(m_pendingMouseEvents); + m_pendingMouseEvents.clear(); + return pendingEvents; +} + +QList<QKeyEvent> PickEventFilter::pendingKeyEvents() +{ + QMutexLocker locker(&m_mutex); + QList<QKeyEvent> pendingEvents(m_pendingKeyEvents); + m_pendingKeyEvents.clear(); return pendingEvents; } @@ -82,7 +90,12 @@ bool PickEventFilter::eventFilter(QObject *obj, QEvent *e) case QEvent::MouseMove: case QEvent::HoverMove: { QMutexLocker locker(&m_mutex); - m_pendingEvents.push_back(QMouseEvent(*static_cast<QMouseEvent *>(e))); + m_pendingMouseEvents.push_back(QMouseEvent(*static_cast<QMouseEvent *>(e))); + } break; + case QEvent::KeyPress: + case QEvent::KeyRelease: { + QMutexLocker locker(&m_mutex); + m_pendingKeyEvents.push_back(QKeyEvent(*static_cast<QKeyEvent *>(e))); } default: break; diff --git a/src/render/picking/pickeventfilter_p.h b/src/render/picking/pickeventfilter_p.h index df94a3085..fc4b00ddc 100644 --- a/src/render/picking/pickeventfilter_p.h +++ b/src/render/picking/pickeventfilter_p.h @@ -53,6 +53,7 @@ #include <QObject> #include <QMouseEvent> +#include <QKeyEvent> #include <QtCore/qmutex.h> QT_BEGIN_NAMESPACE @@ -68,13 +69,15 @@ public: explicit PickEventFilter(QObject *parent = nullptr); ~PickEventFilter(); - QList<QMouseEvent> pendingEvents(); + QList<QMouseEvent> pendingMouseEvents(); + QList<QKeyEvent> pendingKeyEvents(); protected: bool eventFilter(QObject *obj, QEvent *e) Q_DECL_FINAL; private: - QList<QMouseEvent> m_pendingEvents; + QList<QMouseEvent> m_pendingMouseEvents; + QList<QKeyEvent> m_pendingKeyEvents; QMutex m_mutex; }; diff --git a/src/render/picking/picking.pri b/src/render/picking/picking.pri index c4c188a82..c2eb8f50b 100644 --- a/src/render/picking/picking.pri +++ b/src/render/picking/picking.pri @@ -7,11 +7,18 @@ HEADERS += \ $$PWD/qpicktriangleevent.h \ $$PWD/objectpicker_p.h \ $$PWD/pickeventfilter_p.h \ - $$PWD/qobjectpicker_p.h + $$PWD/qobjectpicker_p.h \ + $$PWD/qeventforward.h \ + $$PWD/qeventforward_p.h \ + $$PWD/eventforward_p.h \ + $$PWD/posteventstofrontend_p.h SOURCES += \ $$PWD/qobjectpicker.cpp \ $$PWD/qpickevent.cpp \ $$PWD/qpicktriangleevent.cpp \ $$PWD/objectpicker.cpp \ - $$PWD/pickeventfilter.cpp + $$PWD/pickeventfilter.cpp \ + $$PWD/qeventforward.cpp \ + $$PWD/eventforward.cpp \ + $$PWD/posteventstofrontend.cpp diff --git a/src/render/picking/posteventstofrontend.cpp b/src/render/picking/posteventstofrontend.cpp new file mode 100644 index 000000000..51f986902 --- /dev/null +++ b/src/render/picking/posteventstofrontend.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** 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 "posteventstofrontend_p.h" + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +PostEventsToFrontend::PostEventsToFrontend() + : QObject() +{ + +} + +PostEventsToFrontend::PostEventsToFrontend(QEvent *event) + : QObject() +{ + m_events.append(event); +} + +PostEventsToFrontend::PostEventsToFrontend(const QVector<QEvent *> &events) + : QObject() +{ + m_events = events; +} + +PostEventsToFrontend::~PostEventsToFrontend() +{ + for (QEvent *e : m_events) + delete e; +} + +QVector<QEvent *> &PostEventsToFrontend::events() +{ + return m_events; +} + +} + +QT_END_NAMESPACE diff --git a/src/render/picking/posteventstofrontend_p.h b/src/render/picking/posteventstofrontend_p.h new file mode 100644 index 000000000..5dd29b047 --- /dev/null +++ b/src/render/picking/posteventstofrontend_p.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** 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_POSTEVENTSTOFRONTEND_P_H +#define QT3DRENDER_POSTEVENTSTOFRONTEND_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 <QtGui/qevent.h> +#include <QtCore/qvector.h> +#include <QtCore/qsharedpointer.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +class Q_AUTOTEST_EXPORT PostEventsToFrontend : public QObject +{ + Q_OBJECT +public: + PostEventsToFrontend(); + PostEventsToFrontend(QEvent *event); + PostEventsToFrontend(const QVector<QEvent *> &events); + ~PostEventsToFrontend(); + + QVector<QEvent *> &events(); +private: + QVector<QEvent *> m_events; +}; + +typedef QSharedPointer<PostEventsToFrontend> PostEventsToFrontendPtr; + +} // Qt3DRender + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(Qt3DRender::PostEventsToFrontend*) + +#endif // QT3DRENDER_POSTEVENTSTOFRONTEND_P_H diff --git a/src/render/picking/qeventforward.cpp b/src/render/picking/qeventforward.cpp new file mode 100644 index 000000000..08546fabd --- /dev/null +++ b/src/render/picking/qeventforward.cpp @@ -0,0 +1,285 @@ +/**************************************************************************** +** +** 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 "qeventforward.h" +#include "qeventforward_p.h" +#include "posteventstofrontend_p.h" + +#include <Qt3DCore/qpropertyupdatedchange.h> +#include <QtCore/qcoreapplication.h> + +#include <QtGui/qevent.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +/*! + \class Qt3DRender::QEventForward + \inmodule Qt3DRender + + \brief The QEventForward class instantiates a node that can + be used to forward events from the scene. + + An QEventForward class can be used to forward pick events and keyboard events + from entities having a QObjectPicker. When the QObjectPicker handles pick event, + it hands it to the QEventForward, which converts it to QMouseEvent. The event + mouse coordinates are calculated by interpolating the given coordinate attribute + on the position the pick ray intersected the triangle, and then multiplying the + interpolated coordinate with the given transformation matrix. The event is then + sent and to the target object. + + \since 5.9 +*/ + +/*! + \qmltype EventForward + \instantiates Qt3DRender::QEventForward + \inherits Node + \inqmlmodule Qt3D.Render + \brief The EventForward type instantiates a node that can + be used to forward events from the scene. + + An EventForward type can be used to forward pick events and keyboard events + from entities having a ObjectPicker. When the ObjectPicker handles pick event, + it hands it to the EventForward, which converts it to MouseEvent. The event + mouse coordinates are calculated by interpolating the given coordinate attribute + on the position the pick ray intersected the triangle, and then multiplying the + interpolated coordinate with the given transformation matrix. The event is then + sent and to the target object. + + */ + +/*! + \qmlproperty Object Qt3D.Render::EventForward::target + Holds the object the events are sent to. +*/ +/*! + \qmlproperty bool Qt3D.Render::EventForward::forwardMouseEvents + Holds whether mouse event forwarding is enabled. +*/ +/*! + \qmlproperty bool Qt3D.Render::EventForward::forwardKeyboardEvents + Holds whether keyboard event forwarding is enabled. +*/ +/*! + \qmlproperty Matrix4x4 Qt3D.Render::EventForward::coordinateTransform + Holds the coordinate transformation. +*/ +/*! + \qmlproperty string Qt3D.Render::EventForward::coordinateAttribute + Holds the name of the coordinate attribute the mouse coordinates are calculated from. +*/ +/*! + \qmlproperty bool Qt3D.Render::EventForward::focus + Holds whether the QObjectPicker has focus. +*/ + +/*! + \property QEventForward::target + Holds the object the events are sent to. +*/ +/*! + \property QEventForward::forwardMouseEvents + Holds whether mouse event forwarding is enabled. +*/ +/*! + \property QEventForward::forwardKeyboardEvents + Holds whether keyboard event forwarding is enabled. +*/ +/*! + \property QEventForward::coordinateTransform + Holds the coordinate transformation. +*/ +/*! + \property QEventForward::coordinateAttribute + Holds the name of the coordinate attribute the mouse coordinates are calculated from. +*/ +/*! + \property QEventForward::focus + Holds whether the ObjectPicker has focus. + */ + +/*! + + */ +QEventForward::QEventForward(Qt3DCore::QNode *parent) + : Qt3DCore::QNode(*new QEventForwardPrivate(), parent) +{ +} + +/*! \internal */ +QEventForward::~QEventForward() +{ +} + +QObject *QEventForward::target() const +{ + Q_D(const QEventForward); + return d->m_target; +} + +void QEventForward::targetDestroyed(QObject *target) +{ + Q_D(QEventForward); + Q_ASSERT(target == d->m_target); + setTarget(nullptr); +} + +void QEventForward::setTarget(QObject *target) +{ + Q_D(QEventForward); + if (target != d->m_target) { + if (d->m_target != nullptr) + QObject::disconnect(d->m_destructionConnection); + d->m_target = target; + if (d->m_target) { + d->m_destructionConnection = QObject::connect(target, &QObject::destroyed, + this, &QEventForward::targetDestroyed); + } + emit targetChanged(target); + } +} + +QMatrix4x4 QEventForward::coordinateTransform() const +{ + Q_D(const QEventForward); + return d->m_transform; +} + +void QEventForward::setCoordinateTransform(const QMatrix4x4 &coordinateTransform) +{ + Q_D(QEventForward); + if (coordinateTransform != d->m_transform) { + d->m_transform = coordinateTransform; + emit coordinateTransformChanged(coordinateTransform); + } +} + +QString QEventForward::coordinateAttribute() const +{ + Q_D(const QEventForward); + return d->m_attribute; +} + +void QEventForward::setCoordinateAttribute(const QString &coordinateAttribute) +{ + Q_D(QEventForward); + if (coordinateAttribute != d->m_attribute) { + d->m_attribute = coordinateAttribute; + emit coordinateAttributeChanged(coordinateAttribute); + } +} + +bool QEventForward::forwardMouseEvents() const +{ + Q_D(const QEventForward); + return d->m_forwardMouseEvents; +} + +void QEventForward::setForwardMouseEvents(bool forward) +{ + Q_D(QEventForward); + if (forward != d->m_forwardMouseEvents) { + d->m_forwardMouseEvents = forward; + emit forwardMouseEventsChanged(forward); + } +} + +bool QEventForward::forwardKeyboardEvents() const +{ + Q_D(const QEventForward); + return d->m_forwardKeyboardEvents; +} + +void QEventForward::setForwardKeyboardEvents(bool forward) +{ + Q_D(QEventForward); + if (forward != d->m_forwardKeyboardEvents) { + d->m_forwardKeyboardEvents = forward; + emit forwardKeyboardEventsChanged(forward); + } +} + +bool QEventForward::focus() const +{ + Q_D(const QEventForward); + return d->m_focus; +} + +void QEventForward::setFocus(bool focus) +{ + Q_D(QEventForward); + if (d->m_focus != focus) { + d->m_focus = focus; + emit focusChanged(focus); + } +} + +/*! + \internal + */ +Qt3DCore::QNodeCreatedChangeBasePtr QEventForward::createNodeCreationChange() const +{ + auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QEventForwardData>::create(this); + auto &data = creationChange->data; + Q_D(const QEventForward); + data.target = d->m_target; + data.coordinateTransform = d->m_transform; + data.coordinateAttribute = d->m_attribute; + data.forwardMouseEvents = d->m_forwardMouseEvents; + data.forwardKeyboardEvents = d->m_forwardKeyboardEvents; + data.focus = d->m_focus; + return creationChange; +} + +void QEventForward::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) +{ + Q_D(QEventForward); + Qt3DCore::QPropertyUpdatedChangePtr e + = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(change); + if (e->type() == Qt3DCore::PropertyUpdated && d->m_target != nullptr) { + if (e->propertyName() == QByteArrayLiteral("events")) { + PostEventsToFrontendPtr postedEvents = e->value().value<PostEventsToFrontendPtr>(); + for (QEvent *event : postedEvents->events()) + QCoreApplication::sendEvent(d->m_target, event); + } + } +} + +} // Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/picking/qeventforward.h b/src/render/picking/qeventforward.h new file mode 100644 index 000000000..ee8100318 --- /dev/null +++ b/src/render/picking/qeventforward.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** 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_QEVENTFORWARD_H +#define QT3DRENDER_QEVENTFORWARD_H + +#include <Qt3DRender/qt3drender_global.h> + +#include <Qt3DCore/qnode.h> + +#include <QtGui/qmatrix4x4.h> +#include <QtCore/qstring.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +class QEventForwardPrivate; + +class QT3DRENDERSHARED_EXPORT QEventForward : public Qt3DCore::QNode +{ + Q_OBJECT + Q_PROPERTY(QObject *target READ target WRITE setTarget NOTIFY targetChanged) + Q_PROPERTY(bool forwardMouseEvents READ forwardMouseEvents WRITE setForwardMouseEvents NOTIFY forwardMouseEventsChanged) + Q_PROPERTY(bool forwardKeyboardEvents READ forwardKeyboardEvents WRITE setForwardKeyboardEvents NOTIFY forwardKeyboardEventsChanged) + Q_PROPERTY(QMatrix4x4 coordinateTransform READ coordinateTransform WRITE setCoordinateTransform NOTIFY coordinateTransformChanged) + Q_PROPERTY(QString coordinateAttribute READ coordinateAttribute WRITE setCoordinateAttribute NOTIFY coordinateAttributeChanged) + Q_PROPERTY(bool focus READ focus WRITE setFocus NOTIFY focusChanged) + +public: + explicit QEventForward(Qt3DCore::QNode *parent = nullptr); + ~QEventForward(); + + QObject *target() const; + QMatrix4x4 coordinateTransform() const; + QString coordinateAttribute() const; + bool forwardMouseEvents() const; + bool forwardKeyboardEvents() const; + bool focus() const; + +public Q_SLOTS: + void setTarget(QObject *target); + void setCoordinateTransform(const QMatrix4x4 &coordinateTransform); + void setCoordinateAttribute(const QString &coordinateAttribute); + void setForwardMouseEvents(bool forward); + void setForwardKeyboardEvents(bool forward); + void setFocus(bool focus); + +Q_SIGNALS: + void targetChanged(QObject *target); + void coordinateTransformChanged(const QMatrix4x4 &coordinateTransform); + void coordinateAttributeChanged(const QString &coordinateAttribute); + void forwardMouseEventsChanged(bool forward); + void forwardKeyboardEventsChanged(bool forward); + void focusChanged(bool focus); + +protected: + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) Q_DECL_OVERRIDE; + +private: + Q_DECLARE_PRIVATE(QEventForward) + Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE; + void targetDestroyed(QObject *target); +}; + +} // Qt3DRender + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(Qt3DRender::QEventForward*) + +#endif // QT3DRENDER_QEVENTFORWARD_H diff --git a/src/render/picking/qeventforward_p.h b/src/render/picking/qeventforward_p.h new file mode 100644 index 000000000..c087bc8f5 --- /dev/null +++ b/src/render/picking/qeventforward_p.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** 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_QEVENTFORWARD_P_H +#define QT3DRENDER_QEVENTFORWARD_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 <private/qnode_p.h> +#include <Qt3DCore/qnodeid.h> +#include <qmatrix4x4.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +/*! + \internal +*/ +class QEventForwardPrivate : public Qt3DCore::QNodePrivate +{ +public: + QEventForwardPrivate() + : QNodePrivate() + , m_target(nullptr) + , m_attribute("default") + , m_forwardMouseEvents(true) + , m_forwardKeyboardEvents(false) + , m_focus(false) + { + + } + + Q_DECLARE_PUBLIC(QEventForward) + + QObject *m_target; + QMatrix4x4 m_transform; + QString m_attribute; + bool m_forwardMouseEvents; + bool m_forwardKeyboardEvents; + bool m_focus; + QMetaObject::Connection m_destructionConnection; +}; + +struct QEventForwardData +{ + QObject *target; + QMatrix4x4 coordinateTransform; + QString coordinateAttribute; + bool forwardMouseEvents; + bool forwardKeyboardEvents; + bool focus; +}; + +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_QEVENTFORWARD_P_H diff --git a/src/render/picking/qobjectpicker.cpp b/src/render/picking/qobjectpicker.cpp index 1842b7fee..9fa8b774c 100644 --- a/src/render/picking/qobjectpicker.cpp +++ b/src/render/picking/qobjectpicker.cpp @@ -43,6 +43,7 @@ #include <Qt3DCore/private/qcomponent_p.h> #include <Qt3DCore/qpropertyupdatedchange.h> #include <Qt3DRender/qpickevent.h> +#include <Qt3DRender/qeventforward.h> QT_BEGIN_NAMESPACE @@ -203,6 +204,37 @@ void QObjectPicker::setDragEnabled(bool dragEnabled) } /*! + \qmlproperty EventForward Qt3D.Render::ObjectPicker::eventForward + Holds the EventForward type. +*/ +/*! + \property Qt3DRender::QObjectPicker::eventForward + Holds the EventForward type. + */ +QEventForward *QObjectPicker::eventForward() const +{ + Q_D(const QObjectPicker); + return d->m_eventForward; +} + +void QObjectPicker::setEventForward(QEventForward *eventForward) +{ + Q_D(QObjectPicker); + if (d->m_eventForward != eventForward) { + if (d->m_eventForward) + d->unregisterDestructionHelper(d->m_eventForward); + d->m_eventForward = eventForward; + if (eventForward) { + if (eventForward->parent() == nullptr) + eventForward->setParent(this); + d->registerDestructionHelper(eventForward, &QObjectPicker::setEventForward, + d->m_eventForward); + } + emit eventForwardChanged(eventForward); + } +} + +/*! \qmlproperty bool Qt3D.Render::ObjectPicker::dragEnabled */ /*! @@ -402,6 +434,7 @@ Qt3DCore::QNodeCreatedChangeBasePtr QObjectPicker::createNodeCreationChange() co Q_D(const QObjectPicker); data.hoverEnabled = d->m_hoverEnabled; data.dragEnabled = d->m_dragEnabled; + data.eventForward = Qt3DCore::qIdForNode(d->m_eventForward); return creationChange; } diff --git a/src/render/picking/qobjectpicker.h b/src/render/picking/qobjectpicker.h index 950fff2cc..b00178851 100644 --- a/src/render/picking/qobjectpicker.h +++ b/src/render/picking/qobjectpicker.h @@ -41,6 +41,7 @@ #define QT3DRENDER_QOBJECTPICKER_H #include <Qt3DCore/qcomponent.h> +#include <Qt3DRender/qeventforward.h> #include <Qt3DRender/qt3drender_global.h> QT_BEGIN_NAMESPACE @@ -58,6 +59,7 @@ class QT3DRENDERSHARED_EXPORT QObjectPicker : public Qt3DCore::QComponent Q_PROPERTY(bool dragEnabled READ isDragEnabled WRITE setDragEnabled NOTIFY dragEnabledChanged) Q_PROPERTY(bool pressed READ isPressed NOTIFY pressedChanged) Q_PROPERTY(bool containsMouse READ containsMouse NOTIFY containsMouseChanged) + Q_PROPERTY(Qt3DRender::QEventForward *eventForward READ eventForward WRITE setEventForward NOTIFY eventForwardChanged) public: explicit QObjectPicker(QNode *parent = nullptr); @@ -69,9 +71,12 @@ public: bool containsMouse() const; bool isPressed() const; + QEventForward *eventForward() const; + public Q_SLOTS: void setHoverEnabled(bool hoverEnabled); void setDragEnabled(bool dragEnabled); + void setEventForward(QEventForward *eventForward); Q_SIGNALS: void pressed(Qt3DRender::QPickEvent *pick); @@ -84,6 +89,7 @@ Q_SIGNALS: void dragEnabledChanged(bool dragEnabled); void pressedChanged(bool pressed); void containsMouseChanged(bool containsMouse); + void eventForwardChanged(QEventForward *eventForward); protected: void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) Q_DECL_OVERRIDE; diff --git a/src/render/picking/qobjectpicker_p.h b/src/render/picking/qobjectpicker_p.h index 884e5673b..bddc213cc 100644 --- a/src/render/picking/qobjectpicker_p.h +++ b/src/render/picking/qobjectpicker_p.h @@ -68,6 +68,7 @@ public: , m_pressed(false) , m_containsMouse(false) , m_acceptedLastPressedEvent(true) + , m_eventForward(nullptr) { m_shareable = false; } @@ -78,6 +79,7 @@ public: bool m_pressed; bool m_containsMouse; bool m_acceptedLastPressedEvent; + QEventForward *m_eventForward; enum EventType { Pressed, @@ -101,6 +103,7 @@ struct QObjectPickerData { bool hoverEnabled; bool dragEnabled; + Qt3DCore::QNodeId eventForward; }; } // namespace Qt3DRender diff --git a/src/render/raycasting/qabstractcollisionqueryservice.cpp b/src/render/raycasting/qabstractcollisionqueryservice.cpp index 132af00c9..993ad840e 100644 --- a/src/render/raycasting/qabstractcollisionqueryservice.cpp +++ b/src/render/raycasting/qabstractcollisionqueryservice.cpp @@ -61,9 +61,11 @@ void QAbstractCollisionQueryService::setResultHandle(QCollisionQueryResult &resu result.d_func()->setHandle(handle); } -void QAbstractCollisionQueryService::addEntityHit(QCollisionQueryResult &result, Qt3DCore::QNodeId entity, const QVector3D& intersection, float distance) +void QAbstractCollisionQueryService::addEntityHit(QCollisionQueryResult &result, Qt3DCore::QNodeId entity, + const QVector3D& intersection, float distance, + const QVector3D& uvw) { - result.d_func()->addEntityHit(entity, intersection, distance); + result.d_func()->addEntityHit(entity, intersection, distance, uvw); } } // RayCasting diff --git a/src/render/raycasting/qabstractcollisionqueryservice_p.h b/src/render/raycasting/qabstractcollisionqueryservice_p.h index e2f9fb65a..806c33d5b 100644 --- a/src/render/raycasting/qabstractcollisionqueryservice_p.h +++ b/src/render/raycasting/qabstractcollisionqueryservice_p.h @@ -96,7 +96,8 @@ protected: QAbstractCollisionQueryService(QAbstractCollisionQueryServicePrivate &dd); void setResultHandle(QCollisionQueryResult &result, const QQueryHandle &handle); - void addEntityHit(QCollisionQueryResult &result, Qt3DCore::QNodeId entity, const QVector3D &intersection, float distance); + void addEntityHit(QCollisionQueryResult &result, Qt3DCore::QNodeId entity, const QVector3D &intersection, + float distance, const QVector3D &uvw); private: Q_DECLARE_PRIVATE(QAbstractCollisionQueryService) diff --git a/src/render/raycasting/qboundingvolume_p.h b/src/render/raycasting/qboundingvolume_p.h index f29d08d52..8267c2b18 100644 --- a/src/render/raycasting/qboundingvolume_p.h +++ b/src/render/raycasting/qboundingvolume_p.h @@ -72,7 +72,8 @@ public: }; virtual Qt3DCore::QNodeId id() const = 0; - virtual bool intersects(const QRay3D &ray, QVector3D *q = nullptr) const = 0; + virtual bool intersects(const QRay3D &ray, QVector3D *q = nullptr, + QVector3D *uvw = nullptr) const = 0; virtual Type type() const = 0; }; diff --git a/src/render/raycasting/qcollisionqueryresult.cpp b/src/render/raycasting/qcollisionqueryresult.cpp index 4d887d287..62975200c 100644 --- a/src/render/raycasting/qcollisionqueryresult.cpp +++ b/src/render/raycasting/qcollisionqueryresult.cpp @@ -56,9 +56,10 @@ QCollisionQueryResultPrivate::QCollisionQueryResultPrivate(const QCollisionQuery { } -void QCollisionQueryResultPrivate::addEntityHit(Qt3DCore::QNodeId entity, const QVector3D& intersection, float distance) +void QCollisionQueryResultPrivate::addEntityHit(Qt3DCore::QNodeId entity, const QVector3D& intersection, + float distance, const QVector3D& uvw) { - m_hits.append(QCollisionQueryResult::Hit(entity, intersection, distance)); + m_hits.append(QCollisionQueryResult::Hit(entity, intersection, distance, uvw)); } void QCollisionQueryResultPrivate::setHandle(const QQueryHandle &handle) diff --git a/src/render/raycasting/qcollisionqueryresult_p.h b/src/render/raycasting/qcollisionqueryresult_p.h index 18b45370a..e13dda74a 100644 --- a/src/render/raycasting/qcollisionqueryresult_p.h +++ b/src/render/raycasting/qcollisionqueryresult_p.h @@ -69,13 +69,27 @@ class QT3DRENDERSHARED_EXPORT QCollisionQueryResult { public: struct Hit { - Hit() : m_distance(-1.f), m_triangleIndex(0) { m_vertexIndex[0] = m_vertexIndex[1] = m_vertexIndex[2] = 0; } - Hit(const Qt3DCore::QNodeId &entity, const QVector3D &intersection, float distance) : m_entityId(entity), m_intersection(intersection), m_distance(distance) { } + Hit() + : m_distance(-1.f) + , m_triangleIndex(0) + { + m_vertexIndex[0] = m_vertexIndex[1] = m_vertexIndex[2] = 0; + } + + Hit(Qt3DCore::QNodeId entity, const QVector3D &intersection, float distance, const QVector3D &uvw) + : m_entityId(entity) + , m_intersection(intersection) + , m_distance(distance) + , m_uvw(uvw) + { + } + Qt3DCore::QNodeId m_entityId; QVector3D m_intersection; float m_distance; uint m_triangleIndex; uint m_vertexIndex[3]; + QVector3D m_uvw; }; QCollisionQueryResult(); @@ -123,7 +137,8 @@ public: explicit QCollisionQueryResultPrivate(const QCollisionQueryResultPrivate ©); void setHandle(const QQueryHandle &handle); - void addEntityHit(Qt3DCore::QNodeId entity, const QVector3D& intersection, float distance); + void addEntityHit(Qt3DCore::QNodeId entity, const QVector3D& intersection, float distance, + const QVector3D& uvw); QQueryHandle m_handle; QVector<QCollisionQueryResult::Hit> m_hits; diff --git a/src/render/raycasting/qraycastingservice.cpp b/src/render/raycasting/qraycastingservice.cpp index e92234836..e0c7b6199 100644 --- a/src/render/raycasting/qraycastingservice.cpp +++ b/src/render/raycasting/qraycastingservice.cpp @@ -68,6 +68,7 @@ struct Hit float distance; Qt3DCore::QNodeId id; QVector3D intersection; + QVector3D uvw; }; bool compareHitsDistance(const Hit &a, const Hit &b) @@ -78,7 +79,7 @@ bool compareHitsDistance(const Hit &a, const Hit &b) Hit volumeRayIntersection(const QBoundingVolume *volume, const QRay3D &ray) { Hit hit; - if ((hit.intersects = volume->intersects(ray, &hit.intersection))) { + if ((hit.intersects = volume->intersects(ray, &hit.intersection, &hit.uvw))) { hit.distance = ray.projectedDistance(hit.intersection); hit.id = volume->id(); } @@ -134,12 +135,12 @@ QCollisionQueryResult QRayCastingServicePrivate::collides(const QRay3D &ray, QBo if (mode == QAbstractCollisionQueryService::FirstHit) { Hit firstHit = QtConcurrent::blockingMappedReduced<Hit>(volumes, gathererFunctor, reduceToFirstHit); if (firstHit.intersects) - q->addEntityHit(result, firstHit.id, firstHit.intersection, firstHit.distance); + q->addEntityHit(result, firstHit.id, firstHit.intersection, firstHit.distance, firstHit.uvw); } else { QVector<Hit> hits = QtConcurrent::blockingMappedReduced<QVector<Hit> >(volumes, gathererFunctor, reduceToAllHits); std::sort(hits.begin(), hits.end(), compareHitsDistance); for (const Hit &hit : qAsConst(hits)) - q->addEntityHit(result, hit.id, hit.intersection, hit.distance); + q->addEntityHit(result, hit.id, hit.intersection, hit.distance, hit.uvw); } return result; @@ -154,6 +155,7 @@ QCollisionQueryResult::Hit QRayCastingServicePrivate::collides(const QRay3D &ray result.m_distance = hit.distance; result.m_entityId = hit.id; result.m_intersection = hit.intersection; + result.m_uvw = hit.uvw; } return result; } diff --git a/src/render/render.pro b/src/render/render.pro index 1b90af82f..c31db94b7 100644 --- a/src/render/render.pro +++ b/src/render/render.pro @@ -41,6 +41,7 @@ SOURCES += \ MODULE_PLUGIN_TYPES = \ sceneparsers \ - geometryloaders + geometryloaders \ + renderplugins load(qt_module) diff --git a/src/render/texture/gltexture_p.h b/src/render/texture/gltexture_p.h index 424e77854..d9ce32a9f 100644 --- a/src/render/texture/gltexture_p.h +++ b/src/render/texture/gltexture_p.h @@ -148,6 +148,16 @@ public: m_dirty |= TextureData; } + bool isDirty() + { + QMutexLocker locker(&m_dirtyFlagMutex); + return m_dirty == 0 ? false : true; + } + + QMutex *textureLock() + { + return &m_dirtyFlagMutex; + } protected: template<class APITexture, class APITextureImage> diff --git a/src/src.pro b/src/src.pro index afccd4ff7..0055274e0 100644 --- a/src/src.pro +++ b/src/src.pro @@ -71,6 +71,11 @@ src_plugins_geometryloaders.file = $$PWD/plugins/geometryloaders/geometryloaders src_plugins_geometryloaders.target = sub-plugins-geometryloaders src_plugins_geometryloaders.depends = src_render src_extras +# Qt3D Render plugins +src_plugins_render.file = $$PWD/plugins/renderplugins/renderplugins.pro +src_plugins_render.target = sub-plugins-render +src_plugins_render.depends = src_render src_extras src_quick3d_render + SUBDIRS += \ src_core \ src_render \ @@ -89,6 +94,5 @@ SUBDIRS += \ src_quick3d_imports_extras \ src_plugins_sceneparsers \ src_plugins_geometryloaders \ + src_plugins_render \ doc - - |