summaryrefslogtreecommitdiffstats
path: root/src/api/studio3dqml
diff options
context:
space:
mode:
Diffstat (limited to 'src/api/studio3dqml')
-rw-r--r--src/api/studio3dqml/q3dsplugin.cpp62
-rw-r--r--src/api/studio3dqml/q3dsplugin.h60
-rw-r--r--src/api/studio3dqml/q3dspresentationitem.cpp160
-rw-r--r--src/api/studio3dqml/q3dspresentationitem_p.h76
-rw-r--r--src/api/studio3dqml/q3dsrenderer.cpp458
-rw-r--r--src/api/studio3dqml/q3dsrenderer_p.h110
-rw-r--r--src/api/studio3dqml/q3dsstudio3d.cpp535
-rw-r--r--src/api/studio3dqml/q3dsstudio3d_p.h137
-rw-r--r--src/api/studio3dqml/qmldir3
-rw-r--r--src/api/studio3dqml/studio3dqml.pro34
10 files changed, 1635 insertions, 0 deletions
diff --git a/src/api/studio3dqml/q3dsplugin.cpp b/src/api/studio3dqml/q3dsplugin.cpp
new file mode 100644
index 0000000..640018f
--- /dev/null
+++ b/src/api/studio3dqml/q3dsplugin.cpp
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 NVIDIA CORPORATION.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) 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.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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "q3dsplugin.h"
+
+#include <QtQml/qqml.h>
+
+#include <QtStudio3D/private/q3dsviewersettings_p.h>
+
+#include "q3dsstudio3d_p.h"
+#include "q3dspresentationitem_p.h"
+#include "q3dsqmlstream.h"
+#include "q3dsqmlsubpresentationsettings.h"
+#include "q3dssceneelement.h"
+#include "q3dsdatainput.h"
+
+QT_BEGIN_NAMESPACE
+
+void Q3DSPlugin::registerTypes(const char *uri)
+{
+ Q_ASSERT(uri == QLatin1String("QtStudio3D.OpenGL"));
+
+ // @uri QtStudio3D.OpenGL
+ qmlRegisterType<Q3DSStudio3D>(uri, 2, 4, "Studio3D");
+ qmlRegisterType<Q3DSViewerSettings>(uri, 2, 4, "ViewerSettings");
+ qmlRegisterType<Q3DSPresentationItem>(uri, 2, 4, "Presentation");
+ qmlRegisterType<Q3DSSceneElement>(uri, 2, 4, "SceneElement");
+ qmlRegisterType<Q3DSElement>(uri, 2, 4, "Element");
+ qmlRegisterType<Q3DSQmlStream>(uri, 2, 4, "QmlStream");
+ qmlRegisterType<Q3DSSubPresentationSettings>(uri, 2, 4, "SubPresentationSettings");
+ qmlRegisterType<Q3DSDataInput>(uri, 2, 4, "DataInput");
+ qmlRegisterType<Q3DSDataOutput>(uri, 2, 4, "DataOutput");
+}
+
+QT_END_NAMESPACE
diff --git a/src/api/studio3dqml/q3dsplugin.h b/src/api/studio3dqml/q3dsplugin.h
new file mode 100644
index 0000000..04f6942
--- /dev/null
+++ b/src/api/studio3dqml/q3dsplugin.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 NVIDIA CORPORATION.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) 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.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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3DS_PLUGIN_H
+#define Q3DS_PLUGIN_H
+
+#include <QtQml/qqmlextensionplugin.h>
+
+static void initResources()
+{
+#ifdef QT_STATIC
+ Q_INIT_RESOURCE(qmake_QtStudio3D_OpenGL);
+#endif
+}
+
+QT_BEGIN_NAMESPACE
+
+class Q3DSPlugin : public QQmlExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
+
+public:
+ Q3DSPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent)
+ {
+ initResources();
+ }
+ void registerTypes(const char *uri) override;
+};
+
+QT_END_NAMESPACE
+
+#endif // Q3DS_PLUGIN_H
diff --git a/src/api/studio3dqml/q3dspresentationitem.cpp b/src/api/studio3dqml/q3dspresentationitem.cpp
new file mode 100644
index 0000000..6372f2f
--- /dev/null
+++ b/src/api/studio3dqml/q3dspresentationitem.cpp
@@ -0,0 +1,160 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) 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.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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "q3dspresentationitem_p.h"
+
+#include <QtStudio3D/q3dssceneelement.h>
+#include <QtStudio3D/q3dsdatainput.h>
+#include <QtStudio3D/private/q3dspresentation_p.h>
+#include <QtStudio3D/private/viewerqmlstreamproxy_p.h>
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Presentation
+ \instantiates Q3DSPresentationItem
+ \inqmlmodule QtStudio3D
+ \ingroup OpenGLRuntime
+ \inherits Q3DSPresentation
+ \keyword Studio3D
+
+ \brief Represents a Qt 3D Studio presentation.
+
+ This item provides properties and methods for controlling a
+ presentation.
+
+ Qt 3D Studio supports multiple presentations in one project. There
+ is always a main presentation and zero or more
+ sub-presentations. The sub-presentations are composed into the
+ main presentations either as contents of Qt 3D Studio layers or as
+ texture maps.
+
+ In the filesystem each presentation corresponds to one \c{.uip}
+ presentation file. When present, the \c{.uia} project file ties
+ these together by specifying a name for each of the
+ (sub-)presentations and specifies which one is the main one.
+
+ The \c{.uia} project also defines \l{DataInput}s and
+ \l{DataOutput}s that are exported by the presentations.
+ \l{DataInput}s provide a way to provide input to the presentation
+ to e.g. control a timeline of a subpresentation from code.
+ \l{DataOutput}s provide a way to get notified when an attribute
+ is changed in the presentation by animation timeline,
+ by behavior scripts or by a \l{DataInput}.
+
+ The Presentation type handles child objects of the types \l Element, \l
+ SceneElement, \l DataInput, and \l SubPresentationSettings specially. These
+ will get automatically associated with the presentation and can control
+ certain aspects of it from that point on.
+
+ From the API point of view Presentation corresponds to the
+ main presentation. The source property can refer either to a
+ \c{.uia} or \c{.uip} file. When specifying a file with \c{.uip}
+ extension and a \c{.uia} is present with the same name, the
+ \c{.uia} is loaded automatically and thus sub-presentation
+ information is available regardless.
+ */
+Q3DSPresentationItem::Q3DSPresentationItem(QObject *parent)
+ : Q3DSPresentation(parent)
+ , m_subPresentationSettings(nullptr)
+{
+}
+
+Q3DSPresentationItem::~Q3DSPresentationItem()
+{
+}
+
+/*!
+ Returns the \l SubPresentationSettings associated with this presentation.
+*/
+Q3DSSubPresentationSettings *Q3DSPresentationItem::subPresentationSettings() const
+{
+ return m_subPresentationSettings;
+}
+
+QQmlListProperty<QObject> Q3DSPresentationItem::qmlChildren()
+{
+ return QQmlListProperty<QObject>(this, nullptr, &appendQmlChildren, nullptr, nullptr, nullptr);
+}
+
+void Q3DSPresentationItem::appendQmlChildren(QQmlListProperty<QObject> *list, QObject *obj)
+{
+ auto item = qobject_cast<Q3DSPresentationItem *>(list->object);
+ if (item) {
+ auto scene = qobject_cast<Q3DSSceneElement *>(obj);
+ if (scene) {
+ if (item->registeredElement(scene->elementPath()))
+ qWarning() << __FUNCTION__ << "A duplicate SceneElement defined for Presentation.";
+ else
+ item->registerElement(scene);
+ } else {
+ auto studioElement = qobject_cast<Q3DSElement *>(obj);
+ if (studioElement) {
+ if (item->registeredElement(studioElement->elementPath()))
+ qWarning() << __FUNCTION__ << "A duplicate Element defined for Presentation.";
+ else
+ item->registerElement(studioElement);
+ } else {
+ auto subPresSettings = qobject_cast<Q3DSSubPresentationSettings *>(obj);
+ if (subPresSettings) {
+ if (item->m_subPresentationSettings) {
+ qWarning() << __FUNCTION__
+ << "Duplicate SubPresentationSettings defined for Presentation.";
+ } else {
+ item->m_subPresentationSettings = subPresSettings;
+ item->d_ptr->streamProxy()->setSettings(subPresSettings);
+ }
+ } else {
+ auto dataInput = qobject_cast<Q3DSDataInput *>(obj);
+ if (dataInput) {
+ if (item->registeredDataInput(dataInput->name())) {
+ qWarning() << __FUNCTION__
+ << "Duplicate DataInput defined for Presentation.";
+ } else {
+ item->registerDataInput(dataInput);
+ }
+ } else {
+ auto dataOutput = qobject_cast<Q3DSDataOutput *>(obj);
+ if (dataOutput) {
+ if (item->registeredDataOutput(dataOutput->name())) {
+ qWarning() << __FUNCTION__
+ << "Duplicate DataOutput defined for Presentation.";
+ } else {
+ item->registerDataOutput(dataOutput);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/api/studio3dqml/q3dspresentationitem_p.h b/src/api/studio3dqml/q3dspresentationitem_p.h
new file mode 100644
index 0000000..216f73a
--- /dev/null
+++ b/src/api/studio3dqml/q3dspresentationitem_p.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) 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.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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3DSPRESENTATIONITEM_H
+#define Q3DSPRESENTATIONITEM_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtStudio3D 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 "q3dsqmlsubpresentationsettings.h"
+
+#include <QtStudio3D/q3dspresentation.h>
+#include <QtQml/qqmllist.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q3DSPresentationItem : public Q3DSPresentation
+{
+ Q_OBJECT
+ Q_PROPERTY(QQmlListProperty<QObject> qmlChildren READ qmlChildren DESIGNABLE false)
+ Q_CLASSINFO("DefaultProperty", "qmlChildren")
+
+public:
+ explicit Q3DSPresentationItem(QObject *parent = nullptr);
+ ~Q3DSPresentationItem();
+
+ Q3DSSubPresentationSettings *subPresentationSettings() const;
+
+ QQmlListProperty<QObject> qmlChildren();
+
+public Q_SLOTS:
+ static void appendQmlChildren(QQmlListProperty<QObject> *list, QObject *obj);
+
+private:
+ Q3DSSubPresentationSettings *m_subPresentationSettings;
+
+ friend class Q3DSStudio3D;
+};
+
+QT_END_NAMESPACE
+
+#endif // Q3DSPRESENTATIONITEM_H
diff --git a/src/api/studio3dqml/q3dsrenderer.cpp b/src/api/studio3dqml/q3dsrenderer.cpp
new file mode 100644
index 0000000..7366d6a
--- /dev/null
+++ b/src/api/studio3dqml/q3dsrenderer.cpp
@@ -0,0 +1,458 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 NVIDIA CORPORATION.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) 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.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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "q3dsrenderer_p.h"
+#include "Qt3DSViewerApp.h"
+#include "Qt3DSAudioPlayerImpl.h"
+#include "q3dspresentationitem_p.h"
+
+#include <QtStudio3D/private/q3dscommandqueue_p.h>
+#include <QtStudio3D/private/q3dsviewersettings_p.h>
+#include <QtStudio3D/private/q3dspresentation_p.h>
+#include <QtStudio3D/private/studioutils_p.h>
+#include <QtStudio3D/private/q3dsdatainput_p.h>
+
+#include <QtCore/qdebug.h>
+#include <QtGui/qwindow.h>
+#include <QtGui/qopenglcontext.h>
+#include <QtQuick/qquickwindow.h>
+
+using namespace Q3DSViewer;
+
+QT_BEGIN_NAMESPACE
+
+Q3DSRenderer::Q3DSRenderer(bool visibleFlag, qt3ds::Qt3DSAssetVisitor *assetVisitor)
+ : m_visibleFlag(visibleFlag)
+ , m_initElements(false)
+ , m_runtime(0)
+ , m_window(nullptr)
+ , m_initialized(false)
+ , m_initializationFailure(false)
+ , m_visitor(assetVisitor)
+ , m_settings(new Q3DSViewerSettings(this))
+ , m_presentation(new Q3DSPresentation(this))
+{
+ m_startupTimer.start();
+}
+
+Q3DSRenderer::~Q3DSRenderer()
+{
+ releaseRuntime();
+}
+
+QOpenGLFramebufferObject *Q3DSRenderer::createFramebufferObject(const QSize &size)
+{
+ QOpenGLFramebufferObjectFormat theFormat;
+ theFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
+ QOpenGLFramebufferObject *frameBuffer =
+ new QOpenGLFramebufferObject(size, theFormat);
+ if (m_runtime && m_runtime->IsInitialised())
+ m_runtime->setOffscreenId(frameBuffer->handle());
+ return frameBuffer;
+}
+
+/** Pull pending commands from the plugin.
+ * Invoked automatically by the QML scene graph.
+ *
+ * This is the only place where it is valid for the Q3DSStudio3D plugin and render to communicate.
+ */
+void Q3DSRenderer::synchronize(QQuickFramebufferObject *inView)
+{
+ // Passing m_InitElements here is a bit of a hack to easily set the flag on the plugin.
+ static_cast<Q3DSStudio3D *>(inView)->getCommands(m_initElements, m_commands);
+
+ if (m_initializationFailure)
+ static_cast<Q3DSStudio3D *>(inView)->setError(m_error);
+
+ if (m_commands.m_sourceChanged || m_commands.m_variantListChanged) {
+ releaseRuntime();
+ // Need to update source and variant list here rather than
+ // processCommands, as both are needed for init
+ m_presentation->setVariantList(m_commands.m_variantList);
+ m_presentation->setSource(m_commands.m_source);
+ m_presentation->setDelayedLoading(m_commands.m_delayedLoading);
+ m_initialized = false;
+ m_initializationFailure = false;
+ m_error.clear();
+ static_cast<Q3DSStudio3D *>(inView)->setError(QString());
+ }
+
+ m_initElements = false;
+
+ // We need a handle to the window to be able to reset the GL state inside of Draw().
+ // See https://bugreports.qt.io/browse/QTBUG-47213
+ if (!m_window)
+ m_window = inView->window();
+}
+
+void Q3DSRenderer::releaseRuntime()
+{
+ m_settings->d_ptr->setViewerApp(nullptr);
+ m_presentation->d_ptr->setViewerApp(nullptr);
+
+ if (m_runtime) {
+ m_runtime->Release();
+ m_runtime = nullptr;
+ }
+}
+
+/** Invoked by the QML scene graph indicating that it's time to render.
+ * Calls `draw()` if the plugin is visible, or `processCommands()` otherwise.
+ *
+ * Note that this will still render if the plugin is opacity:0. To avoid this,
+ * add a line to your QML to hide the object when opacity is zero, like:
+ *
+ * visible: opacity != 0
+ */
+void Q3DSRenderer::render()
+{
+ // We may start in a non visible state but we still need
+ // to init the runtime otherwise the commands are never processed
+ if (!m_initialized && !m_initializationFailure) {
+ m_initialized = initializeRuntime(this->framebufferObject());
+ m_initializationFailure = !m_initialized;
+ if (m_initializationFailure)
+ m_commands.clear(true);
+ }
+
+ // Don't render if the plugin is hidden; however, if hidden, but sure
+ // to process pending commands so we can be shown again.
+ if (m_initialized) {
+ if (m_visibleFlag)
+ draw();
+ else
+ processCommands();
+ update(); // mark as dirty to ensure update again
+ }
+}
+
+/** Cause Qt3DS runtime to render content.
+ * Initializes GL and the runtime when called the first time.
+ */
+void Q3DSRenderer::draw()
+{
+ if (m_runtime && m_runtime->IsInitialised() && m_window) {
+ if (m_initialized)
+ m_runtime->RestoreState();
+ m_runtime->Render();
+ m_runtime->SaveState();
+
+ m_window->resetOpenGLState();
+ }
+}
+
+bool Q3DSRenderer::initializeRuntime(QOpenGLFramebufferObject *inFbo)
+{
+ m_runtime = &Q3DSViewerApp::Create(nullptr, new Qt3DSAudioPlayerImpl(), &m_startupTimer);
+ Q_ASSERT(m_runtime);
+
+ // Connect presentation ready signal before initializing the app
+ connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigPresentationReady,
+ this, &Q3DSRenderer::presentationReady);
+ connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigPresentationLoaded,
+ this, &Q3DSRenderer::presentationLoaded);
+
+ int theWidth = inFbo->width();
+ int theHeight = inFbo->height();
+
+ const QString localSource = Q3DSUtils::urlToLocalFileOrQrc(m_presentation->source());
+
+ if (!m_runtime->InitializeApp(theWidth, theHeight,
+ QOpenGLContext::currentContext()->format(),
+ inFbo->handle(), localSource,
+ m_presentation->variantList(),
+ m_presentation->delayedLoading(),
+ m_visitor)) {
+ m_error = m_runtime->error();
+ releaseRuntime();
+ return false;
+ }
+
+ m_runtime->RegisterScriptCallback(Q3DSViewer::ViewerCallbackType::Enum::CALLBACK_ON_INIT,
+ reinterpret_cast<qml_Function>(Q3DSRenderer::onInitHandler),
+ this);
+ m_runtime->RegisterScriptCallback(Q3DSViewer::ViewerCallbackType::Enum::CALLBACK_ON_UPDATE,
+ reinterpret_cast<qml_Function>(Q3DSRenderer::onUpdateHandler),
+ this);
+
+ m_settings->d_ptr->setViewerApp(m_runtime);
+ m_presentation->d_ptr->setViewerApp(m_runtime, false);
+
+ // Connect signals
+ connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigSlideEntered,
+ this, &Q3DSRenderer::enterSlide);
+ connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigSlideExited,
+ this, &Q3DSRenderer::exitSlide);
+ connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigCustomSignal,
+ this, &Q3DSRenderer::customSignalEmitted);
+ connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigElementsCreated,
+ this, &Q3DSRenderer::elementsCreated);
+ connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigMaterialsCreated,
+ this, &Q3DSRenderer::materialsCreated);
+ connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigMeshesCreated,
+ this, &Q3DSRenderer::meshesCreated);
+ connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigDataOutputValueUpdated,
+ this, &Q3DSRenderer::dataOutputValueUpdated);
+
+ return true;
+}
+
+/** Accept user commands (e.g. setAttribute) needed to initialize the code.
+ *
+ * If we attempt to run Qt3DS methods like setAttribute() before the runtime
+ * has been initialized, they will be lost. This method is the correct place
+ * to accept user commands.
+ *
+ * Currently this method just sets a flag needed to pass a flag to the
+ * plugin next time syncronize() is called, which eventually gets the plugin
+ * to emit an `runningChanged` signal the next time `tick()` is called.
+ * As a result, code specified in an `onRunningChanged` handler may be run
+ * after one or more frames have already rendered.
+ */
+void Q3DSRenderer::onInitHandler(void *userData)
+{
+ Q3DSRenderer *theRenderer = static_cast<Q3DSRenderer *>(userData);
+ theRenderer->setInitElements(true);
+}
+
+/** Accept the latest pending user commands (e.g. setAttribute).
+ *
+ * This method just calls `ProcessCommands` to avoid unnecessary
+ * pointer dereferencing and accessor methods (or public member variables).
+ */
+void Q3DSRenderer::onUpdateHandler(void *userData)
+{
+ Q3DSRenderer *theRenderer = static_cast<Q3DSRenderer *>(userData);
+ theRenderer->processCommands();
+}
+
+/** Apply commands queued up by the user (e.g. setAttribute).
+ *
+ * Note that these commands are executed even if the plugin is not visible,
+ * in part to allow changes to the visible flag to be noticed, but also
+ * to allow specialty code to continue to be queued up even when not rendering.
+ */
+void Q3DSRenderer::processCommands()
+{
+ if (!m_runtime) {
+ m_commands.clear(true);
+ return;
+ }
+
+ if (m_commands.m_visibleChanged)
+ m_visibleFlag = m_commands.m_visible;
+
+ if (QOpenGLFramebufferObject *inFbo = this->framebufferObject()) {
+ if (inFbo->isValid() && (inFbo->width() != m_runtime->GetWindowWidth()
+ || inFbo->height() != m_runtime->GetWindowHeight())) {
+ m_runtime->Resize(inFbo->width(), inFbo->height());
+ }
+ }
+
+ if (m_commands.m_scaleModeChanged)
+ m_settings->setScaleMode(m_commands.m_scaleMode);
+ if (m_commands.m_shadeModeChanged)
+ m_settings->setShadeMode(m_commands.m_shadeMode);
+ if (m_commands.m_matteColorChanged)
+ m_settings->setMatteColor(m_commands.m_matteColor);
+ if (m_commands.m_showRenderStatsChanged)
+ m_settings->setShowRenderStats(m_commands.m_showRenderStats);
+ if (m_commands.m_delayedLoadingChanged)
+ this->m_runtime->setDelayedLoading(m_commands.m_delayedLoading);
+
+ if (m_commands.m_globalAnimationTimeChanged)
+ m_presentation->setGlobalAnimationTime(m_commands.m_globalAnimationTime);
+
+ // Send scene graph changes over to Q3DS
+ for (int i = 0; i < m_commands.size(); i++) {
+ const ElementCommand &cmd = m_commands.constCommandAt(i);
+ switch (cmd.m_commandType) {
+ case CommandType_SetAttribute:
+ m_presentation->setAttribute(cmd.m_elementPath, cmd.m_stringValue, cmd.m_variantValue);
+ break;
+ case CommandType_SetPresentationActive:
+ m_presentation->setPresentationActive(cmd.m_elementPath, cmd.m_boolValue);
+ break;
+ case CommandType_GoToTime:
+ m_presentation->goToTime(cmd.m_elementPath, cmd.m_floatValue);
+ break;
+ case CommandType_GoToSlide:
+ m_presentation->goToSlide(cmd.m_elementPath, cmd.m_intValues[0]);
+ break;
+ case CommandType_GoToSlideByName:
+ m_presentation->goToSlide(cmd.m_elementPath, cmd.m_stringValue);
+ break;
+ case CommandType_GoToSlideRelative:
+ m_presentation->goToSlide(cmd.m_elementPath, bool(cmd.m_intValues[0]),
+ bool(cmd.m_intValues[1]));
+ break;
+ case CommandType_FireEvent:
+ m_presentation->fireEvent(cmd.m_elementPath, cmd.m_stringValue);
+ break;
+ case CommandType_MousePress:
+ m_runtime->HandleMousePress(cmd.m_intValues[0],
+ cmd.m_intValues[1], cmd.m_intValues[2], true);
+ break;
+ case CommandType_MouseRelease:
+ m_runtime->HandleMousePress(cmd.m_intValues[0],
+ cmd.m_intValues[1], cmd.m_intValues[2], false);
+ break;
+ case CommandType_MouseMove:
+ m_runtime->HandleMouseMove(cmd.m_intValues[0], cmd.m_intValues[1], true);
+ break;
+ case CommandType_MouseWheel:
+ m_runtime->HandleMouseWheel(cmd.m_intValues[0], cmd.m_intValues[1],
+ bool(cmd.m_intValues[2]), cmd.m_intValues[3]);
+ break;
+ case CommandType_KeyPress:
+ m_runtime->HandleKeyInput(Q3DStudio::EKeyCode(cmd.m_intValues[0]), true);
+ break;
+ case CommandType_KeyRelease:
+ m_runtime->HandleKeyInput(Q3DStudio::EKeyCode(cmd.m_intValues[0]), false);
+ break;
+ case CommandType_SetDataInputValue:
+ m_runtime->SetDataInputValue(
+ cmd.m_stringValue, cmd.m_variantValue,
+ static_cast<qt3ds::runtime::DataInputValueRole>(cmd.m_intValues[0]));
+ break;
+ case CommandType_CreateElements: {
+ m_runtime->createElements(
+ cmd.m_elementPath, cmd.m_stringValue,
+ *static_cast<QVector<QHash<QString, QVariant>> *>(cmd.m_data));
+ // Runtime makes copy of the data in its own format, so we can delete it now
+ auto &command = m_commands.commandAt(i);
+ delete reinterpret_cast<QVector<QHash<QString, QVariant>> *>(command.m_data);
+ command.m_data = nullptr;
+ break;
+ }
+ case CommandType_DeleteElements: {
+ m_runtime->deleteElements(*static_cast<QStringList *>(cmd.m_data));
+ // Runtime makes copy of the data in its own format, so we can delete it now
+ auto &command = m_commands.commandAt(i);
+ delete reinterpret_cast<QStringList *>(command.m_data);
+ command.m_data = nullptr;
+ break;
+ }
+ case CommandType_CreateMaterials: {
+ m_runtime->createMaterials(cmd.m_elementPath, *static_cast<QStringList *>(cmd.m_data));
+ // Runtime makes copy of the data in its own format, so we can delete it now
+ auto &command = m_commands.commandAt(i);
+ delete reinterpret_cast<QStringList *>(command.m_data);
+ command.m_data = nullptr;
+ break;
+ }
+ case CommandType_DeleteMaterials: {
+ m_runtime->deleteMaterials(*static_cast<QStringList *>(cmd.m_data));
+ // Runtime makes copy of the data in its own format, so we can delete it now
+ auto &command = m_commands.commandAt(i);
+ delete reinterpret_cast<QStringList *>(command.m_data);
+ command.m_data = nullptr;
+ break;
+ }
+ case CommandType_CreateMeshes: {
+ m_runtime->createMeshes(*static_cast<QHash<QString, Q3DSViewer::MeshData> *>(
+ cmd.m_data));
+ // Runtime makes copy of the data, so we can delete it now
+ auto &command = m_commands.commandAt(i);
+ auto meshData = reinterpret_cast<QHash<QString, Q3DSViewer::MeshData> *>(
+ command.m_data);
+ delete meshData;
+ command.m_data = nullptr;
+ break;
+ }
+ case CommandType_DeleteMeshes: {
+ m_runtime->deleteMeshes(*static_cast<QStringList *>(cmd.m_data));
+ // Runtime makes copy of the data in its own format, so we can delete it now
+ auto &command = m_commands.commandAt(i);
+ delete reinterpret_cast<QStringList *>(command.m_data);
+ command.m_data = nullptr;
+ break;
+ }
+ case CommandType_RequestSlideInfo: {
+ int current = 0;
+ int previous = 0;
+ QString currentName;
+ QString previousName;
+ const QByteArray path(cmd.m_elementPath.toUtf8());
+ m_runtime->GetSlideInfo(path, current, previous, currentName, previousName);
+ QVariantList *requestData = new QVariantList();
+ requestData->append(QVariant(current));
+ requestData->append(QVariant(previous));
+ requestData->append(QVariant(currentName));
+ requestData->append(QVariant(previousName));
+
+ Q_EMIT requestResponse(cmd.m_elementPath, cmd.m_commandType, requestData);
+
+ break;
+ }
+ case CommandType_RequestDataInputs: {
+ QVariantList *requestData = new QVariantList();
+ if (m_runtime) {
+ const auto diList = m_runtime->dataInputs();
+
+ for (const auto &it : diList) {
+ Q3DSDataInput *newIt = new Q3DSDataInput(it, nullptr);
+ newIt->d_ptr->m_max = m_runtime->dataInputMax(it);
+ newIt->d_ptr->m_min = m_runtime->dataInputMin(it);
+ newIt->d_ptr->m_metadata = m_runtime->dataInputMetadata(it);
+ requestData->append(QVariant::fromValue(newIt));
+ }
+ }
+
+ Q_EMIT requestResponse(cmd.m_elementPath, cmd.m_commandType, requestData);
+ break;
+ }
+ case CommandType_RequestDataOutputs: {
+ QVariantList *requestData = new QVariantList();
+ if (m_presentation) {
+ const auto diList = m_presentation->dataOutputs();
+
+ for (const auto &it : diList)
+ requestData->append(QVariant::fromValue(it->name()));
+ }
+
+ Q_EMIT requestResponse(cmd.m_elementPath, cmd.m_commandType, requestData);
+ break;
+ }
+ case CommandType_PreloadSlide:
+ m_runtime->preloadSlide(cmd.m_elementPath);
+ break;
+ case CommandType_UnloadSlide:
+ m_runtime->unloadSlide(cmd.m_elementPath);
+ break;
+ default:
+ qWarning() << __FUNCTION__ << "Unrecognized CommandType in command list!";
+ }
+ }
+
+ m_commands.clear(false);
+}
+
+QT_END_NAMESPACE
diff --git a/src/api/studio3dqml/q3dsrenderer_p.h b/src/api/studio3dqml/q3dsrenderer_p.h
new file mode 100644
index 0000000..6d044ff
--- /dev/null
+++ b/src/api/studio3dqml/q3dsrenderer_p.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 NVIDIA CORPORATION.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) 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.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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3DS_RENDERER_H
+#define Q3DS_RENDERER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtStudio3D 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 <QtGui/qopenglframebufferobject.h>
+#include <QtQuick/qquickframebufferobject.h>
+
+#include "Qt3DSViewerApp.h"
+#include "q3dsstudio3d_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q3DSViewerSettings;
+class Q3DSPresentation;
+
+class Q3DSRenderer : public QObject,
+ public QQuickFramebufferObject::Renderer
+{
+ Q_OBJECT
+
+public:
+ Q3DSRenderer(bool visibleFlag, qt3ds::Qt3DSAssetVisitor *assetVisitor);
+ ~Q3DSRenderer();
+
+ QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) override;
+
+ void setInitElements(bool inFlag) { m_initElements = inFlag; }
+ void processCommands();
+
+Q_SIGNALS:
+ void enterSlide(const QString &elementPath, unsigned int slide, const QString &slideName);
+ void exitSlide(const QString &elementPath, unsigned int slide, const QString &slideName);
+ void requestResponse(const QString &elementPath, CommandType commandType, void *requestData);
+ void presentationReady();
+ void presentationLoaded();
+ void customSignalEmitted(const QString &elNmentPath, const QString &name);
+ void elementsCreated(const QStringList &elementPaths, const QString &error);
+ void materialsCreated(const QStringList &materialNames, const QString &error);
+ void meshesCreated(const QStringList &meshNames, const QString &error);
+ void dataOutputValueUpdated(const QString &name, const QVariant &newValue);
+
+protected:
+ static void onInitHandler(void *userData);
+ static void onUpdateHandler(void *userData);
+ bool initializeRuntime(QOpenGLFramebufferObject *inFbo);
+ void draw();
+ void render() override;
+ void synchronize(QQuickFramebufferObject *inView) override;
+ void releaseRuntime();
+
+protected:
+ bool m_visibleFlag; // Is the plugin visible? Prevents rendering hidden content.
+ CommandQueue m_commands; // A list of commands retrieved by the plugin to be applied.
+ bool m_initElements; // Flag set when the runtime is first ready to render.
+ Q3DSViewer::Q3DSViewerApp *m_runtime; // The Qt3DS viewer that renders all content.
+ QQuickWindow *m_window; // Window associated with the plugin; needed to reset OpenGL state.
+
+ bool m_initialized; // Has the runtime and OpenGL state been initialized?
+ bool m_initializationFailure; // Initialization failed, no point in trying to init again
+ qt3ds::Qt3DSAssetVisitor *m_visitor;
+
+ Q3DSViewerSettings *m_settings;
+ Q3DSPresentation *m_presentation;
+ QString m_error;
+ QElapsedTimer m_startupTimer;
+};
+
+QT_END_NAMESPACE
+
+#endif // Q3DS_RENDERER_H
diff --git a/src/api/studio3dqml/q3dsstudio3d.cpp b/src/api/studio3dqml/q3dsstudio3d.cpp
new file mode 100644
index 0000000..5a46089
--- /dev/null
+++ b/src/api/studio3dqml/q3dsstudio3d.cpp
@@ -0,0 +1,535 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 NVIDIA CORPORATION.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) 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.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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "q3dsstudio3d_p.h"
+#include "q3dsrenderer_p.h"
+#include "q3dspresentationitem_p.h"
+
+#include <QtStudio3D/private/q3dsviewersettings_p.h>
+#include <QtStudio3D/private/q3dspresentation_p.h>
+#include <QtStudio3D/private/q3dssceneelement_p.h>
+#include <QtStudio3D/private/viewerqmlstreamproxy_p.h>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qfileinfo.h>
+#include <QtQuick/qquickwindow.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Studio3D
+ \instantiates Q3DSStudio3D
+ \inqmlmodule QtStudio3D
+ \ingroup OpenGLRuntime
+ \inherits Item
+ \keyword Studio3D
+
+ \brief Qt 3D Studio presentation viewer.
+
+ This type enables developers to embed Qt 3D Studio presentations in Qt
+ Quick.
+
+ \section2 Example Usage
+
+ \qml
+ Studio3D {
+ id: studio3D
+ anchors.fill: parent
+
+ Presentation {
+ source: "qrc:///presentation.uia"
+ SceneElement {
+ id: scene
+ elementPath: "Scene"
+ currentSlideIndex: 2
+ }
+ Element {
+ id: textLabel
+ elementPath: "Scene.Layer.myLabel"
+ }
+ }
+ ViewerSettings {
+ showRenderStats: true
+ }
+ onRunningChanged: {
+ console.log("Presentation ready!");
+ }
+ }
+ \endqml
+
+ \section2 Controlling the presentation
+
+ Like the example above suggests, Studio3D and the other types under the
+ QtStudio3D import offer more than simply rendering the animated Qt 3D
+ Studio presentation. They also offer scene manipulation, including
+
+ \list
+
+ \li querying and changing scene object properties (for example, the
+ transform of a model, colors and other settings of a material, etc.) via
+ Presentation::getAttribute(), Presentation::setAttribute(), \l Element, and
+ \l DataInput,
+
+ \li changing slides (and thus starting the relevant animations and applying
+ the scene object property changes associated with the new slide) via
+ Presentation::goToSlide(), \l SceneElement, and \l DataInput,
+
+ \li and controlling the timeline (the current playback position for the
+ key-frame based animations) both on the main scene and on individual
+ Component nodes via Presentation::goToTime(), \l SceneElement, and \l DataInput.
+
+ \endlist
+
+ \sa Presentation
+*/
+
+/*!
+ \qmlsignal Studio3D::frameUpdate()
+
+ This signal is emitted each time a frame has been rendered.
+*/
+
+/*!
+ \qmlsignal Studio3D::presentationLoaded()
+
+ This signal is emitted when the presentation has been loaded and is ready
+ to be shown.
+*/
+
+/*!
+ \qmlsignal Studio3D::presentationReady()
+
+ This signal is emitted when the presentation has fully initialized its 3D
+ scene for the first frame.
+
+ The difference to presentationLoaded() is that this signal is emitted only
+ when the asynchronous operations needed to build to 3D scene and the first
+ frame have completed.
+
+ When implementing splash screens via Loader items and the Item::visible
+ property, this is the signal that should be used to trigger hiding the
+ splash screen.
+*/
+
+Q3DSStudio3D::Q3DSStudio3D()
+ : m_viewerSettings(nullptr)
+ , m_presentation(nullptr)
+ , m_emitRunningChange(false)
+ , m_isRunning(false)
+ , m_eventIgnoreFlags(EnableAllEvents)
+ , m_pixelRatio(1.0)
+{
+ setMirrorVertically(true);
+ connect(this, &Q3DSStudio3D::windowChanged, this, &Q3DSStudio3D::handleWindowChanged);
+ connect(this, &Q3DSStudio3D::visibleChanged, this, &Q3DSStudio3D::handleVisibleChanged);
+
+ updateEventMasks();
+}
+
+Q3DSStudio3D::~Q3DSStudio3D()
+{
+}
+
+/*!
+ \qmlproperty Presentation Studio3D::presentation
+
+ Accessor for the presentation. Applications are expected to create a single
+ Presentation child object for Studio3D. If this is omitted, a presentation
+ is created automatically.
+
+ This property is read-only.
+*/
+Q3DSPresentationItem *Q3DSStudio3D::presentation() const
+{
+ return m_presentation;
+}
+
+// #TODO: QT3DS-3566 viewerSettings is missing documentation
+/*!
+ \qmlproperty ViewerSettings Studio3D::viewerSettings
+
+ This property is read-only.
+*/
+Q3DSViewerSettings *Q3DSStudio3D::viewerSettings() const
+{
+ return m_viewerSettings;
+}
+
+/*!
+ \qmlproperty string Studio3D::error
+
+ Contains the text for the error message that was generated during the
+ loading of the presentation. When no error occurred or there is no
+ presentation loaded, the value is an empty string.
+
+ This property is read-only.
+*/
+QString Q3DSStudio3D::error() const
+{
+ return m_error;
+}
+
+void Q3DSStudio3D::setError(const QString &error)
+{
+ if (error != m_error) {
+ m_error = error;
+ Q_EMIT errorChanged(m_error);
+ }
+}
+
+/*!
+ \qmlproperty EventIgnoreFlags Studio3D::ignoredEvents
+
+ This property can be used to ignore mouse/wheel/keyboard events.
+ By default all events are enabled.
+*/
+
+Q3DSStudio3D::EventIgnoreFlags Q3DSStudio3D::ignoredEvents() const
+{
+ return m_eventIgnoreFlags;
+}
+
+void Q3DSStudio3D::setIgnoredEvents(EventIgnoreFlags flags)
+{
+ if (m_eventIgnoreFlags == flags)
+ return;
+
+ m_eventIgnoreFlags = flags;
+ updateEventMasks();
+ Q_EMIT ignoredEventsChanged();
+}
+
+/*!
+ \internal
+ */
+void Q3DSStudio3D::updateEventMasks()
+{
+ if (m_eventIgnoreFlags.testFlag(IgnoreMouseEvents)) {
+ setAcceptedMouseButtons(Qt::NoButton);
+ setAcceptHoverEvents(false);
+ } else {
+ setAcceptedMouseButtons(Qt::MouseButtonMask);
+ setAcceptHoverEvents(true);
+ }
+}
+
+/*!
+ \internal
+ */
+void Q3DSStudio3D::componentComplete()
+{
+ const auto childObjs = children();
+ for (QObject *child : childObjs) {
+ auto settings = qobject_cast<Q3DSViewerSettings *>(child);
+ if (settings) {
+ if (m_viewerSettings)
+ qWarning("Duplicate ViewerSettings defined for Studio3D.");
+ else
+ m_viewerSettings = settings;
+ }
+ auto presentation = qobject_cast<Q3DSPresentationItem *>(child);
+ if (presentation) {
+ if (m_presentation)
+ qWarning("Duplicate Presentation defined for Studio3D.");
+ else
+ m_presentation = presentation;
+ }
+ }
+ if (!m_viewerSettings)
+ m_viewerSettings = new Q3DSViewerSettings(this);
+ if (!m_presentation)
+ m_presentation = new Q3DSPresentationItem(this);
+
+ m_viewerSettings->d_ptr->setCommandQueue(&m_pendingCommands);
+ m_presentation->d_ptr->setCommandQueue(&m_pendingCommands);
+
+ // Ensure qml stream proxy gets created on main thread
+ m_presentation->d_ptr->streamProxy();
+
+ QQuickFramebufferObject::componentComplete();
+}
+
+/*!
+ \internal
+ */
+void Q3DSStudio3D::handleWindowChanged(QQuickWindow *window)
+{
+ if (!window)
+ return;
+
+ window->setClearBeforeRendering(false);
+ m_pixelRatio = window->devicePixelRatio();
+
+ // Call tick every frame of the GUI thread to notify QML about new frame via frameUpdate signal
+ connect(window, &QQuickWindow::afterAnimating, this, &Q3DSStudio3D::tick);
+ // Call update after the frame is handled to queue another frame
+ connect(window, &QQuickWindow::afterSynchronizing, this, &Q3DSStudio3D::update);
+}
+
+/*!
+ \internal
+ Queue up a command to inform the renderer of a newly-changed visible/hidden status.
+ */
+void Q3DSStudio3D::handleVisibleChanged()
+{
+ m_pendingCommands.m_visibleChanged = true;
+ m_pendingCommands.m_visible = isVisible();
+}
+
+/*!
+ \brief internal
+ */
+void Q3DSStudio3D::reset()
+{
+ // Fake a source change to trigger a reloading of the presentation
+ m_pendingCommands.m_sourceChanged = true;
+ m_pendingCommands.m_source = m_presentation->source();
+ m_pendingCommands.m_variantListChanged = true;
+ m_pendingCommands.m_variantList = m_presentation->variantList();
+}
+
+/*!
+ \internal
+ */
+void Q3DSStudio3D::requestResponseHandler(const QString &elementPath, CommandType commandType,
+ void *requestData)
+{
+ switch (commandType) {
+ case CommandType_RequestSlideInfo: {
+ Q3DSSceneElement *handler = qobject_cast<Q3DSSceneElement *>(
+ m_presentation->registeredElement(elementPath));
+ if (handler)
+ handler->d_ptr->requestResponseHandler(commandType, requestData);
+ else
+ qWarning() << __FUNCTION__ << "RequestSlideInfo response got for unregistered scene.";
+ break;
+ }
+ case CommandType_RequestDataInputs: {
+ Q3DSPresentation *handler = qobject_cast<Q3DSPresentation *>(m_presentation);
+ if (handler) {
+ handler->d_ptr->requestResponseHandler(commandType, requestData);
+ } else {
+ qWarning() << __FUNCTION__
+ << "RequestDataInputs response got for invalid presentation.";
+ }
+ break;
+ }
+ case CommandType_RequestDataOutputs: {
+ Q3DSPresentation *handler = qobject_cast<Q3DSPresentation *>(m_presentation);
+ if (handler) {
+ handler->d_ptr->requestResponseHandler(commandType, requestData);
+ } else {
+ qWarning() << __FUNCTION__
+ << "RequestDataOutputs response got for invalid presentation.";
+ }
+ break;
+ }
+ default:
+ qWarning() << __FUNCTION__ << "Unknown command type.";
+ break;
+ }
+}
+
+/*!
+ \internal
+ Create the Q3DSRenderer. Invoked automatically by the QML scene graph.
+ */
+QQuickFramebufferObject::Renderer *Q3DSStudio3D::createRenderer() const
+{
+ // It is "illegal" to create a connection between the renderer
+ // and the plugin, and vice-versa. The only valid time the two
+ // may communicate is during Q3DSRenderer::synchronize().
+ Q3DSRenderer *renderer = new Q3DSRenderer(isVisible(), m_presentation->d_ptr->streamProxy());
+
+ connect(renderer, &Q3DSRenderer::enterSlide,
+ m_presentation->d_ptr, &Q3DSPresentationPrivate::handleSlideEntered);
+ connect(renderer, &Q3DSRenderer::dataOutputValueUpdated,
+ m_presentation->d_ptr, &Q3DSPresentationPrivate::handleDataOutputValueUpdate);
+ connect(renderer, &Q3DSRenderer::elementsCreated,
+ m_presentation->d_ptr, &Q3DSPresentationPrivate::handleElementsCreated);
+ connect(renderer, &Q3DSRenderer::materialsCreated,
+ m_presentation->d_ptr, &Q3DSPresentationPrivate::handleMaterialsCreated);
+ connect(renderer, &Q3DSRenderer::meshesCreated,
+ m_presentation->d_ptr, &Q3DSPresentationPrivate::handleMeshesCreated);
+ connect(renderer, &Q3DSRenderer::exitSlide,
+ m_presentation, &Q3DSPresentation::slideExited);
+ connect(renderer, &Q3DSRenderer::customSignalEmitted,
+ m_presentation, &Q3DSPresentation::customSignalEmitted);
+ connect(renderer, &Q3DSRenderer::requestResponse,
+ this, &Q3DSStudio3D::requestResponseHandler);
+ connect(renderer, &Q3DSRenderer::presentationLoaded,
+ this, &Q3DSStudio3D::presentationLoaded);
+ connect(renderer, &Q3DSRenderer::presentationReady,
+ this, &Q3DSStudio3D::presentationReady);
+ return renderer;
+}
+
+/*!
+ \qmlproperty bool Studio3D::running
+
+ The value of this property is \c true when the presentation has been loaded
+ and is ready to be shown.
+
+ This property is read-only.
+*/
+bool Q3DSStudio3D::isRunning() const
+{
+ return m_isRunning;
+}
+
+/*!
+ \internal
+ Emit QML `runningChanged` and `frameUpdate` and signals.
+ This method is called every frame, and emits the `frameUpdate` signal every frame,
+ regardless of plugin visibility. This allows a hidden Qt3DSView to still process
+ information every frame, even though the Renderer is not rendering.
+
+ To prevent expensive onFrameUpdate handlers from being processed when hidden,
+ add an early return to the top like:
+
+ onFrameUpdate: {
+ if (!visible) return;
+ ...
+ }
+ */
+void Q3DSStudio3D::tick()
+{
+ if (m_emitRunningChange) {
+ m_isRunning = true;
+ Q_EMIT runningChanged(true);
+ m_emitRunningChange = false;
+ }
+
+ // Don't call onFrameUpdate until after onInitialize has been called
+ if (m_isRunning) {
+ // Give QML an opportunity to change Qt3DS values every frame
+ Q_EMIT frameUpdate();
+ }
+}
+
+/*!
+ \internal
+ Copies the list of commands previously queued up. Called by Q3DSRenderer::synchronize().
+ */
+void Q3DSStudio3D::getCommands(bool emitInitialize, CommandQueue &renderQueue)
+{
+ if (emitInitialize)
+ m_emitRunningChange = true;
+
+ renderQueue.copyCommands(m_pendingCommands);
+ m_pendingCommands.clear(false);
+}
+
+/*!
+ \internal
+ */
+void Q3DSStudio3D::mousePressEvent(QMouseEvent *event)
+{
+ if (m_eventIgnoreFlags.testFlag(IgnoreMouseEvents))
+ return;
+
+ if (m_pixelRatio != 1.0) {
+ QMouseEvent scaledEvent(event->type(), event->pos() * m_pixelRatio,
+ event->button(), event->buttons(), event->modifiers());
+ m_presentation->mousePressEvent(&scaledEvent);
+ } else {
+ m_presentation->mousePressEvent(event);
+ }
+}
+
+/*!
+ \internal
+ */
+void Q3DSStudio3D::mouseReleaseEvent(QMouseEvent *event)
+{
+ if (m_eventIgnoreFlags.testFlag(IgnoreMouseEvents))
+ return;
+
+ if (m_pixelRatio != 1.0) {
+ QMouseEvent scaledEvent(event->type(), event->pos() * m_pixelRatio,
+ event->button(), event->buttons(), event->modifiers());
+ m_presentation->mouseReleaseEvent(&scaledEvent);
+ } else {
+ m_presentation->mouseReleaseEvent(event);
+ }
+}
+
+/*!
+ \internal
+ */
+void Q3DSStudio3D::mouseMoveEvent(QMouseEvent *event)
+{
+ if (m_eventIgnoreFlags.testFlag(IgnoreMouseEvents))
+ return;
+
+ if (m_pixelRatio != 1.0) {
+ QMouseEvent scaledEvent(event->type(), event->pos() * m_pixelRatio,
+ event->button(), event->buttons(), event->modifiers());
+ m_presentation->mouseMoveEvent(&scaledEvent);
+ } else {
+ m_presentation->mouseMoveEvent(event);
+ }
+}
+
+/*!
+ \internal
+ */
+void Q3DSStudio3D::wheelEvent(QWheelEvent *event)
+{
+ if (m_eventIgnoreFlags.testFlag(IgnoreWheelEvents))
+ return;
+
+ m_presentation->wheelEvent(event);
+}
+
+/*!
+ \internal
+ */
+void Q3DSStudio3D::keyPressEvent(QKeyEvent *event)
+{
+ if (m_eventIgnoreFlags.testFlag(IgnoreKeyboardEvents))
+ return;
+
+ m_presentation->keyPressEvent(event);
+}
+
+/*!
+ \internal
+ */
+void Q3DSStudio3D::keyReleaseEvent(QKeyEvent *event)
+{
+ if (m_eventIgnoreFlags.testFlag(IgnoreKeyboardEvents))
+ return;
+
+ if (!event->isAutoRepeat())
+ m_presentation->keyReleaseEvent(event);
+}
+
+QT_END_NAMESPACE
diff --git a/src/api/studio3dqml/q3dsstudio3d_p.h b/src/api/studio3dqml/q3dsstudio3d_p.h
new file mode 100644
index 0000000..eed8459
--- /dev/null
+++ b/src/api/studio3dqml/q3dsstudio3d_p.h
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 NVIDIA CORPORATION.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) 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.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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3DS_STUDIO3D_H
+#define Q3DS_STUDIO3D_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtStudio3D 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 <QtStudio3D/private/q3dscommandqueue_p.h>
+#include <QtGui/qopenglframebufferobject.h>
+#include <QtQuick/qquickframebufferobject.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q3DSRenderer;
+class Q3DSViewerSettings;
+class Q3DSPresentationItem;
+
+class Q3DSStudio3D : public QQuickFramebufferObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool running READ isRunning NOTIFY runningChanged)
+ Q_PROPERTY(Q3DSPresentationItem *presentation READ presentation CONSTANT)
+ Q_PROPERTY(Q3DSViewerSettings *viewerSettings READ viewerSettings CONSTANT)
+ Q_PROPERTY(QString error READ error NOTIFY errorChanged)
+ Q_PROPERTY(EventIgnoreFlags ignoredEvents READ ignoredEvents WRITE setIgnoredEvents NOTIFY ignoredEventsChanged)
+
+public:
+ enum EventIgnoreFlag {
+ EnableAllEvents = 0,
+ IgnoreMouseEvents = 0x01,
+ IgnoreWheelEvents = 0x02,
+ IgnoreKeyboardEvents = 0x04,
+ IgnoreAllInputEvents = IgnoreMouseEvents | IgnoreWheelEvents | IgnoreKeyboardEvents
+ };
+ Q_DECLARE_FLAGS(EventIgnoreFlags, EventIgnoreFlag)
+ Q_FLAG(EventIgnoreFlags)
+
+ Q3DSStudio3D();
+ ~Q3DSStudio3D() override;
+
+ QQuickFramebufferObject::Renderer *createRenderer() const override;
+
+ bool isRunning() const;
+ Q3DSPresentationItem *presentation() const;
+ Q3DSViewerSettings *viewerSettings() const;
+ QString error() const;
+ void setError(const QString &error);
+
+ void getCommands(bool emitInitialize, CommandQueue &renderQueue);
+
+ void mousePressEvent(QMouseEvent *event) override;
+ void mouseReleaseEvent(QMouseEvent *event) override;
+ void mouseMoveEvent(QMouseEvent *event) override;
+ void wheelEvent(QWheelEvent *event) override;
+ void keyPressEvent(QKeyEvent *event) override;
+ void keyReleaseEvent(QKeyEvent *event) override;
+
+ EventIgnoreFlags ignoredEvents() const;
+ void setIgnoredEvents(EventIgnoreFlags flags);
+
+ void componentComplete() override;
+
+Q_SIGNALS:
+ void frameUpdate();
+ void runningChanged(bool initialized);
+ void errorChanged(const QString &error);
+ void ignoredEventsChanged();
+ void presentationReady();
+ void presentationLoaded();
+
+public Q_SLOTS:
+ void reset();
+
+protected Q_SLOTS:
+ void handleWindowChanged(QQuickWindow *window);
+ void handleVisibleChanged();
+ void tick();
+ void requestResponseHandler(const QString &elementPath, CommandType commandType,
+ void *requestData);
+private:
+ void updateEventMasks();
+
+protected:
+ Q3DSViewerSettings *m_viewerSettings;
+ Q3DSPresentationItem *m_presentation;
+
+ bool m_emitRunningChange;
+ bool m_isRunning;
+ EventIgnoreFlags m_eventIgnoreFlags;
+
+ CommandQueue m_pendingCommands;
+ qreal m_pixelRatio;
+ QString m_error;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(Q3DSStudio3D::EventIgnoreFlags)
+
+QT_END_NAMESPACE
+
+#endif // Q3DS_STUDIO3D_H
diff --git a/src/api/studio3dqml/qmldir b/src/api/studio3dqml/qmldir
new file mode 100644
index 0000000..1eaa8f2
--- /dev/null
+++ b/src/api/studio3dqml/qmldir
@@ -0,0 +1,3 @@
+module QtStudio3D.OpenGL
+plugin declarative_qtstudio3dopengl
+classname Q3DSPlugin
diff --git a/src/api/studio3dqml/studio3dqml.pro b/src/api/studio3dqml/studio3dqml.pro
new file mode 100644
index 0000000..b62a342
--- /dev/null
+++ b/src/api/studio3dqml/studio3dqml.pro
@@ -0,0 +1,34 @@
+include($$PWD/../../commoninclude.pri)
+
+QT += qml quick opengl studio3d-private
+CONFIG += plugin
+
+qtHaveModule(multimedia) {
+DEFINES += PLATFORM_HAS_QT_MULTIMEDIA_LIB
+QT += multimedia
+}
+
+TARGET = qtstudio3dopengl
+TARGETPATH = QtStudio3D/OpenGL
+IMPORT_VERSION = 2.4
+
+SOURCES += \
+ q3dsplugin.cpp \
+ q3dsstudio3d.cpp \
+ q3dsrenderer.cpp \
+ q3dspresentationitem.cpp
+
+HEADERS += \
+ q3dsplugin.h \
+ q3dsrenderer_p.h \
+ q3dsstudio3d_p.h \
+ q3dspresentationitem_p.h
+
+LIBS += \
+ -lqt3dsopengl$$qtPlatformTargetSuffix() \
+ -lqt3dsqmlstreamer$$qtPlatformTargetSuffix()
+
+OTHER_FILES += \
+ qmldir
+
+load(qml_plugin)