summaryrefslogtreecommitdiffstats
path: root/src/Runtime/api
diff options
context:
space:
mode:
authorPasi Keränen <pasi.keranen@qt.io>2019-05-14 14:02:01 +0300
committerPasi Keränen <pasi.keranen@qt.io>2019-05-16 11:50:24 +0000
commit276d7d0f33cc7befb7337a30cfd4e3f9ce3651b2 (patch)
tree5702d9538c22353f2461ac50e7911fe2bc71d8a8 /src/Runtime/api
parent69ab38dd3a6c16325dc6bb048c86235220a3086c (diff)
Make API related classes easier to find
Make files defining the API and API implementation more visible by moving them to separate folder, just like in Qt 3D Runtime. Rename to be more in line with Qt 3D Runtime similar classes (and also make filename match class name). Task-number: QT3DS-3478 Change-Id: Ie7b91ab7c1dce09c3a07b9f385af8e7ed24c536a Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
Diffstat (limited to 'src/Runtime/api')
-rw-r--r--src/Runtime/api/api.pro5
-rw-r--r--src/Runtime/api/studio3d/q3dscommandqueue.cpp303
-rw-r--r--src/Runtime/api/studio3d/q3dscommandqueue_p.h165
-rw-r--r--src/Runtime/api/studio3d/q3dsdatainput.cpp185
-rw-r--r--src/Runtime/api/studio3d/q3dsdatainput.h98
-rw-r--r--src/Runtime/api/studio3d/q3dsdatainput_p.h76
-rw-r--r--src/Runtime/api/studio3d/q3dselement.cpp154
-rw-r--r--src/Runtime/api/studio3d/q3dselement.h79
-rw-r--r--src/Runtime/api/studio3d/q3dselement_p.h77
-rw-r--r--src/Runtime/api/studio3d/q3dsimagesequencegenerator.cpp56
-rw-r--r--src/Runtime/api/studio3d/q3dsimagesequencegenerator_p.h67
-rw-r--r--src/Runtime/api/studio3d/q3dsimagesequencegeneratorthread.cpp190
-rw-r--r--src/Runtime/api/studio3d/q3dsimagesequencegeneratorthread_p.h90
-rw-r--r--src/Runtime/api/studio3d/q3dspresentation.cpp974
-rw-r--r--src/Runtime/api/studio3d/q3dspresentation.h133
-rw-r--r--src/Runtime/api/studio3d/q3dspresentation_p.h112
-rw-r--r--src/Runtime/api/studio3d/q3dssceneelement.cpp273
-rw-r--r--src/Runtime/api/studio3d/q3dssceneelement.h83
-rw-r--r--src/Runtime/api/studio3d/q3dssceneelement_p.h81
-rw-r--r--src/Runtime/api/studio3d/q3dssurfaceviewer.cpp435
-rw-r--r--src/Runtime/api/studio3d/q3dssurfaceviewer.h106
-rw-r--r--src/Runtime/api/studio3d/q3dssurfaceviewer_p.h103
-rw-r--r--src/Runtime/api/studio3d/q3dsviewersettings.cpp244
-rw-r--r--src/Runtime/api/studio3d/q3dsviewersettings.h101
-rw-r--r--src/Runtime/api/studio3d/q3dsviewersettings_p.h88
-rw-r--r--src/Runtime/api/studio3d/q3dswidget.cpp332
-rw-r--r--src/Runtime/api/studio3d/q3dswidget.h92
-rw-r--r--src/Runtime/api/studio3d/q3dswidget_p.h93
-rw-r--r--src/Runtime/api/studio3d/qstudio3dglobal.h49
-rw-r--r--src/Runtime/api/studio3d/studio3d.pro53
-rw-r--r--src/Runtime/api/studio3d/studioutils.cpp56
-rw-r--r--src/Runtime/api/studio3d/studioutils_p.h52
-rw-r--r--src/Runtime/api/studio3d/viewerqmlstreamproxy.cpp59
-rw-r--r--src/Runtime/api/studio3d/viewerqmlstreamproxy_p.h57
-rw-r--r--src/Runtime/api/studio3dqml/q3dsplugin.cpp61
-rw-r--r--src/Runtime/api/studio3dqml/q3dsplugin.h60
-rw-r--r--src/Runtime/api/studio3dqml/q3dspresentationitem.cpp102
-rw-r--r--src/Runtime/api/studio3dqml/q3dspresentationitem.h66
-rw-r--r--src/Runtime/api/studio3dqml/q3dsrenderer.cpp400
-rw-r--r--src/Runtime/api/studio3dqml/q3dsrenderer.h97
-rw-r--r--src/Runtime/api/studio3dqml/q3dsstudio3d.cpp326
-rw-r--r--src/Runtime/api/studio3dqml/q3dsstudio3d.h111
-rw-r--r--src/Runtime/api/studio3dqml/qmldir3
-rw-r--r--src/Runtime/api/studio3dqml/studio3dqml.pro34
44 files changed, 6381 insertions, 0 deletions
diff --git a/src/Runtime/api/api.pro b/src/Runtime/api/api.pro
new file mode 100644
index 00000000..7d5b27d0
--- /dev/null
+++ b/src/Runtime/api/api.pro
@@ -0,0 +1,5 @@
+TEMPLATE = subdirs
+CONFIG += ordered
+SUBDIRS += \
+ studio3d \
+ studio3dqml
diff --git a/src/Runtime/api/studio3d/q3dscommandqueue.cpp b/src/Runtime/api/studio3d/q3dscommandqueue.cpp
new file mode 100644
index 00000000..ed0ad8b5
--- /dev/null
+++ b/src/Runtime/api/studio3d/q3dscommandqueue.cpp
@@ -0,0 +1,303 @@
+/****************************************************************************
+**
+** 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 "q3dscommandqueue_p.h"
+#include "q3dspresentation.h"
+
+ElementCommand::ElementCommand()
+ : m_commandType(CommandType_Invalid)
+{
+}
+
+QString ElementCommand::toString() const
+{
+ QString ret = QStringLiteral("ElementCommand - Type: %1 Path: '%2' StrVal: '%3' VarVal: '%4'");
+ return ret.arg(m_commandType).arg(m_elementPath)
+ .arg(m_stringValue).arg(m_variantValue.toString());
+}
+
+CommandQueue::CommandQueue()
+ : m_visibleChanged(false)
+ , m_scaleModeChanged(false)
+ , m_shadeModeChanged(false)
+ , m_showRenderStatsChanged(false)
+ , m_matteColorChanged(false)
+ , m_sourceChanged(false)
+ , m_variantListChanged(false)
+ , m_globalAnimationTimeChanged(false)
+ , m_delayedLoadingChanged(false)
+ , m_visible(false)
+ , m_scaleMode(Q3DSViewerSettings::ScaleModeCenter)
+ , m_shadeMode(Q3DSViewerSettings::ShadeModeShaded)
+ , m_showRenderStats(false)
+ , m_matteColor(Qt::black)
+ , m_delayedLoading(false)
+ , m_size(0)
+{
+ qRegisterMetaType<CommandType>();
+}
+
+ElementCommand &CommandQueue::queueCommand(const QString &elementPath,
+ CommandType commandType,
+ const QString &attributeName,
+ const QVariant &value)
+{
+ ElementCommand &cmd = nextFreeCommand();
+
+ cmd.m_commandType = commandType;
+ cmd.m_elementPath = elementPath;
+ cmd.m_stringValue = attributeName;
+ cmd.m_variantValue = value;
+
+ return cmd;
+}
+
+ElementCommand &CommandQueue::queueCommand(const QString &elementPath,
+ CommandType commandType,
+ const QString &attributeName,
+ const QVariant &value,
+ int intValue)
+{
+ ElementCommand &cmd = nextFreeCommand();
+
+ cmd.m_commandType = commandType;
+ cmd.m_elementPath = elementPath;
+ cmd.m_stringValue = attributeName;
+ cmd.m_variantValue = value;
+ cmd.m_intValues[0] = intValue;
+
+ return cmd;
+}
+
+ElementCommand &CommandQueue::queueCommand(const QString &elementPath, CommandType commandType,
+ const QString &value)
+{
+ ElementCommand &cmd = nextFreeCommand();
+
+ cmd.m_commandType = commandType;
+ cmd.m_elementPath = elementPath;
+ cmd.m_stringValue = value;
+
+ return cmd;
+}
+
+ElementCommand &CommandQueue::queueCommand(const QString &elementPath,
+ CommandType commandType, bool value)
+{
+ ElementCommand &cmd = nextFreeCommand();
+
+ cmd.m_commandType = commandType;
+ cmd.m_elementPath = elementPath;
+ cmd.m_boolValue = value;
+
+ return cmd;
+}
+
+ElementCommand &CommandQueue::queueCommand(const QString &elementPath,
+ CommandType commandType, float value)
+{
+ ElementCommand &cmd = nextFreeCommand();
+
+ cmd.m_commandType = commandType;
+ cmd.m_elementPath = elementPath;
+ cmd.m_floatValue = value;
+
+ return cmd;
+}
+
+ElementCommand &CommandQueue::queueCommand(const QString &elementPath,
+ CommandType commandType, int value0, int value1,
+ int value2, int value3)
+{
+ ElementCommand &cmd = nextFreeCommand();
+
+ cmd.m_commandType = commandType;
+ cmd.m_elementPath = elementPath;
+ cmd.m_intValues[0] = value0;
+ cmd.m_intValues[1] = value1;
+ cmd.m_intValues[2] = value2;
+ cmd.m_intValues[3] = value3;
+
+ return cmd;
+}
+
+ElementCommand &CommandQueue::queueCommand(const QString &elementPath, CommandType commandType,
+ const QString &stringValue, void *commandData)
+{
+ ElementCommand &cmd = nextFreeCommand();
+
+ cmd.m_commandType = commandType;
+ cmd.m_elementPath = elementPath;
+ cmd.m_stringValue = stringValue;
+ cmd.m_data = commandData;
+
+ return cmd;
+}
+
+ElementCommand &CommandQueue::queueCommand(const QString &elementPath, CommandType commandType)
+{
+ ElementCommand &cmd = nextFreeCommand();
+
+ cmd.m_commandType = commandType;
+ cmd.m_elementPath = elementPath;
+
+ return cmd;
+}
+
+void CommandQueue::copyCommands(CommandQueue &fromQueue)
+{
+ m_visibleChanged = m_visibleChanged || fromQueue.m_visibleChanged;
+ m_scaleModeChanged = m_scaleModeChanged || fromQueue.m_scaleModeChanged;
+ m_shadeModeChanged = m_shadeModeChanged || fromQueue.m_shadeModeChanged;
+ m_showRenderStatsChanged = m_showRenderStatsChanged || fromQueue.m_showRenderStatsChanged;
+ m_matteColorChanged = m_matteColorChanged || fromQueue.m_matteColorChanged;
+ m_sourceChanged = m_sourceChanged || fromQueue.m_sourceChanged;
+ m_variantListChanged = m_variantListChanged || fromQueue.m_variantListChanged;
+ m_globalAnimationTimeChanged
+ = m_globalAnimationTimeChanged || fromQueue.m_globalAnimationTimeChanged;
+ m_delayedLoadingChanged = m_delayedLoadingChanged || fromQueue.m_delayedLoadingChanged;
+
+ if (fromQueue.m_visibleChanged)
+ m_visible = fromQueue.m_visible;
+ if (fromQueue.m_scaleModeChanged)
+ m_scaleMode = fromQueue.m_scaleMode;
+ if (fromQueue.m_shadeModeChanged)
+ m_shadeMode = fromQueue.m_shadeMode;
+ if (fromQueue.m_showRenderStatsChanged)
+ m_showRenderStats = fromQueue.m_showRenderStats;
+ if (fromQueue.m_matteColorChanged)
+ m_matteColor = fromQueue.m_matteColor;
+ if (fromQueue.m_sourceChanged)
+ m_source = fromQueue.m_source;
+ if (fromQueue.m_variantListChanged)
+ m_variantList = fromQueue.m_variantList;
+ if (fromQueue.m_globalAnimationTimeChanged)
+ m_globalAnimationTime = fromQueue.m_globalAnimationTime;
+ if (fromQueue.m_delayedLoadingChanged)
+ m_delayedLoading = fromQueue.m_delayedLoading;
+
+ // Pending queue may be synchronized multiple times between queue processing, so let's append
+ // to the existing queue rather than clearing it.
+ for (int i = 0; i < fromQueue.m_size; i++) {
+ const ElementCommand &source = fromQueue.constCommandAt(i);
+ switch (source.m_commandType) {
+ case CommandType_SetDataInputValue:
+ queueCommand(source.m_elementPath, source.m_commandType, source.m_stringValue,
+ source.m_variantValue, source.m_intValues[0]);
+ break;
+ case CommandType_SetAttribute:
+ queueCommand(source.m_elementPath, source.m_commandType, source.m_stringValue,
+ source.m_variantValue);
+ break;
+ case CommandType_GoToSlideByName:
+ case CommandType_FireEvent:
+ case CommandType_CreateMaterial:
+ queueCommand(source.m_elementPath, source.m_commandType, source.m_stringValue);
+ break;
+ case CommandType_SetPresentationActive:
+ queueCommand(source.m_elementPath, source.m_commandType,
+ source.m_boolValue);
+ break;
+ case CommandType_GoToTime:
+ queueCommand(source.m_elementPath, source.m_commandType,
+ source.m_floatValue);
+ break;
+ case CommandType_GoToSlide:
+ case CommandType_GoToSlideRelative:
+ case CommandType_MousePress:
+ case CommandType_MouseRelease:
+ case CommandType_MouseMove:
+ case CommandType_MouseWheel:
+ case CommandType_KeyPress:
+ case CommandType_KeyRelease:
+ queueCommand(source.m_elementPath, source.m_commandType,
+ source.m_intValues[0], source.m_intValues[1],
+ source.m_intValues[2], source.m_intValues[3]);
+ break;
+ case CommandType_CreateElement:
+ queueCommand(source.m_elementPath, source.m_commandType, source.m_stringValue,
+ source.m_data);
+ fromQueue.commandAt(i).m_data = nullptr; // This queue takes ownership of data
+ break;
+ case CommandType_DeleteElement:
+ case CommandType_RequestSlideInfo:
+ case CommandType_UnloadSlide:
+ case CommandType_PreloadSlide:
+ case CommandType_RequestDataInputs:
+ queueCommand(source.m_elementPath, source.m_commandType);
+ break;
+ default:
+ queueCommand(QString(), CommandType_Invalid, false);
+ break;
+ }
+ }
+}
+
+// Clears changed states and empties the queue
+void CommandQueue::clear(bool deleteCommandData)
+{
+ m_visibleChanged = false;
+ m_scaleModeChanged = false;
+ m_shadeModeChanged = false;
+ m_showRenderStatsChanged = false;
+ m_matteColorChanged = false;
+ m_sourceChanged = false;
+ m_variantListChanged = false;
+ m_globalAnimationTimeChanged = false;
+ m_delayedLoadingChanged = false;
+
+ if (deleteCommandData) {
+ for (int i = 0; i < m_size; ++i) {
+ ElementCommand &cmd = m_elementCommands[i];
+ if (cmd.m_data) {
+ switch (cmd.m_commandType) {
+ case CommandType_CreateElement:
+ delete static_cast<QHash<QString, QVariant> *>(cmd.m_data);
+ break;
+ default:
+ Q_ASSERT(false); // Should never come here
+ break;
+ }
+ cmd.m_data = nullptr;
+ }
+ }
+ }
+
+ // We do not clear the actual queued commands, those will be reused the next frame
+ // To avoid a lot of unnecessary reallocations.
+ m_size = 0;
+}
+
+ElementCommand &CommandQueue::nextFreeCommand()
+{
+ m_size++;
+ if (m_size > m_elementCommands.size())
+ m_elementCommands.append(ElementCommand());
+ return m_elementCommands[m_size - 1];
+}
diff --git a/src/Runtime/api/studio3d/q3dscommandqueue_p.h b/src/Runtime/api/studio3d/q3dscommandqueue_p.h
new file mode 100644
index 00000000..ff30829f
--- /dev/null
+++ b/src/Runtime/api/studio3d/q3dscommandqueue_p.h
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** 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_COMMAND_QUEUE_H
+#define Q3DS_COMMAND_QUEUE_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 "q3dsviewersettings.h"
+
+#include <QtGui/qcolor.h>
+#include <QtCore/qsize.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+enum CommandType {
+ CommandType_Invalid = 0,
+ CommandType_SetAttribute,
+ CommandType_SetPresentationActive,
+ CommandType_GoToSlideByName,
+ CommandType_GoToSlide,
+ CommandType_GoToSlideRelative,
+ CommandType_GoToTime,
+ CommandType_FireEvent,
+ CommandType_MousePress,
+ CommandType_MouseRelease,
+ CommandType_MouseMove,
+ CommandType_MouseWheel,
+ CommandType_KeyPress,
+ CommandType_KeyRelease,
+ CommandType_SetGlobalAnimationTime,
+ CommandType_SetDataInputValue,
+ CommandType_CreateElement,
+ CommandType_DeleteElement,
+ CommandType_CreateMaterial,
+
+ // Requests
+ CommandType_RequestSlideInfo,
+ CommandType_RequestDataInputs,
+ CommandType_PreloadSlide,
+ CommandType_UnloadSlide
+};
+
+class Q_STUDIO3D_EXPORT ElementCommand
+{
+public:
+ ElementCommand();
+
+ CommandType m_commandType;
+ QString m_elementPath;
+ QString m_stringValue;
+ QVariant m_variantValue;
+ void *m_data = nullptr; // Data is owned by the queue and is deleted once command is handled
+ union {
+ bool m_boolValue;
+ float m_floatValue;
+ int m_intValues[4];
+ qint64 m_int64Value;
+ };
+
+ QString toString() const;
+};
+
+typedef QVector<ElementCommand> CommandList;
+
+class Q_STUDIO3D_EXPORT CommandQueue
+{
+public:
+ CommandQueue();
+
+ ElementCommand &queueCommand(const QString &elementPath, CommandType commandType,
+ const QString &attributeName, const QVariant &value);
+ ElementCommand &queueCommand(const QString &elementPath, CommandType commandType,
+ const QString &attributeName, const QVariant &value,
+ int intValue);
+ ElementCommand &queueCommand(const QString &elementPath, CommandType commandType,
+ const QString &value);
+ ElementCommand &queueCommand(const QString &elementPath, CommandType commandType,
+ bool value);
+ ElementCommand &queueCommand(const QString &elementPath, CommandType commandType,
+ float value);
+ ElementCommand &queueCommand(const QString &elementPath, CommandType commandType,
+ int value0, int value1 = 0,
+ int value2 = 0, int value3 = 0);
+ ElementCommand &queueCommand(const QString &elementPath, CommandType commandType,
+ const QString &stringValue, void *commandData);
+ ElementCommand &queueCommand(const QString &elementPath, CommandType commandType);
+
+ void copyCommands(CommandQueue &fromQueue);
+
+ bool m_visibleChanged;
+ bool m_scaleModeChanged;
+ bool m_shadeModeChanged;
+ bool m_showRenderStatsChanged;
+ bool m_matteColorChanged;
+ bool m_sourceChanged;
+ bool m_variantListChanged;
+ bool m_globalAnimationTimeChanged;
+ bool m_delayedLoadingChanged;
+
+ bool m_visible;
+ Q3DSViewerSettings::ScaleMode m_scaleMode;
+ Q3DSViewerSettings::ShadeMode m_shadeMode;
+ bool m_showRenderStats;
+ QColor m_matteColor;
+ QUrl m_source;
+ QStringList m_variantList;
+ qint64 m_globalAnimationTime;
+ bool m_delayedLoading;
+
+ void clear(bool deleteCommandData);
+ int size() const { return m_size; }
+ const ElementCommand &constCommandAt(int index) const { return m_elementCommands.at(index); }
+ ElementCommand &commandAt(int index) { return m_elementCommands[index]; }
+
+private:
+ ElementCommand &nextFreeCommand();
+
+ CommandList m_elementCommands;
+ int m_size;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(CommandType)
+
+#endif // Q3DS_COMMAND_QUEUE_H
diff --git a/src/Runtime/api/studio3d/q3dsdatainput.cpp b/src/Runtime/api/studio3d/q3dsdatainput.cpp
new file mode 100644
index 00000000..3048613e
--- /dev/null
+++ b/src/Runtime/api/studio3d/q3dsdatainput.cpp
@@ -0,0 +1,185 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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 "q3dsdatainput_p.h"
+#include "q3dspresentation_p.h"
+#include "q3dscommandqueue_p.h"
+
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+Q3DSDataInput::Q3DSDataInput(QObject *parent)
+ : QObject(parent)
+ , d_ptr(new Q3DSDataInputPrivate(this))
+{
+}
+
+Q3DSDataInput::Q3DSDataInput(const QString &name, QObject *parent)
+ : QObject(parent)
+ , d_ptr(new Q3DSDataInputPrivate(this))
+{
+ d_ptr->m_name = name;
+}
+
+Q3DSDataInput::Q3DSDataInput(Q3DSPresentation *presentation, const QString &name, QObject *parent)
+ : QObject(parent)
+ , d_ptr(new Q3DSDataInputPrivate(this))
+{
+ d_ptr->m_name = name;
+ d_ptr->m_presentation = presentation;
+ if (presentation)
+ presentation->registerDataInput(this);
+}
+
+Q3DSDataInput::Q3DSDataInput(Q3DSDataInputPrivate *d, Q3DSPresentation *presentation,
+ const QString &name, QObject *parent)
+ : QObject(parent)
+ , d_ptr(d)
+{
+ d_ptr->m_name = name;
+ d_ptr->m_presentation = presentation;
+ if (presentation)
+ presentation->registerDataInput(this);
+}
+
+Q3DSDataInput::~Q3DSDataInput()
+{
+ delete d_ptr;
+}
+
+QString Q3DSDataInput::name() const
+{
+ return d_ptr->m_name;
+}
+
+void Q3DSDataInput::setName(const QString &name)
+{
+ if (d_ptr->m_name != name) {
+ d_ptr->m_name = name;
+ if (d_ptr->m_presentation)
+ d_ptr->m_presentation->registerDataInput(this);
+ Q_EMIT nameChanged();
+ }
+}
+
+QVariant Q3DSDataInput::value() const
+{
+ return d_ptr->m_value;
+}
+
+// TODO: Min and Max are not currently exposed to QML, as implementation requires
+// cumbersome traversal over command queue from QML viewer to renderer.
+float Q3DSDataInput::min() const
+{
+ if (d_ptr->m_presentation)
+ return 0.0f;
+
+ return d_ptr->m_presentation->d_ptr->dataInputMin(d_ptr->m_name);
+}
+
+float Q3DSDataInput::max() const
+{
+ if (d_ptr->m_presentation)
+ return 0.0f;
+
+ return d_ptr->m_presentation->d_ptr->dataInputMax(d_ptr->m_name);
+}
+
+bool Q3DSDataInput::isValid() const
+{
+ if (d_ptr->m_presentation)
+ return d_ptr->m_presentation->d_ptr->isValidDataInput(this);
+ else
+ return false;
+}
+
+void Q3DSDataInput::setMin(float min)
+{
+ d_ptr->m_presentation->setDataInputValue(d_ptr->m_name, min, ValueRole::Min);
+ emit minChanged();
+}
+
+void Q3DSDataInput::setMax(float max)
+{
+ d_ptr->m_presentation->setDataInputValue(d_ptr->m_name, max, ValueRole::Max);
+ emit maxChanged();
+}
+
+void Q3DSDataInput::setValue(const QVariant &value)
+{
+ // Since properties controlled by data inputs can change without the current value being
+ // reflected on the value of the DataInput element, we allow setting the value to the
+ // same one it was previously and still consider it a change.
+ // For example, when controlling timeline, the value set to DataInput will only be
+ // the current value for one frame if presentation has a running animation.
+ d_ptr->setValue(value, ValueRole::Value);
+ Q_EMIT valueChanged();
+}
+
+void Q3DSDataInputPrivate::setPresentation(Q3DSPresentation *presentation)
+{
+ m_presentation = presentation;
+}
+
+Q3DSDataInputPrivate::Q3DSDataInputPrivate(Q3DSDataInput *parent)
+ : q_ptr(parent)
+{
+}
+
+Q3DSDataInputPrivate::~Q3DSDataInputPrivate()
+{
+ if (m_presentation)
+ m_presentation->unregisterDataInput(q_ptr);
+}
+
+void Q3DSDataInputPrivate::setValue(const QVariant &value, Q3DSDataInput::ValueRole valueRole)
+{
+ m_value = value;
+ if (m_presentation)
+ m_presentation->setDataInputValue(m_name, m_value, valueRole);
+}
+
+void Q3DSDataInputPrivate::setViewerApp(Q3DSViewer::Q3DSViewerApp *app)
+{
+ m_viewerApp = app;
+
+ if (m_viewerApp && m_value.isValid())
+ setValue(m_value);
+}
+
+void Q3DSDataInputPrivate::setCommandQueue(CommandQueue *queue)
+{
+ m_commandQueue = queue;
+
+ if (m_commandQueue && m_value.isValid())
+ setValue(m_value);
+}
+
+QT_END_NAMESPACE
diff --git a/src/Runtime/api/studio3d/q3dsdatainput.h b/src/Runtime/api/studio3d/q3dsdatainput.h
new file mode 100644
index 00000000..fc5933fa
--- /dev/null
+++ b/src/Runtime/api/studio3d/q3dsdatainput.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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 Q3DSDATAINPUT_H
+#define Q3DSDATAINPUT_H
+
+#include <QtStudio3D/qstudio3dglobal.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q3DSDataInputPrivate;
+class Q3DSPresentation;
+
+class Q_STUDIO3D_EXPORT Q3DSDataInput : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(Q3DSDataInput)
+
+ Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
+ Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged)
+ // TODO: QML-side getter/setter for min and max
+ // Q_PROPERTY(float max READ max WRITE setMax NOTIFY maxChanged)
+ // Q_PROPERTY(float min READ min WRITE setMin NOTIFY minChanged)
+public:
+ explicit Q3DSDataInput(QObject *parent = nullptr);
+ explicit Q3DSDataInput(const QString &name, QObject *parent = nullptr);
+ explicit Q3DSDataInput(Q3DSPresentation *presentation, const QString &name,
+ QObject *parent = nullptr);
+
+ virtual ~Q3DSDataInput();
+
+ enum class ValueRole {
+ Value = 0,
+ Min = 1,
+ Max = 2
+ };
+
+ QString name() const;
+ QVariant value() const;
+ float min() const;
+ float max() const;
+ bool isValid() const;
+
+public Q_SLOTS:
+ void setName(const QString &name);
+ void setValue(const QVariant &value);
+ void setMin(float min);
+ void setMax(float max);
+
+Q_SIGNALS:
+ void nameChanged();
+ void valueChanged();
+ void minChanged();
+ void maxChanged();
+
+protected:
+ explicit Q3DSDataInput(Q3DSDataInputPrivate *d, Q3DSPresentation *presentation,
+ const QString &name, QObject *parent = nullptr);
+ Q3DSDataInputPrivate *d_ptr;
+
+private:
+ Q_DISABLE_COPY(Q3DSDataInput)
+ friend class Q3DSPresentationPrivate;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(Q3DSDataInput*)
+
+#endif // Q3DSDATAINPUT_H
diff --git a/src/Runtime/api/studio3d/q3dsdatainput_p.h b/src/Runtime/api/studio3d/q3dsdatainput_p.h
new file mode 100644
index 00000000..855406cd
--- /dev/null
+++ b/src/Runtime/api/studio3d/q3dsdatainput_p.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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 Q3DSDATAINPUT_P_P_H
+#define Q3DSDATAINPUT_P_P_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 "q3dsdatainput.h"
+#include "q3dscommandqueue_p.h"
+#include "Qt3DSViewerApp.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q3DSPresentationPrivate;
+
+class Q_STUDIO3D_EXPORT Q3DSDataInputPrivate
+{
+ Q_DECLARE_PUBLIC(Q3DSDataInput)
+public:
+ explicit Q3DSDataInputPrivate(Q3DSDataInput *parent);
+ virtual ~Q3DSDataInputPrivate();
+
+ void setValue(const QVariant &value,
+ Q3DSDataInput::ValueRole valueRole = Q3DSDataInput::ValueRole::Value);
+ void setViewerApp(Q3DSViewer::Q3DSViewerApp *app);
+ void setCommandQueue(CommandQueue *queue);
+ void setPresentation(Q3DSPresentation *presentation);
+
+protected:
+ Q3DSDataInput *q_ptr;
+ Q3DSViewer::Q3DSViewerApp *m_viewerApp = nullptr; // Not owned
+ CommandQueue *m_commandQueue = nullptr; // Not owned
+ Q3DSPresentation *m_presentation = nullptr; // Not owned
+ QString m_name;
+ QVariant m_value;
+};
+
+QT_END_NAMESPACE
+
+#endif // Q3DSDATAINPUT_P_P_H
diff --git a/src/Runtime/api/studio3d/q3dselement.cpp b/src/Runtime/api/studio3d/q3dselement.cpp
new file mode 100644
index 00000000..ac3221dd
--- /dev/null
+++ b/src/Runtime/api/studio3d/q3dselement.cpp
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** 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 "q3dselement_p.h"
+#include "q3dspresentation_p.h"
+#include "q3dscommandqueue_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qsettings.h>
+#include <QtCore/qcoreapplication.h>
+
+QT_BEGIN_NAMESPACE
+
+Q3DSElement::Q3DSElement(QObject *parent)
+ : QObject(parent)
+ , d_ptr(new Q3DSElementPrivate(this))
+{
+}
+
+Q3DSElement::Q3DSElement(const QString &elementPath, QObject *parent)
+ : QObject(parent)
+ , d_ptr(new Q3DSElementPrivate(this))
+{
+ d_ptr->m_elementPath = elementPath;
+}
+
+Q3DSElement::Q3DSElement(Q3DSPresentation *presentation, const QString &elementPath,
+ QObject *parent)
+ : QObject(parent)
+ , d_ptr(new Q3DSElementPrivate(this))
+{
+ d_ptr->m_elementPath = elementPath;
+ if (presentation)
+ presentation->registerElement(this);
+}
+
+Q3DSElement::Q3DSElement(Q3DSElementPrivate *d, Q3DSPresentation *presentation,
+ const QString &elementPath, QObject *parent)
+ : QObject(parent)
+ , d_ptr(d)
+{
+ d_ptr->m_elementPath = elementPath;
+ if (presentation)
+ presentation->registerElement(this);
+}
+
+Q3DSElement::~Q3DSElement()
+{
+ // Private class isn't QObject, so we need to delete it explicitly
+ delete d_ptr;
+}
+
+QString Q3DSElement::elementPath() const
+{
+ return d_ptr->m_elementPath;
+}
+
+void Q3DSElement::setElementPath(const QString &elementPath)
+{
+ if (d_ptr->m_elementPath != elementPath) {
+ d_ptr->setElementPath(elementPath);
+ Q_EMIT elementPathChanged(d_ptr->m_elementPath);
+ }
+}
+
+void Q3DSElement::setAttribute(const QString &attributeName, const QVariant &value)
+{
+ if (d_ptr->m_presentation)
+ d_ptr->m_presentation->q_ptr->setAttribute(d_ptr->m_elementPath, attributeName, value);
+ else
+ qWarning() << __FUNCTION__ << "Element is not registered to any presentation!";
+}
+
+void Q3DSElement::fireEvent(const QString &eventName)
+{
+ if (d_ptr->m_presentation)
+ d_ptr->m_presentation->q_ptr->fireEvent(d_ptr->m_elementPath, eventName);
+ else
+ qWarning() << __FUNCTION__ << "Element is not registered to any presentation!";
+}
+
+Q3DSElementPrivate::Q3DSElementPrivate(Q3DSElement *parent)
+ : q_ptr(parent)
+ , m_viewerApp(nullptr)
+ , m_commandQueue(nullptr)
+ , m_presentation(nullptr)
+{
+}
+
+Q3DSElementPrivate::~Q3DSElementPrivate()
+{
+ if (m_presentation)
+ m_presentation->unregisterElement(q_ptr);
+}
+
+void Q3DSElementPrivate::setElementPath(const QString &elementPath)
+{
+ m_elementPath = elementPath;
+
+ if (m_presentation)
+ m_presentation->registerElement(q_ptr);
+}
+
+void Q3DSElementPrivate::setViewerApp(Q3DSViewer::Q3DSViewerApp *app)
+{
+ m_viewerApp = app;
+}
+
+void Q3DSElementPrivate::setCommandQueue(CommandQueue *queue)
+{
+ m_commandQueue = queue;
+}
+
+void Q3DSElementPrivate::setPresentation(Q3DSPresentationPrivate *presentation)
+{
+ m_presentation = presentation;
+}
+
+void Q3DSElementPrivate::requestResponseHandler(CommandType commandType, void *requestData)
+{
+ Q_UNUSED(commandType)
+ Q_UNUSED(requestData)
+
+ // Base element doesn't handle any request command types yet
+ qWarning() << __FUNCTION__ << "Unknown command type.";
+}
+
+QT_END_NAMESPACE
diff --git a/src/Runtime/api/studio3d/q3dselement.h b/src/Runtime/api/studio3d/q3dselement.h
new file mode 100644
index 00000000..04c43f52
--- /dev/null
+++ b/src/Runtime/api/studio3d/q3dselement.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** 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 Q3DSELEMENT_H
+#define Q3DSELEMENT_H
+
+#include <QtStudio3D/qstudio3dglobal.h>
+#include <QtCore/qobject.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q3DSElementPrivate;
+class Q3DSPresentation;
+
+class Q_STUDIO3D_EXPORT Q3DSElement : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(Q3DSElement)
+
+ Q_PROPERTY(QString elementPath READ elementPath WRITE setElementPath NOTIFY elementPathChanged)
+
+public:
+ explicit Q3DSElement(QObject *parent = nullptr);
+ explicit Q3DSElement(const QString &elementPath, QObject *parent = nullptr);
+ explicit Q3DSElement(Q3DSPresentation *presentation, const QString &elementPath,
+ QObject *parent = nullptr);
+ virtual ~Q3DSElement();
+
+ QString elementPath() const;
+
+public Q_SLOTS:
+ void setElementPath(const QString &elementPath);
+ void setAttribute(const QString &attributeName, const QVariant &value);
+ void fireEvent(const QString &eventName);
+
+Q_SIGNALS:
+ void elementPathChanged(const QString &elementPath);
+
+protected:
+ explicit Q3DSElement(Q3DSElementPrivate *d, Q3DSPresentation *presentation,
+ const QString &elementPath, QObject *parent = nullptr);
+ Q3DSElementPrivate *d_ptr;
+
+private:
+ Q_DISABLE_COPY(Q3DSElement)
+
+ friend class Q3DSPresentationPrivate;
+ friend class Q3DSStudio3D;
+};
+
+QT_END_NAMESPACE
+
+#endif // Q3DSELEMENT_H
diff --git a/src/Runtime/api/studio3d/q3dselement_p.h b/src/Runtime/api/studio3d/q3dselement_p.h
new file mode 100644
index 00000000..d4e77b1c
--- /dev/null
+++ b/src/Runtime/api/studio3d/q3dselement_p.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** 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 Q3DSSCENE_P_H
+#define Q3DSSCENE_P_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 "q3dselement.h"
+#include "q3dscommandqueue_p.h"
+#include "Qt3DSViewerApp.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q3DSPresentationPrivate;
+
+class Q_STUDIO3D_EXPORT Q3DSElementPrivate
+{
+ Q_DECLARE_PUBLIC(Q3DSElement)
+public:
+ explicit Q3DSElementPrivate(Q3DSElement *parent);
+ virtual ~Q3DSElementPrivate();
+
+ void setElementPath(const QString &elementPath);
+
+ virtual void setViewerApp(Q3DSViewer::Q3DSViewerApp *app);
+ virtual void setCommandQueue(CommandQueue *queue);
+ virtual void setPresentation(Q3DSPresentationPrivate *presentation);
+
+ virtual void requestResponseHandler(CommandType commandType, void *requestData);
+
+protected:
+ Q3DSElement *q_ptr;
+ Q3DSViewer::Q3DSViewerApp *m_viewerApp; // Not owned
+ CommandQueue *m_commandQueue; // Not owned
+ Q3DSPresentationPrivate *m_presentation; // Not owned
+ QString m_elementPath;
+};
+
+QT_END_NAMESPACE
+
+#endif // Q3DSSCENE_P_H
diff --git a/src/Runtime/api/studio3d/q3dsimagesequencegenerator.cpp b/src/Runtime/api/studio3d/q3dsimagesequencegenerator.cpp
new file mode 100644
index 00000000..d0b8251b
--- /dev/null
+++ b/src/Runtime/api/studio3d/q3dsimagesequencegenerator.cpp
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** 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 "q3dsimagesequencegenerator_p.h"
+#include "q3dsimagesequencegeneratorthread_p.h"
+
+#ifndef Q_OS_ANDROID
+bool Q3DSImageSequenceGenerator::generateImageSequence(
+ const QString &presentation, qreal start, qreal end, qreal fps, qreal frameInterval,
+ int width, int height, const QString &outPath, const QString &outFile)
+{
+ Q3DSImageSequenceGeneratorThread *thread = new Q3DSImageSequenceGeneratorThread;
+
+ connect(thread, &Q3DSImageSequenceGeneratorThread::generationFinished,
+ this, &Q3DSImageSequenceGenerator::finished);
+
+ bool success = thread->initialize(presentation, start, end, fps, frameInterval, width, height,
+ outPath, outFile);
+
+ if (success) {
+ connect(thread, &Q3DSImageSequenceGeneratorThread::progress,
+ this, &Q3DSImageSequenceGenerator::progress);
+ thread->start();
+ } else {
+ delete thread;
+ }
+
+ return success;
+}
+#endif
diff --git a/src/Runtime/api/studio3d/q3dsimagesequencegenerator_p.h b/src/Runtime/api/studio3d/q3dsimagesequencegenerator_p.h
new file mode 100644
index 00000000..bc56fb1e
--- /dev/null
+++ b/src/Runtime/api/studio3d/q3dsimagesequencegenerator_p.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** 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 Q3DSIMAGE_SEQUENCE_GENERATOR_H
+#define Q3DSIMAGE_SEQUENCE_GENERATOR_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/qstudio3dglobal.h>
+#include <QtCore/qobject.h>
+#ifndef Q_OS_ANDROID
+QT_BEGIN_NAMESPACE
+
+class Q_STUDIO3D_EXPORT Q3DSImageSequenceGenerator : public QObject
+{
+ Q_OBJECT
+public:
+ Q3DSImageSequenceGenerator() {}
+ virtual ~Q3DSImageSequenceGenerator() {}
+
+ bool generateImageSequence(const QString &presentation, qreal start, qreal end,
+ qreal fps, qreal frameInterval, int width, int height,
+ const QString &outPath, const QString &outFile);
+Q_SIGNALS:
+ void progress(int totalFrames, int frameNumber);
+ void finished(bool success, const QString &details);
+};
+
+QT_END_NAMESPACE
+
+#endif // Q3DSIMAGE_SEQUENCE_GENERATOR_H
+#endif
diff --git a/src/Runtime/api/studio3d/q3dsimagesequencegeneratorthread.cpp b/src/Runtime/api/studio3d/q3dsimagesequencegeneratorthread.cpp
new file mode 100644
index 00000000..40bb95b9
--- /dev/null
+++ b/src/Runtime/api/studio3d/q3dsimagesequencegeneratorthread.cpp
@@ -0,0 +1,190 @@
+/****************************************************************************
+**
+** 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 "q3dsimagesequencegeneratorthread_p.h"
+#include "q3dssurfaceviewer.h"
+#include "q3dspresentation.h"
+#include "q3dsviewersettings.h"
+
+#include <QtGui/qopenglcontext.h>
+#include <QtGui/qopenglfunctions.h>
+#include <QtGui/qoffscreensurface.h>
+#include <QtGui/qopenglframebufferobject.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qmath.h>
+
+bool Q3DSImageSequenceGeneratorThread::initialize(
+ const QString &presentation, qreal start, qreal end, qreal fps, qreal frameInterval,
+ int width, int height, const QString &outPath, const QString &outFile)
+{
+ QFileInfo fileInfo(presentation);
+ if (!fileInfo.exists()) {
+ QString error = QObject::tr("File not found: '%1'").arg(presentation);
+ qWarning() << "Generating image sequence failed -" << error;
+ Q_EMIT generationFinished(false, error);
+ return false;
+ }
+
+ m_outputFileName = QStringLiteral("%2/%1_%3.png");
+ if (outFile.isEmpty()) {
+ m_outputFileName = m_outputFileName.arg(fileInfo.baseName())
+ .arg(outPath).arg(QStringLiteral("%1"));
+ } else {
+ m_outputFileName = m_outputFileName.arg(outFile).arg(outPath).arg(QStringLiteral("%1"));
+ }
+
+ m_sourceUrl = QUrl::fromLocalFile(fileInfo.absoluteFilePath());
+
+ QSurfaceFormat format;
+ format.setDepthBufferSize(24);
+ format.setStencilBufferSize(8);
+
+ m_context = new QOpenGLContext;
+ m_context->setFormat(format);
+ if (!m_context->create()) {
+ QString error = QObject::tr("Failed to create context");
+ qWarning() << "Generating image sequence failed -" << error;
+ Q_EMIT generationFinished(false, error);
+ return false;
+ }
+
+ m_surface = new QOffscreenSurface;
+ m_surface->setFormat(m_context->format());
+ m_surface->create();
+
+ m_mainThread = QThread::currentThread();
+ m_surface->moveToThread(this);
+ m_context->moveToThread(this);
+
+ m_start = start;
+ m_end = end;
+ m_fps = fps;
+ m_frameInterval = frameInterval;
+ m_width = width;
+ m_height = height;
+
+ return true;
+}
+
+Q3DSImageSequenceGeneratorThread::Q3DSImageSequenceGeneratorThread()
+ : m_start(0)
+ , m_end(10000)
+ , m_fps(60)
+ , m_frameInterval(16.666667)
+ , m_width(1920)
+ , m_height(1080)
+ , m_surface(nullptr)
+ , m_context(nullptr)
+{
+}
+
+Q3DSImageSequenceGeneratorThread::~Q3DSImageSequenceGeneratorThread() {
+ delete m_context;
+ delete m_surface;
+}
+
+void Q3DSImageSequenceGeneratorThread::run() {
+ if (!m_context->makeCurrent(m_surface)) {
+ QString error = QObject::tr("Couldn't make context current.");
+ qWarning() << "Generating image sequence failed -" << error;
+ Q_EMIT generationFinished(false, error);
+ cleanup();
+ return;
+ }
+
+ const QSize size(m_width, m_height);
+ QOpenGLFramebufferObject fbo(size, QOpenGLFramebufferObject::CombinedDepthStencil);
+
+ Q3DSSurfaceViewer viewer;
+ viewer.presentation()->setSource(m_sourceUrl);
+ viewer.settings()->setScaleMode(Q3DSViewerSettings::ScaleModeFill);
+
+ viewer.setUpdateInterval(-1);
+ viewer.setAutoSize(false);
+ viewer.setSize(size);
+
+ if (!viewer.initialize(m_surface, m_context, fbo.handle())) {
+ QString error = QObject::tr("Viewer initialization failed.");
+ qWarning() << "Generating image sequence failed -" << error;
+ Q_EMIT generationFinished(false, error);
+ cleanup();
+ return;
+ }
+
+ if (m_frameInterval <= 0)
+ m_frameInterval = 1000.0 / m_fps;
+
+ // Presentations always assume you want to start animating at time zero and set a local
+ // offset to global time when they render the first frame. This means we need to always
+ // render a frame at global time zero first.
+ if (qRound(m_start) != 0) {
+ viewer.presentation()->setGlobalAnimationTime(0);
+ viewer.update();
+ }
+
+ // Add a bit of time to the end time to ensure we don't lose the last frame to rounding errors
+ m_end += m_frameInterval / 10000.0;
+
+ // Ensure directory exists
+ QFileInfo fi(m_outputFileName);
+ QDir dir = fi.absoluteDir();
+ dir.mkpath(".");
+
+ int frameCount = 0;
+ int totalFrames = qCeil((m_end - m_start) / m_frameInterval);
+ for (qreal t = m_start; t <= m_end; t += m_frameInterval) {
+ ++frameCount;
+ viewer.presentation()->setGlobalAnimationTime(qRound64(t));
+ viewer.update();
+ if (!fbo.toImage().save(m_outputFileName.arg(frameCount))) {
+ QString error = QObject::tr("Failed to write output file: '%1'")
+ .arg(m_outputFileName.arg(frameCount));
+ qWarning() << "Generating image sequence failed -" << error;
+ Q_EMIT generationFinished(false, error);
+ cleanup();
+ return;
+ }
+ Q_EMIT progress(totalFrames, frameCount);
+ }
+
+ Q_EMIT generationFinished(true, m_outputFileName.arg("*"));
+ cleanup();
+}
+
+void Q3DSImageSequenceGeneratorThread::cleanup()
+{
+ m_context->doneCurrent();
+ delete m_context;
+ m_context = nullptr;
+ // Surface needs to be deleted in the thread it was created in
+ m_surface->moveToThread(m_mainThread);
+ deleteLater();
+}
diff --git a/src/Runtime/api/studio3d/q3dsimagesequencegeneratorthread_p.h b/src/Runtime/api/studio3d/q3dsimagesequencegeneratorthread_p.h
new file mode 100644
index 00000000..45869a69
--- /dev/null
+++ b/src/Runtime/api/studio3d/q3dsimagesequencegeneratorthread_p.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** 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 Q3DSIMAGE_SEQUENCE_GENERATOR_THREAD_H
+#define Q3DSIMAGE_SEQUENCE_GENERATOR_THREAD_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/qstudio3dglobal.h>
+#include <QtCore/qthread.h>
+#include <QtCore/qurl.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOffscreenSurface;
+class QOpenGLContext;
+
+class Q3DSImageSequenceGeneratorThread : public QThread
+{
+ Q_OBJECT
+public:
+ Q3DSImageSequenceGeneratorThread();
+ virtual ~Q3DSImageSequenceGeneratorThread();
+
+ bool initialize(const QString &presentation, qreal start, qreal end,
+ qreal fps, qreal frameInterval, int width, int height,
+ const QString &outPath, const QString &outFile);
+
+Q_SIGNALS:
+ void progress(int totalFrames, int frameNumber);
+ void generationFinished(bool success, const QString &details);
+
+protected:
+ void run() override;
+
+private:
+ void cleanup();
+
+ QUrl m_sourceUrl;
+ qreal m_start;
+ qreal m_end;
+ qreal m_fps;
+ qreal m_frameInterval;
+ int m_width;
+ int m_height;
+ QString m_outputFileName;
+
+ QOffscreenSurface *m_surface;
+ QOpenGLContext *m_context;
+ QThread *m_mainThread;
+};
+
+QT_END_NAMESPACE
+
+#endif // Q3DSIMAGE_SEQUENCE_GENERATOR_THREAD_H
diff --git a/src/Runtime/api/studio3d/q3dspresentation.cpp b/src/Runtime/api/studio3d/q3dspresentation.cpp
new file mode 100644
index 00000000..0887d702
--- /dev/null
+++ b/src/Runtime/api/studio3d/q3dspresentation.cpp
@@ -0,0 +1,974 @@
+/****************************************************************************
+**
+** 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 "q3dspresentation_p.h"
+#include "q3dssceneelement_p.h"
+#include "q3dscommandqueue_p.h"
+#include "viewerqmlstreamproxy_p.h"
+#include "q3dsdatainput_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qsettings.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtGui/qevent.h>
+
+QT_BEGIN_NAMESPACE
+
+Q3DSPresentation::Q3DSPresentation(QObject *parent)
+ : QObject(parent)
+ , d_ptr(new Q3DSPresentationPrivate(this))
+{
+}
+
+Q3DSPresentation::~Q3DSPresentation()
+{
+}
+
+QUrl Q3DSPresentation::source() const
+{
+ return d_ptr->m_source;
+}
+
+QStringList Q3DSPresentation::variantList() const
+{
+ return d_ptr->m_variantList;
+}
+
+void Q3DSPresentation::registerElement(Q3DSElement *element)
+{
+ d_ptr->registerElement(element);
+}
+
+void Q3DSPresentation::unregisterElement(Q3DSElement *element)
+{
+ d_ptr->unregisterElement(element);
+}
+
+Q3DSElement *Q3DSPresentation::registeredElement(const QString &elementPath) const
+{
+ return d_ptr->m_elements.value(elementPath, nullptr);
+}
+
+void Q3DSPresentation::registerDataInput(Q3DSDataInput *dataInput)
+{
+ d_ptr->registerDataInput(dataInput);
+}
+
+void Q3DSPresentation::unregisterDataInput(Q3DSDataInput *dataInput)
+{
+ d_ptr->unregisterDataInput(dataInput);
+}
+
+Q3DSDataInput *Q3DSPresentation::registeredDataInput(const QString &name) const
+{
+ return d_ptr->m_dataInputs.value(name, nullptr);
+}
+
+QVector<Q3DSDataInput *> Q3DSPresentation::dataInputs() const
+{
+ QVector<Q3DSDataInput *> ret;
+ const auto datainputs = d_ptr->m_dataInputs;
+ for (const auto &it : datainputs)
+ ret.append(it);
+
+ return ret;
+}
+
+QVariantList Q3DSPresentation::getDataInputs() const
+{
+ QVariantList ret;
+ const auto datainputs = dataInputs();
+
+ for (const auto &it : datainputs)
+ ret.append(QVariant::fromValue(it));
+
+ return ret;
+}
+
+void Q3DSPresentation::setSource(const QUrl &source)
+{
+ if (d_ptr->m_source != source) {
+ d_ptr->setSource(source);
+ Q_EMIT sourceChanged(source);
+ }
+}
+
+void Q3DSPresentation::setVariantList(const QStringList &variantList)
+{
+ if (d_ptr->m_variantList != variantList) {
+ d_ptr->setVariantList(variantList);
+ Q_EMIT variantListChanged(variantList);
+ }
+}
+
+bool Q3DSPresentation::delayedLoading() const
+{
+ return d_ptr->m_delayedLoading;
+}
+
+void Q3DSPresentation::setDelayedLoading(bool enable)
+{
+ if (d_ptr->m_delayedLoading != enable) {
+ d_ptr->setDelayedLoading(enable);
+ Q_EMIT delayedLoadingChanged(enable);
+ }
+}
+
+void Q3DSPresentation::preloadSlide(const QString &elementPath)
+{
+ if (d_ptr->m_viewerApp)
+ d_ptr->m_viewerApp->preloadSlide(elementPath);
+ else if (d_ptr->m_commandQueue)
+ d_ptr->m_commandQueue->queueCommand(elementPath, CommandType_PreloadSlide);
+}
+
+void Q3DSPresentation::unloadSlide(const QString &elementPath)
+{
+ if (d_ptr->m_viewerApp)
+ d_ptr->m_viewerApp->unloadSlide(elementPath);
+ else if (d_ptr->m_commandQueue)
+ d_ptr->m_commandQueue->queueCommand(elementPath, CommandType_UnloadSlide);
+}
+
+void Q3DSPresentation::goToSlide(const QString &elementPath, unsigned int index)
+{
+ if (d_ptr->m_viewerApp) {
+ const QByteArray path(elementPath.toUtf8());
+ d_ptr->m_viewerApp->GoToSlideByIndex(path, index);
+ } else if (d_ptr->m_commandQueue) {
+ d_ptr->m_commandQueue->queueCommand(elementPath, CommandType_GoToSlide, int(index));
+ }
+}
+
+void Q3DSPresentation::goToSlide(const QString &elementPath, const QString &name)
+{
+ if (d_ptr->m_viewerApp) {
+ const QByteArray path(elementPath.toUtf8());
+ const QByteArray byteName(name.toUtf8());
+ d_ptr->m_viewerApp->GoToSlideByName(path, byteName);
+ } else if (d_ptr->m_commandQueue) {
+ d_ptr->m_commandQueue->queueCommand(elementPath, CommandType_GoToSlideByName, name);
+ }
+}
+
+void Q3DSPresentation::goToSlide(const QString &elementPath, bool next, bool wrap)
+{
+ if (d_ptr->m_viewerApp) {
+ const QByteArray path(elementPath.toUtf8());
+ d_ptr->m_viewerApp->GoToSlideRelative(path, next, wrap);
+ } else if (d_ptr->m_commandQueue) {
+ d_ptr->m_commandQueue->queueCommand(elementPath, CommandType_GoToSlideRelative,
+ int(next), int(wrap));
+ }
+}
+
+void Q3DSPresentation::goToTime(const QString &elementPath, float time)
+{
+ if (d_ptr->m_viewerApp) {
+ const QByteArray path(elementPath.toUtf8());
+ d_ptr->m_viewerApp->GoToTime(path, time);
+ } else if (d_ptr->m_commandQueue) {
+ d_ptr->m_commandQueue->queueCommand(elementPath, CommandType_GoToTime, time);
+ }
+}
+
+void Q3DSPresentation::setAttribute(const QString &elementPath, const QString &attributeName,
+ const QVariant &value)
+{
+ if (d_ptr->m_viewerApp) {
+ const QByteArray path(elementPath.toUtf8());
+ const QByteArray name(attributeName.toUtf8());
+
+ QByteArray valueStr;
+ float valueFloat;
+
+ const void *theValue = nullptr;
+ switch (static_cast<QMetaType::Type>(value.type())) {
+ case QMetaType::Bool:
+ case QMetaType::Int:
+ case QMetaType::Double:
+ case QMetaType::Float:
+ valueFloat = value.toFloat();
+ theValue = &valueFloat;
+ break;
+ case QMetaType::QString:
+ default: // Try string for other types
+ valueStr = value.toString().toUtf8();
+ theValue = valueStr.constData();
+ break;
+ }
+ d_ptr->m_viewerApp->SetAttribute(path, name, (char *)theValue);
+ } else if (d_ptr->m_commandQueue) {
+ d_ptr->m_commandQueue->queueCommand(elementPath, CommandType_SetAttribute,
+ attributeName, value);
+ }
+}
+
+void Q3DSPresentation::setPresentationActive(const QString &id, bool active)
+{
+ if (d_ptr->m_viewerApp) {
+ const QByteArray presId(id.toUtf8());
+ d_ptr->m_viewerApp->SetPresentationActive(presId, active);
+ } else if (d_ptr->m_commandQueue) {
+ d_ptr->m_commandQueue->queueCommand(id, CommandType_SetPresentationActive, active);
+ }
+}
+
+void Q3DSPresentation::fireEvent(const QString &elementPath, const QString &eventName)
+{
+ if (d_ptr->m_viewerApp) {
+ const QByteArray path(elementPath.toUtf8());
+ const QByteArray name(eventName.toUtf8());
+ d_ptr->m_viewerApp->FireEvent(path, name);
+ } else if (d_ptr->m_commandQueue) {
+ d_ptr->m_commandQueue->queueCommand(elementPath, CommandType_FireEvent, eventName);
+ }
+}
+
+void Q3DSPresentation::setGlobalAnimationTime(qint64 milliseconds)
+{
+ if (d_ptr->m_viewerApp) {
+ d_ptr->m_viewerApp->SetGlobalAnimationTime(milliseconds);
+ } else {
+ d_ptr->m_commandQueue->m_globalAnimationTimeChanged = true;
+ d_ptr->m_commandQueue->m_globalAnimationTime = milliseconds;
+ }
+}
+
+void Q3DSPresentation::setDataInputValue(const QString &name, const QVariant &value,
+ Q3DSDataInput::ValueRole valueRole)
+{
+ if (d_ptr->m_viewerApp) {
+ d_ptr->m_viewerApp->SetDataInputValue(name, value,
+ (qt3ds::runtime::DataInputValueRole)valueRole);
+ } else if (d_ptr->m_commandQueue) {
+ d_ptr->m_commandQueue->queueCommand(QString(), CommandType_SetDataInputValue,
+ name, value, static_cast<int>(valueRole));
+ }
+}
+
+/**
+ Adds a new child element for the element specified by parentElementPath to the slide specified
+ with slideName. Only model element creation is currently supported.
+ A referenced material element is also created for the new model element. The source material
+ name can be specified with custom "material" property in the properties hash.
+ The source material must exist in the material container of the presentation.
+*/
+void Q3DSPresentation::createElement(const QString &parentElementPath, const QString &slideName,
+ const QHash<QString, QVariant> &properties)
+{
+ if (d_ptr->m_viewerApp) {
+ d_ptr->m_viewerApp->createElement(parentElementPath, slideName, properties);
+ } else if (d_ptr->m_commandQueue) {
+ // We need to copy the properties map as queue takes ownership of it
+ QHash<QString, QVariant> *theProperties = new QHash<QString, QVariant>(properties);
+ d_ptr->m_commandQueue->queueCommand(parentElementPath, CommandType_CreateElement,
+ slideName, theProperties);
+ }
+}
+
+/**
+ Removes an element added by createElement and all its child elements.
+*/
+void Q3DSPresentation::deleteElement(const QString &elementPath)
+{
+ if (d_ptr->m_viewerApp)
+ d_ptr->m_viewerApp->deleteElement(elementPath);
+ else if (d_ptr->m_commandQueue)
+ d_ptr->m_commandQueue->queueCommand(elementPath, CommandType_DeleteElement);
+}
+
+/**
+ Creates a material specified by the materialDefinition parameter into the material
+ container of the presentation that owns the element specified by the elementPath parameter.
+ After creation, the material can be used for new elements created via createElement.
+ The materialDefinition parameter can contain either the file path to a material definition
+ file or a material definition in the Qt 3D Studion material data format.
+*/
+void Q3DSPresentation::createMaterial(const QString &elementPath,
+ const QString &materialDefinition)
+{
+ if (d_ptr->m_viewerApp) {
+ d_ptr->m_viewerApp->createMaterial(elementPath, materialDefinition);
+ } else if (d_ptr->m_commandQueue) {
+ d_ptr->m_commandQueue->queueCommand(elementPath, CommandType_CreateMaterial,
+ materialDefinition);
+ }
+}
+
+void Q3DSPresentation::mousePressEvent(QMouseEvent *e)
+{
+ if (d_ptr->m_viewerApp) {
+ d_ptr->m_viewerApp->HandleMousePress(e->x(), e->y(), e->button(), true);
+ } else if (d_ptr->m_commandQueue) {
+ d_ptr->m_commandQueue->queueCommand(QString(), CommandType_MousePress,
+ e->x(), e->y(), int(e->button()));
+ }
+}
+
+void Q3DSPresentation::mouseReleaseEvent(QMouseEvent *e)
+{
+ if (d_ptr->m_viewerApp) {
+ d_ptr->m_viewerApp->HandleMousePress(e->x(), e->y(), e->button(), false);
+ } else if (d_ptr->m_commandQueue) {
+ d_ptr->m_commandQueue->queueCommand(QString(), CommandType_MouseRelease,
+ e->x(), e->y(), int(e->button()));
+ }
+}
+
+void Q3DSPresentation::mouseMoveEvent(QMouseEvent *e)
+{
+ if (d_ptr->m_viewerApp) {
+ d_ptr->m_viewerApp->HandleMouseMove(e->x(), e->y(), true);
+ } else if (d_ptr->m_commandQueue) {
+ d_ptr->m_commandQueue->queueCommand(QString(), CommandType_MouseMove,
+ e->x(), e->y());
+ }
+}
+
+void Q3DSPresentation::wheelEvent(QWheelEvent *e)
+{
+ QPoint pixelData = e->pixelDelta();
+ int numSteps = 0;
+ if (pixelData.isNull()) {
+ if (e->orientation() == Qt::Vertical)
+ numSteps = e->angleDelta().y() / 8;
+ else
+ numSteps = e->angleDelta().x() / 8;
+ } else {
+ // trackpad, pixel = one step in scroll wheel.
+ if (e->orientation() == Qt::Vertical)
+ numSteps = pixelData.y();
+ else
+ numSteps = pixelData.x();
+ }
+ if (numSteps != 0) {
+ if (d_ptr->m_viewerApp) {
+ d_ptr->m_viewerApp->HandleMouseWheel(e->x(), e->y(),
+ e->orientation() == Qt::Vertical ? 0 : 1,
+ numSteps);
+ } else if (d_ptr->m_commandQueue) {
+ d_ptr->m_commandQueue->queueCommand(QString(), CommandType_MouseWheel,
+ e->x(), e->y(),
+ int(e->orientation() == Qt::Vertical), numSteps);
+ }
+ }
+}
+
+void Q3DSPresentation::keyPressEvent(QKeyEvent *e)
+{
+ if (d_ptr->m_viewerApp) {
+ d_ptr->m_viewerApp->HandleKeyInput(d_ptr->getScanCode(e), true);
+ } else if (d_ptr->m_commandQueue) {
+ d_ptr->m_commandQueue->queueCommand(QString(), CommandType_KeyPress,
+ d_ptr->getScanCode(e));
+ }
+}
+
+void Q3DSPresentation::keyReleaseEvent(QKeyEvent *e)
+{
+ if (d_ptr->m_viewerApp) {
+ d_ptr->m_viewerApp->HandleKeyInput(d_ptr->getScanCode(e), false);
+ } else if (d_ptr->m_commandQueue) {
+ d_ptr->m_commandQueue->queueCommand(QString(), CommandType_KeyRelease,
+ d_ptr->getScanCode(e));
+ }
+}
+
+Q3DSPresentationPrivate::Q3DSPresentationPrivate(Q3DSPresentation *q)
+ : QObject(q)
+ , q_ptr(q)
+ , m_viewerApp(nullptr)
+ , m_commandQueue(nullptr)
+ , m_streamProxy(nullptr)
+ , m_delayedLoading(false)
+{
+}
+
+Q3DSPresentationPrivate::~Q3DSPresentationPrivate()
+{
+ unregisterAllElements();
+ unregisterAllDataInputs();
+ delete m_streamProxy;
+}
+
+void Q3DSPresentationPrivate::setSource(const QUrl &source)
+{
+ m_source = source;
+ if (m_commandQueue) {
+ m_commandQueue->m_sourceChanged = true;
+ m_commandQueue->m_source = source;
+ }
+}
+
+void Q3DSPresentationPrivate::setVariantList(const QStringList &variantList)
+{
+ m_variantList = variantList;
+ if (m_commandQueue) {
+ m_commandQueue->m_variantListChanged = true;
+ m_commandQueue->m_variantList = variantList;
+ }
+}
+
+void Q3DSPresentationPrivate::setViewerApp(Q3DSViewer::Q3DSViewerApp *app, bool connectApp)
+{
+ Q3DSViewer::Q3DSViewerApp *oldApp = m_viewerApp;
+ m_viewerApp = app;
+
+ const auto elements = m_elements.values();
+ for (Q3DSElement *element : elements)
+ element->d_ptr->setViewerApp(app);
+
+ if (m_viewerApp) {
+ const auto dataInputs = m_viewerApp->dataInputs();
+ for (const auto &name : dataInputs) {
+ if (!m_dataInputs.contains(name)) {
+ auto *di = new Q3DSDataInput(name, nullptr);
+ registerDataInput(di);
+ }
+ }
+ Q_EMIT q_ptr->dataInputsReady();
+ }
+
+ if (connectApp) {
+ if (app) {
+ connect(app, &Q3DSViewer::Q3DSViewerApp::SigSlideEntered,
+ this, &Q3DSPresentationPrivate::handleSlideEntered);
+ connect(app, &Q3DSViewer::Q3DSViewerApp::SigSlideExited,
+ q_ptr, &Q3DSPresentation::slideExited);
+ connect(app, &Q3DSViewer::Q3DSViewerApp::SigCustomSignal,
+ q_ptr, &Q3DSPresentation::customSignalEmitted);
+ connect(app, &Q3DSViewer::Q3DSViewerApp::SigElementCreated,
+ q_ptr, &Q3DSPresentation::elementCreated);
+ connect(app, &Q3DSViewer::Q3DSViewerApp::SigMaterialCreated,
+ q_ptr, &Q3DSPresentation::materialCreated);
+ }
+ if (oldApp) {
+ disconnect(oldApp, &Q3DSViewer::Q3DSViewerApp::SigSlideEntered,
+ this, &Q3DSPresentationPrivate::handleSlideEntered);
+ disconnect(oldApp, &Q3DSViewer::Q3DSViewerApp::SigSlideExited,
+ q_ptr, &Q3DSPresentation::slideExited);
+ disconnect(oldApp, &Q3DSViewer::Q3DSViewerApp::SigCustomSignal,
+ q_ptr, &Q3DSPresentation::customSignalEmitted);
+ disconnect(oldApp, &Q3DSViewer::Q3DSViewerApp::SigElementCreated,
+ q_ptr, &Q3DSPresentation::elementCreated);
+ disconnect(oldApp, &Q3DSViewer::Q3DSViewerApp::SigMaterialCreated,
+ q_ptr, &Q3DSPresentation::materialCreated);
+ }
+ }
+}
+
+void Q3DSPresentationPrivate::setCommandQueue(CommandQueue *queue)
+{
+ m_commandQueue = queue;
+
+ const auto elements = m_elements.values();
+ const auto dataInputs = m_dataInputs.values();
+ for (Q3DSElement *element : elements)
+ element->d_ptr->setCommandQueue(queue);
+ for (Q3DSDataInput *di : dataInputs)
+ di->d_ptr->setCommandQueue(queue);
+
+ if (m_commandQueue) {
+ setDelayedLoading(m_delayedLoading);
+ setVariantList(m_variantList);
+ // Queue a request ASAP for datainputs defined in UIA file so that
+ // getDataInputs has up-to-date info at the earliest.
+ m_commandQueue->queueCommand({}, CommandType_RequestDataInputs);
+ setSource(m_source);
+ }
+}
+
+void Q3DSPresentationPrivate::setDelayedLoading(bool enable)
+{
+ m_delayedLoading = enable;
+ if (m_commandQueue) {
+ m_commandQueue->m_delayedLoading = enable;
+ m_commandQueue->m_delayedLoadingChanged = true;
+ }
+}
+
+void Q3DSPresentationPrivate::requestResponseHandler(CommandType commandType, void *requestData)
+{
+ switch (commandType) {
+ case CommandType_RequestDataInputs: {
+ QVariantList *response = reinterpret_cast<QVariantList *>(requestData);
+
+ for (int i = 0; i < response->size(); ++i) {
+ // Check and append to QML-side list if the (UIA) presentation has additional datainputs
+ // that are not explicitly defined in QML code.
+ if (!m_dataInputs.contains(response->at(i).value<QString>()))
+ registerDataInput(new Q3DSDataInput(response->at(i).value<QString>(), nullptr));
+ }
+ delete response;
+ Q_EMIT q_ptr->dataInputsReady();
+ break;
+ }
+ default:
+ Q_ASSERT(false);
+ break;
+ }
+}
+// Doc note: The ownership of the registered scenes remains with the caller, who needs to
+// ensure that registered scenes are alive as long as the presentation is alive.
+void Q3DSPresentationPrivate::registerElement(Q3DSElement *element)
+{
+ Q_ASSERT(!element->elementPath().isEmpty());
+
+ // Allow only single registration for each element path and scene object
+ QMutableHashIterator<QString, Q3DSElement *> i(m_elements);
+ while (i.hasNext()) {
+ i.next();
+ if (i.value() == element) {
+ // If the same scene object is already registered with different path,
+ // remove it from the map to avoid duplication.
+ if (i.key() != element->elementPath())
+ i.remove();
+ } else if (i.key() == element->elementPath()) {
+ // If the same element path is registered by another scene object, the old
+ // scene object is unregistered.
+ i.value()->d_ptr->setViewerApp(nullptr);
+ i.value()->d_ptr->setPresentation(nullptr);
+ i.remove();
+ }
+ }
+
+ element->d_ptr->setViewerApp(m_viewerApp);
+ element->d_ptr->setCommandQueue(m_commandQueue);
+ element->d_ptr->setPresentation(this);
+
+ m_elements.insert(element->elementPath(), element);
+}
+
+void Q3DSPresentationPrivate::unregisterElement(Q3DSElement *element)
+{
+ Q3DSElement *oldScene = m_elements.value(element->elementPath());
+ if (oldScene == element) {
+ element->d_ptr->setViewerApp(nullptr);
+ element->d_ptr->setCommandQueue(nullptr);
+ element->d_ptr->setPresentation(nullptr);
+ m_elements.remove(element->elementPath());
+ }
+}
+
+void Q3DSPresentationPrivate::unregisterAllElements()
+{
+ for (Q3DSElement *element : m_elements.values()) {
+ element->d_ptr->setViewerApp(nullptr);
+ element->d_ptr->setCommandQueue(nullptr);
+ element->d_ptr->setPresentation(nullptr);
+ }
+ m_elements.clear();
+}
+
+void Q3DSPresentationPrivate::registerDataInput(Q3DSDataInput *dataInput)
+{
+ Q_ASSERT(!dataInput->name().isEmpty());
+
+ // Allow only single registration for each DataInput
+ QMutableHashIterator<QString, Q3DSDataInput *> i(m_dataInputs);
+ while (i.hasNext()) {
+ i.next();
+ if (i.value() == dataInput) {
+ // If the same DataInput object is already registered with different name,
+ // remove it from the map to avoid duplication.
+ if (i.key() != dataInput->name())
+ i.remove();
+ } else if (i.key() == dataInput->name()) {
+ // If the same name is registered by another DataInput object, the old
+ // DataInput object is unregistered.
+ i.value()->d_ptr->setViewerApp(nullptr);
+ i.value()->d_ptr->setPresentation(nullptr);
+ i.remove();
+ }
+ }
+
+ dataInput->d_ptr->setPresentation(q_ptr);
+ dataInput->d_ptr->setViewerApp(m_viewerApp);
+ dataInput->d_ptr->setCommandQueue(m_commandQueue);
+
+ m_dataInputs.insert(dataInput->name(), dataInput);
+}
+
+void Q3DSPresentationPrivate::unregisterDataInput(Q3DSDataInput *dataInput)
+{
+ Q3DSDataInput *oldDi = m_dataInputs.value(dataInput->name());
+ if (oldDi == dataInput) {
+ dataInput->d_ptr->setCommandQueue(nullptr);
+ dataInput->d_ptr->setViewerApp(nullptr);
+ dataInput->d_ptr->setPresentation(nullptr);
+ m_dataInputs.remove(dataInput->name());
+ }
+}
+
+void Q3DSPresentationPrivate::unregisterAllDataInputs()
+{
+ for (Q3DSDataInput *di : m_dataInputs.values()) {
+ di->d_ptr->setViewerApp(nullptr);
+ di->d_ptr->setCommandQueue(nullptr);
+ di->d_ptr->setPresentation(nullptr);
+ }
+ m_dataInputs.clear();
+}
+bool Q3DSPresentationPrivate::isValidDataInput(const Q3DSDataInput *dataInput) const
+{
+ if (!m_viewerApp)
+ return false;
+
+ return m_viewerApp->dataInputs().contains(dataInput->name());
+}
+
+float Q3DSPresentationPrivate::dataInputMin(const QString &name) const
+{
+ if (!m_viewerApp)
+ return 0.0f;
+
+ return m_viewerApp->dataInputMin(name);
+}
+
+float Q3DSPresentationPrivate::dataInputMax(const QString &name) const
+{
+ if (!m_viewerApp)
+ return 0.0f;
+
+ return m_viewerApp->dataInputMax(name);
+}
+
+Q3DStudio::EKeyCode Q3DSPresentationPrivate::getScanCode(QKeyEvent *e)
+{
+ enum {
+ RIGHT_SHIFT = 0x036,
+ RIGHT_CTRL = 0x11d,
+ RIGHT_ALT = 0x138,
+ };
+
+ Qt::Key keyScanCode = static_cast<Qt::Key>(e->key());
+
+ Q3DStudio::EKeyCode newScanCode = Q3DStudio::KEY_NOKEY;
+ switch (keyScanCode) {
+ case Qt::Key_Down:
+ newScanCode = Q3DStudio::KEY_DOWN;
+ break;
+ case Qt::Key_Up:
+ newScanCode = Q3DStudio::KEY_UP;
+ break;
+ case Qt::Key_Left:
+ newScanCode = Q3DStudio::KEY_LEFT;
+ break;
+ case Qt::Key_Right:
+ newScanCode = Q3DStudio::KEY_RIGHT;
+ break;
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ newScanCode = e->modifiers() == Qt::KeypadModifier ? Q3DStudio::KEY_NUMPADENTER
+ : Q3DStudio::KEY_RETURN;
+ break;
+ case Qt::Key_Backspace:
+ newScanCode = Q3DStudio::KEY_BACK;
+ break;
+ case Qt::Key_Tab:
+ newScanCode = Q3DStudio::KEY_TAB;
+ break;
+ case Qt::Key_Escape:
+ newScanCode = Q3DStudio::KEY_ESCAPE;
+ break;
+ case Qt::Key_A:
+ newScanCode = Q3DStudio::KEY_A;
+ break;
+ case Qt::Key_B:
+ newScanCode = Q3DStudio::KEY_B;
+ break;
+ case Qt::Key_C:
+ newScanCode = Q3DStudio::KEY_C;
+ break;
+ case Qt::Key_D:
+ newScanCode = Q3DStudio::KEY_D;
+ break;
+ case Qt::Key_E:
+ newScanCode = Q3DStudio::KEY_E;
+ break;
+ case Qt::Key_F:
+ newScanCode = Q3DStudio::KEY_F;
+ break;
+ case Qt::Key_G:
+ newScanCode = Q3DStudio::KEY_G;
+ break;
+ case Qt::Key_H:
+ newScanCode = Q3DStudio::KEY_H;
+ break;
+ case Qt::Key_I:
+ newScanCode = Q3DStudio::KEY_I;
+ break;
+ case Qt::Key_J:
+ newScanCode = Q3DStudio::KEY_J;
+ break;
+ case Qt::Key_K:
+ newScanCode = Q3DStudio::KEY_K;
+ break;
+ case Qt::Key_L:
+ newScanCode = Q3DStudio::KEY_L;
+ break;
+ case Qt::Key_M:
+ newScanCode = Q3DStudio::KEY_M;
+ break;
+ case Qt::Key_N:
+ newScanCode = Q3DStudio::KEY_N;
+ break;
+ case Qt::Key_O:
+ newScanCode = Q3DStudio::KEY_O;
+ break;
+ case Qt::Key_P:
+ newScanCode = Q3DStudio::KEY_P;
+ break;
+ case Qt::Key_Q:
+ newScanCode = Q3DStudio::KEY_Q;
+ break;
+ case Qt::Key_R:
+ newScanCode = Q3DStudio::KEY_R;
+ break;
+ case Qt::Key_S:
+ newScanCode = Q3DStudio::KEY_S;
+ break;
+ case Qt::Key_T:
+ newScanCode = Q3DStudio::KEY_T;
+ break;
+ case Qt::Key_U:
+ newScanCode = Q3DStudio::KEY_U;
+ break;
+ case Qt::Key_V:
+ newScanCode = Q3DStudio::KEY_V;
+ break;
+ case Qt::Key_W:
+ newScanCode = Q3DStudio::KEY_W;
+ break;
+ case Qt::Key_X:
+ newScanCode = Q3DStudio::KEY_X;
+ break;
+ case Qt::Key_Y:
+ newScanCode = Q3DStudio::KEY_Y;
+ break;
+ case Qt::Key_Z:
+ newScanCode = Q3DStudio::KEY_Z;
+ break;
+ case Qt::Key_0:
+ newScanCode =
+ e->modifiers() == Qt::KeypadModifier ? Q3DStudio::KEY_NUMPAD0 : Q3DStudio::KEY_0;
+ break;
+ case Qt::Key_1:
+ newScanCode =
+ e->modifiers() == Qt::KeypadModifier ? Q3DStudio::KEY_NUMPAD1 : Q3DStudio::KEY_1;
+ break;
+ case Qt::Key_2:
+ newScanCode =
+ e->modifiers() == Qt::KeypadModifier ? Q3DStudio::KEY_NUMPAD2 : Q3DStudio::KEY_2;
+ break;
+ case Qt::Key_3:
+ newScanCode =
+ e->modifiers() == Qt::KeypadModifier ? Q3DStudio::KEY_NUMPAD3 : Q3DStudio::KEY_3;
+ break;
+ case Qt::Key_4:
+ newScanCode =
+ e->modifiers() == Qt::KeypadModifier ? Q3DStudio::KEY_NUMPAD4 : Q3DStudio::KEY_4;
+ break;
+ case Qt::Key_5:
+ newScanCode =
+ e->modifiers() == Qt::KeypadModifier ? Q3DStudio::KEY_NUMPAD5 : Q3DStudio::KEY_5;
+ break;
+ case Qt::Key_6:
+ newScanCode =
+ e->modifiers() == Qt::KeypadModifier ? Q3DStudio::KEY_NUMPAD6 : Q3DStudio::KEY_6;
+ break;
+ case Qt::Key_7:
+ newScanCode =
+ e->modifiers() == Qt::KeypadModifier ? Q3DStudio::KEY_NUMPAD7 : Q3DStudio::KEY_7;
+ break;
+ case Qt::Key_8:
+ newScanCode =
+ e->modifiers() == Qt::KeypadModifier ? Q3DStudio::KEY_NUMPAD8 : Q3DStudio::KEY_8;
+ break;
+ case Qt::Key_9:
+ newScanCode =
+ e->modifiers() == Qt::KeypadModifier ? Q3DStudio::KEY_NUMPAD9 : Q3DStudio::KEY_9;
+ break;
+ case Qt::Key_Minus:
+ newScanCode = e->modifiers() == Qt::KeypadModifier ? Q3DStudio::KEY_NUMPADSUBTRACT
+ : Q3DStudio::KEY_SUBTRACT;
+ break;
+ case Qt::Key_Plus:
+ newScanCode = e->modifiers() == Qt::KeypadModifier ? Q3DStudio::KEY_NUMPADADD
+ : Q3DStudio::KEY_EQUALS;
+ break;
+ case Qt::Key_NumLock:
+ newScanCode = Q3DStudio::KEY_NUMLOCK;
+ break;
+ case Qt::Key_ScrollLock:
+ newScanCode = Q3DStudio::KEY_SCROLL;
+ break;
+ case Qt::Key_CapsLock:
+ newScanCode = Q3DStudio::KEY_CAPITAL;
+ break;
+ case Qt::Key_Pause:
+ newScanCode = Q3DStudio::KEY_PAUSE;
+ break;
+ case Qt::Key_Print:
+ newScanCode = Q3DStudio::KEY_PRINTSCREEN;
+ break;
+ case Qt::Key_Insert:
+ newScanCode = Q3DStudio::KEY_INSERT;
+ break;
+ case Qt::Key_Delete:
+ newScanCode = Q3DStudio::KEY_DELETE;
+ break;
+ case Qt::Key_Home:
+ newScanCode = Q3DStudio::KEY_HOME;
+ break;
+ case Qt::Key_End:
+ newScanCode = Q3DStudio::KEY_END;
+ break;
+ case Qt::Key_PageUp:
+ newScanCode = Q3DStudio::KEY_PGUP;
+ break;
+ case Qt::Key_PageDown:
+ newScanCode = Q3DStudio::KEY_PGDN;
+ break;
+ case Qt::Key_F1:
+ newScanCode = Q3DStudio::KEY_F1;
+ break;
+ case Qt::Key_F2:
+ newScanCode = Q3DStudio::KEY_F2;
+ break;
+ case Qt::Key_F3:
+ newScanCode = Q3DStudio::KEY_F3;
+ break;
+ case Qt::Key_F4:
+ newScanCode = Q3DStudio::KEY_F4;
+ break;
+ case Qt::Key_F5:
+ newScanCode = Q3DStudio::KEY_F5;
+ break;
+ case Qt::Key_F6:
+ newScanCode = Q3DStudio::KEY_F6;
+ break;
+ case Qt::Key_F7:
+ newScanCode = Q3DStudio::KEY_F7;
+ break;
+ case Qt::Key_F8:
+ newScanCode = Q3DStudio::KEY_F8;
+ break;
+ case Qt::Key_F9:
+ newScanCode = Q3DStudio::KEY_F9;
+ break;
+ case Qt::Key_F10:
+ newScanCode = Q3DStudio::KEY_F10;
+ break;
+ case Qt::Key_F11:
+ newScanCode = Q3DStudio::KEY_F11;
+ break;
+ case Qt::Key_F12:
+ newScanCode = Q3DStudio::KEY_F12;
+ break;
+ case Qt::Key_F13:
+ newScanCode = Q3DStudio::KEY_F13;
+ break;
+ case Qt::Key_F14:
+ newScanCode = Q3DStudio::KEY_F14;
+ break;
+ case Qt::Key_QuoteLeft:
+ newScanCode = Q3DStudio::KEY_GRAVE;
+ break;
+ case Qt::Key_Asterisk:
+ newScanCode = Q3DStudio::KEY_MULTIPLY;
+ break;
+ case Qt::Key_BracketRight:
+ newScanCode = Q3DStudio::KEY_RBRACKET;
+ break;
+ case Qt::Key_BracketLeft:
+ newScanCode = Q3DStudio::KEY_LBRACKET;
+ break;
+ case Qt::Key_Semicolon:
+ newScanCode = Q3DStudio::KEY_SEMICOLON;
+ break;
+ case Qt::Key_Comma:
+ newScanCode = Q3DStudio::KEY_COMMA;
+ break;
+ case Qt::Key_Period:
+ newScanCode = e->modifiers() == Qt::KeypadModifier ? Q3DStudio::KEY_NUMPADDECIMAL
+ : Q3DStudio::KEY_PERIOD;
+ break;
+ case Qt::Key_Apostrophe:
+ newScanCode = Q3DStudio::KEY_APOSTROPHE;
+ break;
+ case Qt::Key_Slash:
+ newScanCode = Q3DStudio::KEY_SLASH;
+ break;
+ case Qt::Key_Backslash:
+ newScanCode = Q3DStudio::KEY_BACKSLASH;
+ break;
+ case Qt::Key_Equal:
+ newScanCode = Q3DStudio::KEY_EQUALS;
+ break;
+ case Qt::Key_Space:
+ newScanCode = Q3DStudio::KEY_SPACE;
+ break;
+ case Qt::Key_Shift:
+ newScanCode =
+ e->nativeScanCode() == RIGHT_SHIFT ? Q3DStudio::KEY_RSHIFT : Q3DStudio::KEY_LSHIFT;
+ break;
+ case Qt::Key_Control:
+ newScanCode = e->nativeScanCode() == RIGHT_CTRL ? Q3DStudio::KEY_RCONTROL
+ : Q3DStudio::KEY_LCONTROL;
+ break;
+ case Qt::Key_Alt:
+ newScanCode =
+ e->nativeScanCode() == RIGHT_ALT ? Q3DStudio::KEY_RALT : Q3DStudio::KEY_LALT;
+ break;
+ default:
+ break;
+ }
+
+ return newScanCode;
+}
+
+ViewerQmlStreamProxy *Q3DSPresentationPrivate::streamProxy()
+{
+ if (!m_streamProxy)
+ m_streamProxy = new ViewerQmlStreamProxy();
+ return m_streamProxy;
+}
+
+void Q3DSPresentationPrivate::handleSlideEntered(const QString &elementPath, unsigned int index,
+ const QString &name)
+{
+ Q3DSSceneElement *scene = qobject_cast<Q3DSSceneElement *>(m_elements.value(elementPath));
+ if (scene)
+ scene->d_func()->handleSlideEntered(index, name);
+ Q_EMIT q_ptr->slideEntered(elementPath, index, name);
+}
+
+QT_END_NAMESPACE
diff --git a/src/Runtime/api/studio3d/q3dspresentation.h b/src/Runtime/api/studio3d/q3dspresentation.h
new file mode 100644
index 00000000..d7f02e49
--- /dev/null
+++ b/src/Runtime/api/studio3d/q3dspresentation.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** 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 Q3DSPRESENTATION_H
+#define Q3DSPRESENTATION_H
+
+#include <QtStudio3D/qstudio3dglobal.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qurl.h>
+#include <QtStudio3D/q3dsdatainput.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q3DSPresentationPrivate;
+class Q3DSElement;
+class QMouseEvent;
+class QWheelEvent;
+class QKeyEvent;
+
+class Q_STUDIO3D_EXPORT Q3DSPresentation : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(Q3DSPresentation)
+ Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+ Q_PROPERTY(QStringList variantList READ variantList WRITE setVariantList NOTIFY variantListChanged)
+ Q_PROPERTY(bool delayedLoading READ delayedLoading WRITE setDelayedLoading NOTIFY delayedLoadingChanged)
+
+public:
+ explicit Q3DSPresentation(QObject *parent = nullptr);
+ ~Q3DSPresentation();
+
+ QUrl source() const;
+ QStringList variantList() const;
+
+ void registerElement(Q3DSElement *scene);
+ void unregisterElement(Q3DSElement *scene);
+ Q3DSElement *registeredElement(const QString &elementPath) const;
+
+ void registerDataInput(Q3DSDataInput *dataInput);
+ void unregisterDataInput(Q3DSDataInput *dataInput);
+ Q3DSDataInput *registeredDataInput(const QString &name) const;
+
+ Q_INVOKABLE QVariantList getDataInputs() const;
+ QVector<Q3DSDataInput *> dataInputs() const;
+
+ bool delayedLoading() const;
+ void setDelayedLoading(bool enable);
+
+ Q_INVOKABLE void preloadSlide(const QString &elementPath);
+ Q_INVOKABLE void unloadSlide(const QString &elementPath);
+
+ // Input event handlers
+ void mousePressEvent(QMouseEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+ void mouseMoveEvent(QMouseEvent *e);
+ void wheelEvent(QWheelEvent *e);
+ void keyPressEvent(QKeyEvent *e);
+ void keyReleaseEvent(QKeyEvent *e);
+
+ void createElement(const QString &parentElementPath, const QString &slideName,
+ const QHash<QString, QVariant> &properties);
+ void deleteElement(const QString &elementPath);
+ void createMaterial(const QString &elementPath, const QString &materialDefinition);
+
+public Q_SLOTS:
+ void setSource(const QUrl &source);
+ void setVariantList(const QStringList &variantList);
+ void goToSlide(const QString &elementPath, unsigned int index);
+ void goToSlide(const QString &elementPath, const QString &name);
+ void goToSlide(const QString &elementPath, bool next, bool wrap);
+ void goToTime(const QString &elementPath, float time);
+ void setAttribute(const QString &elementPath, const QString &attributeName,
+ const QVariant &value);
+ void setPresentationActive(const QString &id, bool active);
+ void fireEvent(const QString &elementPath, const QString &eventName);
+ void setGlobalAnimationTime(qint64 milliseconds);
+ void setDataInputValue(const QString &name, const QVariant &value,
+ Q3DSDataInput::ValueRole valueRole = Q3DSDataInput::ValueRole::Value);
+
+Q_SIGNALS:
+ void variantListChanged(const QStringList &variantList);
+ void sourceChanged(const QUrl &source);
+ void slideEntered(const QString &elementPath, unsigned int index, const QString &name);
+ void slideExited(const QString &elementPath, unsigned int index, const QString &name);
+ // Indicates that data input definitions in the Studio project have been parsed
+ // and datainputs are available through dataInputs() / getDataInputs().
+ void dataInputsReady();
+ void customSignalEmitted(const QString &elementPath, const QString &name);
+ void delayedLoadingChanged(bool enable);
+ void elementCreated(const QString &elementPath, const QString &error);
+ void materialCreated(const QString &name, const QString &error);
+
+private:
+ Q_DISABLE_COPY(Q3DSPresentation)
+ Q3DSPresentationPrivate *d_ptr;
+
+ friend class Q3DSPresentationItem;
+ friend class Q3DSSurfaceViewerPrivate;
+ friend class Q3DSWidgetPrivate;
+ friend class Q3DSRenderer;
+ friend class Q3DSStudio3D;
+ friend class Q3DSDataInput;
+};
+
+QT_END_NAMESPACE
+
+#endif // Q3DSPRESENTATION_H
diff --git a/src/Runtime/api/studio3d/q3dspresentation_p.h b/src/Runtime/api/studio3d/q3dspresentation_p.h
new file mode 100644
index 00000000..6172aa33
--- /dev/null
+++ b/src/Runtime/api/studio3d/q3dspresentation_p.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** 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 Q3DSPRESENTATION_P_H
+#define Q3DSPRESENTATION_P_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 "q3dspresentation.h"
+#include "q3dscommandqueue_p.h"
+#include "Qt3DSViewerApp.h"
+#include <QtCore/QHash>
+#include <QtCore/QUrl>
+
+QT_BEGIN_NAMESPACE
+
+class CommandQueue;
+class ViewerQmlStreamProxy;
+class QKeyEvent;
+
+class Q_STUDIO3D_EXPORT Q3DSPresentationPrivate : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PUBLIC(Q3DSPresentation)
+
+public:
+ typedef QHash<QString, Q3DSElement *> ElementMap;
+ typedef QHash<QString, Q3DSDataInput *> DataInputMap;
+
+ explicit Q3DSPresentationPrivate(Q3DSPresentation *parent);
+ ~Q3DSPresentationPrivate();
+
+ void setSource(const QUrl &source);
+ void setVariantList(const QStringList &variantList);
+ void setViewerApp(Q3DSViewer::Q3DSViewerApp *app, bool connectApp = true);
+ void setCommandQueue(CommandQueue *queue);
+ void setDelayedLoading(bool enable);
+
+ void registerElement(Q3DSElement *element);
+ void unregisterElement(Q3DSElement *element);
+ void unregisterAllElements();
+
+ void registerDataInput(Q3DSDataInput *dataInput);
+ void unregisterDataInput(Q3DSDataInput *dataInput);
+ void unregisterAllDataInputs();
+
+ bool isValidDataInput(const Q3DSDataInput *dataInput) const;
+ float dataInputMin(const QString &name) const;
+ float dataInputMax(const QString &name) const;
+
+ ViewerQmlStreamProxy *streamProxy();
+ Q3DStudio::EKeyCode getScanCode(QKeyEvent *e);
+
+ void requestResponseHandler(CommandType commandType, void *requestData);
+
+public Q_SLOTS:
+ void handleSlideEntered(const QString &elementPath, unsigned int index, const QString &name);
+
+public:
+ Q3DSPresentation *q_ptr;
+
+private:
+ Q3DSViewer::Q3DSViewerApp *m_viewerApp; // Not owned
+ CommandQueue *m_commandQueue; // Not owned
+ ElementMap m_elements;
+ DataInputMap m_dataInputs;
+ QUrl m_source;
+ QStringList m_variantList;
+ ViewerQmlStreamProxy *m_streamProxy;
+ bool m_delayedLoading;
+
+ friend class Q3DSStudio3D;
+};
+
+QT_END_NAMESPACE
+
+#endif // Q3DSPRESENTATION_P_H
diff --git a/src/Runtime/api/studio3d/q3dssceneelement.cpp b/src/Runtime/api/studio3d/q3dssceneelement.cpp
new file mode 100644
index 00000000..2eef5d00
--- /dev/null
+++ b/src/Runtime/api/studio3d/q3dssceneelement.cpp
@@ -0,0 +1,273 @@
+/****************************************************************************
+**
+** 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 "q3dssceneelement_p.h"
+#include "q3dspresentation_p.h"
+#include "q3dscommandqueue_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qsettings.h>
+#include <QtCore/qcoreapplication.h>
+
+QT_BEGIN_NAMESPACE
+
+Q3DSSceneElement::Q3DSSceneElement(QObject *parent)
+ : Q3DSElement(new Q3DSSceneElementPrivate(this), nullptr, QString(), parent)
+{
+}
+
+Q3DSSceneElement::Q3DSSceneElement(const QString &elementPath, QObject *parent)
+ : Q3DSElement(new Q3DSSceneElementPrivate(this), nullptr, elementPath, parent)
+{
+}
+
+Q3DSSceneElement::Q3DSSceneElement(Q3DSPresentation *presentation, const QString &elementPath,
+ QObject *parent)
+ : Q3DSElement(new Q3DSSceneElementPrivate(this), presentation, elementPath, parent)
+{
+
+}
+
+Q3DSSceneElement::~Q3DSSceneElement()
+{
+}
+
+int Q3DSSceneElement::currentSlideIndex() const
+{
+ Q_D(const Q3DSSceneElement);
+ return d->m_currentSlideIndex;
+}
+
+int Q3DSSceneElement::previousSlideIndex() const
+{
+ Q_D(const Q3DSSceneElement);
+ return d->m_previousSlideIndex;
+}
+
+QString Q3DSSceneElement::currentSlideName() const
+{
+ Q_D(const Q3DSSceneElement);
+ return d->m_currentSlideName;
+}
+
+QString Q3DSSceneElement::previousSlideName() const
+{
+ Q_D(const Q3DSSceneElement);
+ return d->m_previousSlideName;
+}
+
+void Q3DSSceneElement::setCurrentSlideIndex(int currentSlideIndex)
+{
+ Q_D(Q3DSSceneElement);
+ if (d->m_viewerApp) {
+ const QByteArray path(d->m_elementPath.toUtf8());
+ d->m_viewerApp->GoToSlideByIndex(path, currentSlideIndex + 1);
+ } else if (d->m_commandQueue) {
+ d->m_commandQueue->queueCommand(d->m_elementPath, CommandType_GoToSlide,
+ int(currentSlideIndex + 1));
+ } else {
+ // Store desired slide until we have either app or queue. Only name or index can be set.
+ d->m_initialSlideIndex = currentSlideIndex + 1;
+ d->m_initialSlideName.clear();
+ }
+}
+
+void Q3DSSceneElement::setCurrentSlideName(const QString &currentSlideName)
+{
+ Q_D(Q3DSSceneElement);
+ if (d->m_viewerApp) {
+ const QByteArray path(d->m_elementPath.toUtf8());
+ const QByteArray name(currentSlideName.toUtf8());
+ d->m_viewerApp->GoToSlideByName(path, name);
+ } else if (d->m_commandQueue) {
+ d->m_commandQueue->queueCommand(d->m_elementPath, CommandType_GoToSlideByName,
+ currentSlideName);
+ } else {
+ // Store desired slide until we have either app or queue. Only name or index can be set.
+ d->m_initialSlideName = currentSlideName;
+ d->m_initialSlideIndex = 0;
+ }
+}
+
+void Q3DSSceneElement::goToSlide(bool next, bool wrap)
+{
+ Q_D(Q3DSSceneElement);
+ d->goToSlide(next, wrap);
+}
+
+void Q3DSSceneElement::goToTime(float time)
+{
+ Q_D(Q3DSSceneElement);
+ d->goToTime(time);
+}
+
+Q3DSSceneElementPrivate::Q3DSSceneElementPrivate(Q3DSSceneElement *parent)
+ : Q3DSElementPrivate(parent)
+ , m_currentSlideIndex(0)
+ , m_previousSlideIndex(0)
+ , m_initialSlideIndex(0)
+ , m_slideInfoRequestPending(false)
+{
+}
+
+Q3DSSceneElementPrivate::~Q3DSSceneElementPrivate()
+{
+}
+
+void Q3DSSceneElementPrivate::handleSlideEntered(int index, const QString &name)
+{
+ Q_Q(Q3DSSceneElement);
+
+ // Initializing presentation will report slide entered for the scenes on the default slide
+ // of the presentation even if user has specified different initial slides.
+ // Since we don't have robust error reporting mechanism from the viewerapp,
+ // we cannot simply ignore these initial enters, as there is no guarantee the slide
+ // user wants even exists.
+
+ // We ignore the slide exited signals and rely on stored previous slide data
+ // to avoid excessive signaling on slide changes.
+ bool notifyCurrent = m_currentSlideIndex != index;
+ bool notifyPrevious = m_previousSlideIndex != m_currentSlideIndex;
+
+ // Since child (i.e. component) slides always get enter event when parent slide is entered,
+ // it is possible that current and previous slides are the same. This feels bit odd, but is
+ // technically correct, as the last time we got enter, the same slide was made current.
+ // It also matches the internal m_viewerApp logic for previous slides.
+ m_previousSlideIndex = m_currentSlideIndex;
+ m_previousSlideName = m_currentSlideName;
+ m_currentSlideIndex = index;
+ m_currentSlideName = name;
+
+ if (notifyPrevious) {
+ Q_EMIT q->previousSlideIndexChanged(m_previousSlideIndex);
+ Q_EMIT q->previousSlideNameChanged(m_previousSlideName);
+ }
+
+ if (notifyCurrent) {
+ Q_EMIT q->currentSlideIndexChanged(m_currentSlideIndex);
+ Q_EMIT q->currentSlideNameChanged(m_currentSlideName);
+ }
+}
+
+void Q3DSSceneElementPrivate::goToSlide(bool next, bool wrap)
+{
+ if (m_presentation)
+ m_presentation->q_ptr->goToSlide(m_elementPath, next, wrap);
+ else
+ qWarning() << __FUNCTION__ << "Element is not registered to any presentation!";
+}
+
+void Q3DSSceneElementPrivate::goToTime(float time)
+{
+ if (m_presentation)
+ m_presentation->q_ptr->goToTime(m_elementPath, time);
+ else
+ qWarning() << __FUNCTION__ << "Element is not registered to any presentation!";
+}
+
+void Q3DSSceneElementPrivate::setViewerApp(Q3DSViewer::Q3DSViewerApp *app)
+{
+ Q_Q(Q3DSSceneElement);
+
+ if (app || m_viewerApp) {
+ m_currentSlideIndex = 0;
+ m_currentSlideName.clear();
+ m_previousSlideIndex = 0;
+ m_previousSlideName.clear();
+ }
+
+ Q3DSElementPrivate::setViewerApp(app);
+
+ if (m_viewerApp) {
+ const QByteArray path(m_elementPath.toUtf8());
+ m_viewerApp->GetSlideInfo(path, m_currentSlideIndex, m_previousSlideIndex,
+ m_currentSlideName, m_previousSlideName);
+
+ // If user has set current slide before viewer app has been set for the first time,
+ // we will switch to the desired slide after we initialize.
+ if (m_initialSlideIndex != 0)
+ q->setCurrentSlideIndex(m_initialSlideIndex - 1);
+ else if (!m_initialSlideName.isEmpty())
+ q->setCurrentSlideName(m_initialSlideName);
+
+ m_initialSlideIndex = 0;
+ m_initialSlideName.clear();
+ }
+}
+
+void Q3DSSceneElementPrivate::setCommandQueue(CommandQueue *queue)
+{
+ Q_Q(Q3DSSceneElement);
+
+ if (queue || m_commandQueue) {
+ m_currentSlideIndex = 0;
+ m_currentSlideName.clear();
+ m_previousSlideIndex = 0;
+ m_previousSlideName.clear();
+ }
+ Q3DSElementPrivate::setCommandQueue(queue);
+
+ if (m_commandQueue) {
+ m_commandQueue->queueCommand(m_elementPath, CommandType_RequestSlideInfo);
+ m_slideInfoRequestPending = true;
+ // If user has set current slide before the queue has been set for the first time,
+ // we will switch to the desired slide after we initialize.
+ if (m_initialSlideIndex != 0)
+ q->setCurrentSlideIndex(m_initialSlideIndex - 1);
+ else if (!m_initialSlideName.isEmpty())
+ q->setCurrentSlideName(m_initialSlideName);
+
+ m_initialSlideIndex = 0;
+ m_initialSlideName.clear();
+ }
+}
+
+void Q3DSSceneElementPrivate::requestResponseHandler(CommandType commandType, void *requestData)
+{
+ switch (commandType) {
+ case CommandType_RequestSlideInfo: {
+ QVariantList *response = reinterpret_cast<QVariantList *>(requestData);
+ if (m_slideInfoRequestPending) {
+ m_slideInfoRequestPending = false;
+
+ m_previousSlideIndex = response->at(1).toInt();
+ m_previousSlideName = response->at(3).toString();
+
+ handleSlideEntered(response->at(0).toInt(), response->at(2).toString());
+ }
+ delete response;
+ break;
+ }
+ default:
+ Q3DSElementPrivate::requestResponseHandler(commandType, requestData);
+ break;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/Runtime/api/studio3d/q3dssceneelement.h b/src/Runtime/api/studio3d/q3dssceneelement.h
new file mode 100644
index 00000000..2d96255c
--- /dev/null
+++ b/src/Runtime/api/studio3d/q3dssceneelement.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** 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 Q3DSSCENEELEMENT_H
+#define Q3DSSCENEELEMENT_H
+
+#include <QtStudio3D/q3dselement.h>
+#include <QtCore/qobject.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q3DSSceneElementPrivate;
+
+class Q_STUDIO3D_EXPORT Q3DSSceneElement : public Q3DSElement
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(Q3DSSceneElement)
+
+ Q_PROPERTY(int currentSlideIndex READ currentSlideIndex WRITE setCurrentSlideIndex NOTIFY currentSlideIndexChanged)
+ Q_PROPERTY(int previousSlideIndex READ previousSlideIndex NOTIFY previousSlideIndexChanged)
+ Q_PROPERTY(QString currentSlideName READ currentSlideName WRITE setCurrentSlideName NOTIFY currentSlideNameChanged)
+ Q_PROPERTY(QString previousSlideName READ previousSlideName NOTIFY previousSlideNameChanged)
+
+public:
+ explicit Q3DSSceneElement(QObject *parent = nullptr);
+ explicit Q3DSSceneElement(const QString &elementPath, QObject *parent = nullptr);
+ explicit Q3DSSceneElement(Q3DSPresentation *presentation, const QString &elementPath,
+ QObject *parent = nullptr);
+ ~Q3DSSceneElement();
+
+ int currentSlideIndex() const;
+ int previousSlideIndex() const;
+ QString currentSlideName() const;
+ QString previousSlideName() const;
+
+public Q_SLOTS:
+ void setCurrentSlideIndex(int currentSlideIndex);
+ void setCurrentSlideName(const QString &currentSlideName);
+ void goToSlide(bool next, bool wrap);
+ void goToTime(float time);
+
+Q_SIGNALS:
+ void currentSlideIndexChanged(int currentSlideIndex);
+ void previousSlideIndexChanged(int previousSlideIndex);
+ void currentSlideNameChanged(const QString &currentSlideName);
+ void previousSlideNameChanged(const QString &previousSlideName);
+
+private:
+ Q_DISABLE_COPY(Q3DSSceneElement)
+
+ friend class Q3DSPresentationPrivate;
+ friend class Q3DSStudio3D;
+};
+
+QT_END_NAMESPACE
+
+#endif // Q3DSSCENEELEMENT_H
diff --git a/src/Runtime/api/studio3d/q3dssceneelement_p.h b/src/Runtime/api/studio3d/q3dssceneelement_p.h
new file mode 100644
index 00000000..02d2bdff
--- /dev/null
+++ b/src/Runtime/api/studio3d/q3dssceneelement_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** 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 Q3DSSCENEELEMENT_P_H
+#define Q3DSSCENEELEMENT_P_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 "q3dssceneelement.h"
+#include "q3dselement_p.h"
+#include "q3dscommandqueue_p.h"
+#include "Qt3DSViewerApp.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q3DSPresentationPrivate;
+
+class Q_STUDIO3D_EXPORT Q3DSSceneElementPrivate : public Q3DSElementPrivate
+{
+ Q_DECLARE_PUBLIC(Q3DSSceneElement)
+public:
+ explicit Q3DSSceneElementPrivate(Q3DSSceneElement *parent);
+ ~Q3DSSceneElementPrivate();
+
+ void handleSlideEntered(int index, const QString &name);
+ void goToSlide(bool next, bool wrap);
+ void goToTime(float time);
+
+ void setViewerApp(Q3DSViewer::Q3DSViewerApp *app) override;
+ void setCommandQueue(CommandQueue *queue) override;
+
+ void requestResponseHandler(CommandType commandType, void *requestData) override;
+
+private:
+ int m_currentSlideIndex;
+ int m_previousSlideIndex;
+ int m_initialSlideIndex;
+ QString m_currentSlideName;
+ QString m_previousSlideName;
+ QString m_initialSlideName;
+ bool m_slideInfoRequestPending;
+};
+
+QT_END_NAMESPACE
+
+#endif // Q3DSSCENEELEMENT_P_H
diff --git a/src/Runtime/api/studio3d/q3dssurfaceviewer.cpp b/src/Runtime/api/studio3d/q3dssurfaceviewer.cpp
new file mode 100644
index 00000000..fc90e341
--- /dev/null
+++ b/src/Runtime/api/studio3d/q3dssurfaceviewer.cpp
@@ -0,0 +1,435 @@
+/****************************************************************************
+**
+** 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 "q3dssurfaceviewer_p.h"
+#include "Qt3DSAudioPlayerImpl.h"
+#include "viewerqmlstreamproxy_p.h"
+#include "q3dsviewersettings_p.h"
+#include "q3dspresentation_p.h"
+#include "studioutils_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtGui/qopenglcontext.h>
+#include <QtGui/qopenglfunctions.h>
+#include <QtGui/qoffscreensurface.h>
+#include <QtGui/qwindow.h>
+#include <QtGui/QPlatformSurfaceEvent>
+
+#include <QtCore/QFileInfo>
+
+using namespace Q3DSViewer;
+
+QT_BEGIN_NAMESPACE
+
+Q3DSSurfaceViewer::Q3DSSurfaceViewer(QObject *parent)
+ : QObject(parent)
+ , d_ptr(new Q3DSSurfaceViewerPrivate(this))
+{
+}
+
+Q3DSSurfaceViewer::~Q3DSSurfaceViewer()
+{
+ delete d_ptr;
+}
+
+bool Q3DSSurfaceViewer::initialize(QSurface *surface, QOpenGLContext *context, GLuint fboId)
+{
+ return d_ptr->initialize(surface, context, fboId);
+}
+
+void Q3DSSurfaceViewer::shutdown()
+{
+ d_ptr->shutdown();
+}
+
+void Q3DSSurfaceViewer::reset()
+{
+ d_ptr->reset();
+}
+
+void Q3DSSurfaceViewer::update()
+{
+ d_ptr->update();
+}
+
+QImage Q3DSSurfaceViewer::grab(const QRect &rect)
+{
+ return d_ptr->grab(rect);
+}
+
+QSize Q3DSSurfaceViewer::size() const
+{
+ return d_ptr->m_size;
+}
+
+void Q3DSSurfaceViewer::setSize(const QSize &size)
+{
+ d_ptr->setSize(size);
+}
+
+bool Q3DSSurfaceViewer::autoSize() const
+{
+ return d_ptr->m_autoSize;
+}
+
+void Q3DSSurfaceViewer::setAutoSize(bool autoSize)
+{
+ if (d_ptr->m_autoSize != autoSize) {
+ d_ptr->m_autoSize = autoSize;
+ Q_EMIT autoSizeChanged(autoSize);
+ }
+}
+
+int Q3DSSurfaceViewer::updateInterval() const
+{
+ return d_ptr->m_updateInterval;
+}
+
+void Q3DSSurfaceViewer::setUpdateInterval(int interval)
+{
+ d_ptr->setUpdateInterval(interval);
+}
+
+bool Q3DSSurfaceViewer::isRunning() const
+{
+ return d_ptr->m_viewerApp != nullptr;
+}
+
+QString Q3DSSurfaceViewer::presentationId() const
+{
+ return d_ptr->m_id;
+}
+
+int Q3DSSurfaceViewer::fboId() const
+{
+ return d_ptr->m_fboId;
+}
+
+QSurface *Q3DSSurfaceViewer::surface() const
+{
+ return d_ptr->m_surface;
+}
+
+QOpenGLContext *Q3DSSurfaceViewer::context() const
+{
+ return d_ptr->m_context;
+}
+
+Q3DSViewerSettings *Q3DSSurfaceViewer::settings() const
+{
+ return d_ptr->m_settings;
+}
+
+Q3DSPresentation *Q3DSSurfaceViewer::presentation() const
+{
+ return d_ptr->m_presentation;
+}
+
+void Q3DSSurfaceViewer::setPresentationId(const QString &id)
+{
+ if (d_ptr->m_id != id) {
+ d_ptr->m_id = id;
+ Q_EMIT presentationIdChanged(id);
+ if (d_ptr->m_viewerApp)
+ d_ptr->m_viewerApp->setPresentationId(id);
+ }
+}
+
+Q3DSSurfaceViewerPrivate::Q3DSSurfaceViewerPrivate(Q3DSSurfaceViewer *q)
+ : QObject(q)
+ , q_ptr(q)
+ , m_viewerApp(nullptr)
+ , m_timer(nullptr)
+ , m_updateInterval(-1)
+ , m_pixelRatio(1.0)
+ , m_fboId(0)
+ , m_surface(nullptr)
+ , m_context(nullptr)
+ , m_autoSize(true)
+ , m_settings(new Q3DSViewerSettings(this))
+ , m_presentation(new Q3DSPresentation(this))
+{
+ m_startupTimer.start();
+ connect(m_presentation, &Q3DSPresentation::sourceChanged,
+ this, &Q3DSSurfaceViewerPrivate::reset);
+}
+
+Q3DSSurfaceViewerPrivate::~Q3DSSurfaceViewerPrivate()
+{
+ releaseRuntime();
+
+ delete m_timer;
+}
+
+void Q3DSSurfaceViewerPrivate::reset()
+{
+ if (m_viewerApp) {
+ releaseRuntime();
+ initializeRuntime();
+ }
+}
+
+void Q3DSSurfaceViewerPrivate::setSize(const QSize &size)
+{
+ if (m_size != size) {
+ m_size = size;
+
+ if (m_viewerApp) {
+ m_context->makeCurrent(m_surface);
+ m_viewerApp->Resize(int(m_size.width() * m_pixelRatio),
+ int(m_size.height() * m_pixelRatio));
+ }
+
+ Q_EMIT q_ptr->sizeChanged(m_size);
+ }
+}
+
+void Q3DSSurfaceViewerPrivate::setUpdateInterval(int interval)
+{
+ if (m_updateInterval != interval) {
+ m_updateInterval = interval;
+ resetUpdateTimer();
+ Q_EMIT q_ptr->updateIntervalChanged(m_updateInterval);
+ }
+}
+
+bool Q3DSSurfaceViewerPrivate::initialize(QSurface *surface, QOpenGLContext *context, GLuint fboId)
+{
+ Q_ASSERT(context);
+ Q_ASSERT(surface);
+
+ if (m_presentation->source().isEmpty()) {
+ qWarning("Failed to initialize Q3DSSurfaceViewer,"
+ " presentation source must be set before calling initialize()");
+ return false;
+ }
+
+ QFileInfo info(Q3DSUtils::urlToLocalFileOrQrc(m_presentation->source()));
+ if (!info.exists()) {
+ qWarning() << "Failed to initialize Q3DSSurfaceViewer, the presentation doesn't exist:"
+ << m_presentation->source().toString();
+ return false;
+ }
+
+ shutdown();
+
+ m_surface = surface;
+ m_context = context;
+ m_fboId = fboId;
+ if (m_surface->surfaceClass() == QSurface::Window && fboId == 0)
+ m_pixelRatio = static_cast<QWindow *>(m_surface)->devicePixelRatio();
+
+ surfaceObject()->installEventFilter(this);
+
+ connect(context, &QOpenGLContext::aboutToBeDestroyed, this, &Q3DSSurfaceViewerPrivate::shutdown);
+
+ bool success = initializeRuntime();
+
+ if (success)
+ Q_EMIT q_ptr->runningChanged(true);
+
+ return success;
+}
+
+
+void Q3DSSurfaceViewerPrivate::shutdown()
+{
+ bool oldInitialized = (m_viewerApp != nullptr);
+
+ if (m_context) {
+ disconnect(m_context, &QOpenGLContext::aboutToBeDestroyed,
+ this, &Q3DSSurfaceViewerPrivate::shutdown);
+ }
+
+ if (m_surface)
+ surfaceObject()->removeEventFilter(this);
+
+ releaseRuntime();
+
+ m_surface = nullptr;
+ m_context = nullptr;
+ m_fboId = 0;
+
+ if (oldInitialized)
+ Q_EMIT q_ptr->runningChanged(false);
+}
+
+
+void Q3DSSurfaceViewerPrivate::update()
+{
+ if (m_viewerApp && m_viewerApp->IsInitialised()) {
+ if (m_surface->surfaceClass() != QSurface::Window
+ || static_cast<QWindow *>(m_surface)->isExposed()) {
+ m_context->makeCurrent(m_surface);
+ if (m_autoSize)
+ setSize(m_surface->size());
+ m_viewerApp->Render();
+
+ if (m_fboId == 0)
+ m_context->swapBuffers(m_surface);
+
+ Q_EMIT q_ptr->frameUpdated();
+ }
+ }
+}
+
+extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format,
+ bool include_alpha);
+
+QImage Q3DSSurfaceViewerPrivate::grab(const QRect &rect)
+{
+ QRect captureRect;
+ QSize fullSize = m_size * m_pixelRatio;
+ if (rect.isValid()) {
+ captureRect = QRect(rect.x() * m_pixelRatio, rect.y() * m_pixelRatio,
+ rect.width() * m_pixelRatio, rect.height() * m_pixelRatio);
+ } else {
+ captureRect = QRect(0, 0, fullSize.width(), fullSize.height());
+ }
+ QImage image(captureRect.size(), QImage::Format_ARGB32);
+
+ if (m_surface && m_context && m_viewerApp && m_viewerApp->IsInitialised()
+ && (m_surface->surfaceClass() != QSurface::Window
+ || static_cast<QWindow *>(m_surface)->isExposed())) {
+ m_context->makeCurrent(m_surface);
+
+ // Render now to ensure the image is up to date and will actually exist in case
+ // the surface has a non-preserved swap buffer
+ if (m_autoSize)
+ setSize(m_surface->size());
+ m_viewerApp->Render();
+
+ m_context->functions()->glBindFramebuffer(GL_FRAMEBUFFER, m_fboId);
+ QImage fullGrab = qt_gl_read_framebuffer(fullSize, false, false);
+
+ // Also update the screen to match the grab, since we just rendered
+ if (m_fboId == 0)
+ m_context->swapBuffers(m_surface);
+
+ if (captureRect.size() == fullSize)
+ image = fullGrab;
+ else
+ image = fullGrab.copy(captureRect);
+ }
+
+ return image;
+}
+
+bool Q3DSSurfaceViewerPrivate::eventFilter(QObject *obj, QEvent *e)
+{
+ if (m_surface && e->type() == QEvent::PlatformSurface) {
+ if (surfaceObject() == obj) {
+ QPlatformSurfaceEvent *ev = static_cast<QPlatformSurfaceEvent *>(e);
+ if (ev->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed)
+ shutdown();
+ }
+ }
+ return QObject::eventFilter(obj, e);
+}
+
+bool Q3DSSurfaceViewerPrivate::initializeRuntime()
+{
+ Q_ASSERT(!m_viewerApp);
+
+ m_context->makeCurrent(m_surface);
+
+ m_viewerApp = &Q3DSViewerApp::Create(m_context, new Qt3DSAudioPlayerImpl(), &m_startupTimer);
+ connect(m_viewerApp, &Q3DSViewerApp::SigPresentationReady,
+ this->q_ptr, &Q3DSSurfaceViewer::presentationReady);
+ connect(m_viewerApp, &Q3DSViewerApp::SigPresentationLoaded,
+ this->q_ptr, &Q3DSSurfaceViewer::presentationLoaded);
+ Q_ASSERT(m_viewerApp);
+
+ const QString localSource = Q3DSUtils::urlToLocalFileOrQrc(m_presentation->source());
+
+ if (m_autoSize)
+ m_size = m_surface->size();
+
+ if (!m_viewerApp->InitializeApp(int(m_size.width() * m_pixelRatio),
+ int(m_size.height() * m_pixelRatio),
+ m_context->format(), m_fboId, localSource,
+ m_presentation->variantList(),
+ m_presentation->delayedLoading(),
+ m_presentation->d_ptr->streamProxy())) {
+ releaseRuntime();
+ qWarning("Failed to initialize runtime");
+ return false;
+ }
+
+ if (!m_id.isEmpty())
+ m_viewerApp->setPresentationId(m_id);
+ m_settings->d_ptr->setViewerApp(m_viewerApp);
+ m_presentation->d_ptr->setViewerApp(m_viewerApp);
+
+ resetUpdateTimer();
+
+ return true;
+}
+
+void Q3DSSurfaceViewerPrivate::releaseRuntime()
+{
+ m_settings->d_ptr->setViewerApp(nullptr);
+ m_presentation->d_ptr->setViewerApp(nullptr);
+
+ if (m_context && m_surface)
+ m_context->makeCurrent(m_surface);
+
+ if (m_viewerApp) {
+ m_viewerApp->Release();
+ m_viewerApp = nullptr;
+ }
+
+ resetUpdateTimer();
+}
+
+void Q3DSSurfaceViewerPrivate::resetUpdateTimer()
+{
+ if (m_viewerApp && m_updateInterval >= 0) {
+ if (!m_timer) {
+ m_timer = new QTimer();
+ connect(m_timer, &QTimer::timeout, this, &Q3DSSurfaceViewerPrivate::update);
+ }
+ m_timer->start(m_updateInterval);
+ } else if (m_timer) {
+ m_timer->stop();
+ }
+}
+
+QObject *Q3DSSurfaceViewerPrivate::surfaceObject()
+{
+ if (m_surface) {
+ if (m_surface->surfaceClass() == QSurface::Window)
+ return static_cast<QWindow *>(m_surface);
+ else
+ return static_cast<QOffscreenSurface *>(m_surface);
+ }
+ return nullptr;
+}
+
+QT_END_NAMESPACE
diff --git a/src/Runtime/api/studio3d/q3dssurfaceviewer.h b/src/Runtime/api/studio3d/q3dssurfaceviewer.h
new file mode 100644
index 00000000..90d25aa1
--- /dev/null
+++ b/src/Runtime/api/studio3d/q3dssurfaceviewer.h
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** 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 Q3DSSURFACEVIEWER_H
+#define Q3DSSURFACEVIEWER_H
+
+#include <QtStudio3D/qstudio3dglobal.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qsize.h>
+#include <QtCore/qurl.h>
+#include <QtGui/qimage.h>
+#include <QtGui/qopengl.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q3DSSurfaceViewerPrivate;
+class QSurface;
+class QOpenGLContext;
+class Q3DSViewerSettings;
+class Q3DSPresentation;
+
+class Q_STUDIO3D_EXPORT Q3DSSurfaceViewer : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(Q3DSSurfaceViewer)
+ Q_PROPERTY(QSize size READ size WRITE setSize NOTIFY sizeChanged)
+ Q_PROPERTY(bool autoSize READ autoSize WRITE setAutoSize NOTIFY autoSizeChanged)
+ Q_PROPERTY(int updateInterval READ updateInterval WRITE setUpdateInterval NOTIFY updateIntervalChanged)
+ Q_PROPERTY(bool running READ isRunning NOTIFY runningChanged)
+ Q_PROPERTY(QString presentationId READ presentationId WRITE setPresentationId NOTIFY presentationIdChanged)
+
+public:
+ explicit Q3DSSurfaceViewer(QObject *parent = nullptr);
+ ~Q3DSSurfaceViewer();
+
+ bool initialize(QSurface *surface, QOpenGLContext *context, GLuint fboId = 0);
+
+ QImage grab(const QRect &rect = QRect());
+
+ // Property accessors
+ QSize size() const;
+ bool autoSize() const;
+ int updateInterval() const;
+ bool isRunning() const;
+ QString presentationId() const;
+
+ int fboId() const;
+ QSurface *surface() const;
+ QOpenGLContext *context() const;
+
+ Q3DSViewerSettings *settings() const;
+ Q3DSPresentation *presentation() const;
+
+public Q_SLOTS:
+ void setSize(const QSize &size);
+ void setAutoSize(bool autoSize);
+ void setUpdateInterval(int interval);
+ void update();
+ void shutdown();
+ void reset();
+ void setPresentationId(const QString &id);
+
+Q_SIGNALS:
+ void presentationLoaded();
+ void presentationReady();
+ void sizeChanged(const QSize &size);
+ void autoSizeChanged(bool autoSize);
+ void updateIntervalChanged(bool autoUpdate);
+ void runningChanged(bool initialized);
+ void frameUpdated();
+ void presentationIdChanged(const QString &id);
+
+private:
+ Q_DISABLE_COPY(Q3DSSurfaceViewer)
+ Q3DSSurfaceViewerPrivate *d_ptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // Q3DSSURFACEVIEWER_H
diff --git a/src/Runtime/api/studio3d/q3dssurfaceviewer_p.h b/src/Runtime/api/studio3d/q3dssurfaceviewer_p.h
new file mode 100644
index 00000000..9c56c1b5
--- /dev/null
+++ b/src/Runtime/api/studio3d/q3dssurfaceviewer_p.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** 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 Q3DSSURFACEVIEWER_P_H
+#define Q3DSSURFACEVIEWER_P_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 "q3dssurfaceviewer.h"
+#include "Qt3DSViewerApp.h"
+
+#include <QtCore/qtimer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSurface;
+class QOpenGLContext;
+class Q3DSViewerSettings;
+class Q3DSPresentation;
+
+class Q_STUDIO3D_EXPORT Q3DSSurfaceViewerPrivate : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PUBLIC(Q3DSSurfaceViewer)
+public:
+ explicit Q3DSSurfaceViewerPrivate(Q3DSSurfaceViewer *parent = nullptr);
+ ~Q3DSSurfaceViewerPrivate();
+
+ void reset();
+ void setSize(const QSize &size);
+ void setUpdateInterval(int interval);
+ bool initialize(QSurface *surface, QOpenGLContext *context, GLuint fboId);
+ void update();
+
+ QImage grab(const QRect &rect);
+
+private Q_SLOTS:
+ void shutdown();
+
+protected:
+ bool eventFilter(QObject *obj, QEvent *e) override;
+
+private:
+ bool initializeRuntime();
+ void releaseRuntime();
+ void resetUpdateTimer();
+ QObject *surfaceObject();
+
+ Q3DSSurfaceViewer *q_ptr;
+
+ Q3DSViewer::Q3DSViewerApp *m_viewerApp;
+ QSize m_size;
+ QTimer *m_timer;
+ int m_updateInterval;
+ qreal m_pixelRatio;
+ GLuint m_fboId;
+ QSurface *m_surface; // Not owned
+ QOpenGLContext *m_context; // Not owned
+ bool m_autoSize;
+ Q3DSViewerSettings *m_settings;
+ Q3DSPresentation *m_presentation;
+ QString m_id;
+ QElapsedTimer m_startupTimer;
+};
+
+QT_END_NAMESPACE
+
+#endif // Q3DSSURFACEVIEWER_P_H
diff --git a/src/Runtime/api/studio3d/q3dsviewersettings.cpp b/src/Runtime/api/studio3d/q3dsviewersettings.cpp
new file mode 100644
index 00000000..b6660c84
--- /dev/null
+++ b/src/Runtime/api/studio3d/q3dsviewersettings.cpp
@@ -0,0 +1,244 @@
+/****************************************************************************
+**
+** 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 "q3dsviewersettings_p.h"
+#include "Qt3DSViewerApp.h"
+#include "q3dscommandqueue_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qsettings.h>
+#include <QtCore/qcoreapplication.h>
+
+QT_BEGIN_NAMESPACE
+
+Q3DSViewerSettings::Q3DSViewerSettings(QObject *parent)
+ : QObject(parent)
+ , d_ptr(new Q3DSViewerSettingsPrivate(this))
+{
+}
+
+Q3DSViewerSettings::~Q3DSViewerSettings()
+{
+}
+
+QColor Q3DSViewerSettings::matteColor() const
+{
+ return d_ptr->m_matteColor;
+}
+
+bool Q3DSViewerSettings::isShowRenderStats() const
+{
+ return d_ptr->m_showRenderStats;
+}
+
+Q3DSViewerSettings::ShadeMode Q3DSViewerSettings::shadeMode() const
+{
+ return d_ptr->m_shadeMode;
+}
+
+Q3DSViewerSettings::ScaleMode Q3DSViewerSettings::scaleMode() const
+{
+ return d_ptr->m_scaleMode;
+}
+
+void Q3DSViewerSettings::save(const QString &group, const QString &organization,
+ const QString &application)
+{
+ d_ptr->save(group, organization, application);
+}
+
+void Q3DSViewerSettings::load(const QString &group, const QString &organization,
+ const QString &application)
+{
+ d_ptr->load(group, organization, application);
+}
+
+void Q3DSViewerSettings::setMatteColor(const QColor &color)
+{
+ if (d_ptr->m_matteColor != color) {
+ d_ptr->setMatteColor(color);
+ Q_EMIT matteColorChanged(color);
+ }
+}
+
+void Q3DSViewerSettings::setShowRenderStats(bool show)
+{
+ if (d_ptr->m_showRenderStats != show) {
+ d_ptr->setShowRenderStats(show);
+ Q_EMIT showRenderStatsChanged(show);
+ }
+}
+
+void Q3DSViewerSettings::setShadeMode(Q3DSViewerSettings::ShadeMode mode)
+{
+ if (d_ptr->m_shadeMode != mode) {
+ d_ptr->setShadeMode(mode);
+ Q_EMIT shadeModeChanged(mode);
+ }
+
+}
+
+void Q3DSViewerSettings::setScaleMode(Q3DSViewerSettings::ScaleMode mode)
+{
+ if (d_ptr->m_scaleMode != mode) {
+ d_ptr->setScaleMode(mode);
+ Q_EMIT scaleModeChanged(mode);
+ }
+}
+
+Q3DSViewerSettingsPrivate::Q3DSViewerSettingsPrivate(Q3DSViewerSettings *q)
+ : QObject(q)
+ , q_ptr(q)
+ , m_viewerApp(nullptr)
+ , m_commandQueue(nullptr)
+ , m_matteColor(Qt::black)
+ , m_showRenderStats(false)
+ , m_shadeMode(Q3DSViewerSettings::ShadeModeShaded)
+ , m_scaleMode(Q3DSViewerSettings::ScaleModeCenter)
+ , m_savedSettings(nullptr)
+{
+}
+
+Q3DSViewerSettingsPrivate::~Q3DSViewerSettingsPrivate()
+{
+}
+
+void Q3DSViewerSettingsPrivate::setViewerApp(Q3DSViewer::Q3DSViewerApp *app)
+{
+ m_viewerApp = app;
+ if (m_viewerApp) {
+ setMatteColor(m_matteColor);
+ setShowRenderStats(m_showRenderStats);
+ setShadeMode(m_shadeMode);
+ setScaleMode(m_scaleMode);
+ }
+}
+
+void Q3DSViewerSettingsPrivate::setCommandQueue(CommandQueue *queue)
+{
+ m_commandQueue = queue;
+ if (m_commandQueue) {
+ setMatteColor(m_matteColor);
+ setShowRenderStats(m_showRenderStats);
+ setShadeMode(m_shadeMode);
+ setScaleMode(m_scaleMode);
+ }
+}
+
+void Q3DSViewerSettingsPrivate::save(const QString &group, const QString &organization,
+ const QString &application)
+{
+ initSettingsStore(group, organization, application);
+
+ m_savedSettings->setValue(QStringLiteral("matteColor"), m_matteColor);
+ m_savedSettings->setValue(QStringLiteral("showRenderStats"), m_showRenderStats);
+ m_savedSettings->setValue(QStringLiteral("shadeMode"), m_shadeMode);
+ m_savedSettings->setValue(QStringLiteral("scaleMode"), m_scaleMode);
+}
+
+void Q3DSViewerSettingsPrivate::load(const QString &group, const QString &organization,
+ const QString &application)
+{
+ initSettingsStore(group, organization, application);
+
+ q_ptr->setMatteColor(m_savedSettings->value(QStringLiteral("matteColor")).value<QColor>());
+ q_ptr->setShowRenderStats(m_savedSettings->value(QStringLiteral("showRenderStats")).toBool());
+ q_ptr->setShadeMode(Q3DSViewerSettings::ShadeMode(
+ m_savedSettings->value(QStringLiteral("shadeMode")).toInt()));
+ q_ptr->setScaleMode(Q3DSViewerSettings::ScaleMode(
+ m_savedSettings->value(QStringLiteral("scaleMode")).toInt()));
+}
+
+void Q3DSViewerSettingsPrivate::setMatteColor(const QColor &color)
+{
+ m_matteColor = color;
+ if (m_viewerApp) {
+ m_viewerApp->setMatteColor(color);
+ } else if (m_commandQueue) {
+ m_commandQueue->m_matteColor = color;
+ m_commandQueue->m_matteColorChanged = true;
+ }
+}
+
+void Q3DSViewerSettingsPrivate::setShowRenderStats(bool show)
+{
+ m_showRenderStats = show;
+ if (m_viewerApp) {
+ m_viewerApp->setShowOnScreenStats(show);
+ } else if (m_commandQueue) {
+ m_commandQueue->m_showRenderStats = show;
+ m_commandQueue->m_showRenderStatsChanged = true;
+ }
+}
+
+void Q3DSViewerSettingsPrivate::setShadeMode(Q3DSViewerSettings::ShadeMode mode)
+{
+ m_shadeMode = mode;
+ if (m_viewerApp) {
+ if (mode == Q3DSViewerSettings::ShadeModeShaded)
+ m_viewerApp->SetShadeMode(Q3DSViewer::ViewerShadeModes::Shaded);
+ else
+ m_viewerApp->SetShadeMode(Q3DSViewer::ViewerShadeModes::ShadedWireframe);
+ } else if (m_commandQueue) {
+ m_commandQueue->m_shadeMode = mode;
+ m_commandQueue->m_shadeModeChanged = true;
+ }
+}
+
+void Q3DSViewerSettingsPrivate::setScaleMode(Q3DSViewerSettings::ScaleMode mode)
+{
+ m_scaleMode = mode;
+ if (m_viewerApp) {
+ if (mode == Q3DSViewerSettings::ScaleModeFit)
+ m_viewerApp->SetScaleMode(Q3DSViewer::ViewerScaleModes::ScaleToFit);
+ else if (mode == Q3DSViewerSettings::ScaleModeFill)
+ m_viewerApp->SetScaleMode(Q3DSViewer::ViewerScaleModes::ScaleToFill);
+ else
+ m_viewerApp->SetScaleMode(Q3DSViewer::ViewerScaleModes::ExactSize);
+ } else if (m_commandQueue) {
+ m_commandQueue->m_scaleMode = mode;
+ m_commandQueue->m_scaleModeChanged = true;
+ }
+}
+
+void Q3DSViewerSettingsPrivate::initSettingsStore(const QString &group, const QString &organization,
+ const QString &application)
+{
+ if (!m_savedSettings) {
+ QString org = organization.isEmpty() ? QCoreApplication::instance()->organizationName()
+ : organization;
+ QString app = application.isEmpty() ? QCoreApplication::instance()->applicationName()
+ : application;
+
+ m_savedSettings = new QSettings(org, app, this);
+ m_savedSettings->beginGroup(group);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/Runtime/api/studio3d/q3dsviewersettings.h b/src/Runtime/api/studio3d/q3dsviewersettings.h
new file mode 100644
index 00000000..82d7d62e
--- /dev/null
+++ b/src/Runtime/api/studio3d/q3dsviewersettings.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** 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 Q3DSVIEWERSETTINGS_H
+#define Q3DSVIEWERSETTINGS_H
+
+#include <QtStudio3D/qstudio3dglobal.h>
+#include <QtCore/qobject.h>
+#include <QtGui/qcolor.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q3DSViewerSettingsPrivate;
+
+class Q_STUDIO3D_EXPORT Q3DSViewerSettings : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(Q3DSViewerSettings)
+ Q_ENUMS(ShadeMode)
+ Q_ENUMS(ScaleMode)
+ Q_PROPERTY(QColor matteColor READ matteColor WRITE setMatteColor NOTIFY matteColorChanged)
+ Q_PROPERTY(bool showRenderStats READ isShowRenderStats WRITE setShowRenderStats NOTIFY showRenderStatsChanged)
+ Q_PROPERTY(ShadeMode shadeMode READ shadeMode WRITE setShadeMode NOTIFY shadeModeChanged)
+ Q_PROPERTY(ScaleMode scaleMode READ scaleMode WRITE setScaleMode NOTIFY scaleModeChanged)
+
+public:
+ enum ShadeMode {
+ ShadeModeShaded,
+ ShadeModeShadedWireframe
+ };
+
+ enum ScaleMode {
+ ScaleModeFit,
+ ScaleModeFill,
+ ScaleModeCenter
+ };
+
+ explicit Q3DSViewerSettings(QObject *parent = nullptr);
+ ~Q3DSViewerSettings();
+
+ QColor matteColor() const;
+ bool isShowRenderStats() const;
+ ShadeMode shadeMode() const;
+ ScaleMode scaleMode() const;
+
+ Q_INVOKABLE void save(const QString &group, const QString &organization = QString(),
+ const QString &application = QString());
+ Q_INVOKABLE void load(const QString &group, const QString &organization = QString(),
+ const QString &application = QString());
+
+public Q_SLOTS:
+ void setMatteColor(const QColor &color);
+ void setShowRenderStats(bool show);
+ void setShadeMode(ShadeMode mode);
+ void setScaleMode(ScaleMode mode);
+
+Q_SIGNALS:
+ void matteColorChanged(const QColor &color);
+ void showRenderStatsChanged(bool show);
+ void shadeModeChanged(ShadeMode mode);
+ void scaleModeChanged(ScaleMode mode);
+
+private:
+ Q_DISABLE_COPY(Q3DSViewerSettings)
+ Q3DSViewerSettingsPrivate *d_ptr;
+
+ friend class Q3DSSurfaceViewerPrivate;
+ friend class Q3DSWidgetPrivate;
+ friend class Q3DSRenderer;
+ friend class Q3DSStudio3D;
+};
+
+QT_END_NAMESPACE
+
+#endif // Q3DSVIEWERSETTINGS_H
diff --git a/src/Runtime/api/studio3d/q3dsviewersettings_p.h b/src/Runtime/api/studio3d/q3dsviewersettings_p.h
new file mode 100644
index 00000000..48fbae3a
--- /dev/null
+++ b/src/Runtime/api/studio3d/q3dsviewersettings_p.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** 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 Q3DSVIEWERSETTINGS_P_H
+#define Q3DSVIEWERSETTINGS_P_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 "q3dsviewersettings.h"
+#include "Qt3DSViewerApp.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSettings;
+class CommandQueue;
+
+class Q_STUDIO3D_EXPORT Q3DSViewerSettingsPrivate : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PUBLIC(Q3DSViewerSettings)
+public:
+ explicit Q3DSViewerSettingsPrivate(Q3DSViewerSettings *parent);
+ ~Q3DSViewerSettingsPrivate();
+
+ void setViewerApp(Q3DSViewer::Q3DSViewerApp *app);
+ void setCommandQueue(CommandQueue *queue);
+ void save(const QString &group, const QString &organization, const QString &application);
+ void load(const QString &group, const QString &organization, const QString &application);
+
+ void setMatteColor(const QColor &color);
+ void setShowRenderStats(bool show);
+ void setShadeMode(Q3DSViewerSettings::ShadeMode mode);
+ void setScaleMode(Q3DSViewerSettings::ScaleMode mode);
+
+public:
+ Q3DSViewerSettings *q_ptr;
+
+private:
+ void initSettingsStore(const QString &group, const QString &organization,
+ const QString &application);
+
+ Q3DSViewer::Q3DSViewerApp *m_viewerApp; // Not owned
+ CommandQueue *m_commandQueue; // Not owned
+ QColor m_matteColor;
+ bool m_showRenderStats;
+ Q3DSViewerSettings::ShadeMode m_shadeMode;
+ Q3DSViewerSettings::ScaleMode m_scaleMode;
+ QSettings *m_savedSettings;
+};
+
+QT_END_NAMESPACE
+
+#endif // Q3DSVIEWERSETTINGS_P_H
diff --git a/src/Runtime/api/studio3d/q3dswidget.cpp b/src/Runtime/api/studio3d/q3dswidget.cpp
new file mode 100644
index 00000000..23334b5b
--- /dev/null
+++ b/src/Runtime/api/studio3d/q3dswidget.cpp
@@ -0,0 +1,332 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 - 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 "q3dswidget_p.h"
+#include "Qt3DSAudioPlayerImpl.h"
+#include "viewerqmlstreamproxy_p.h"
+#include "q3dsviewersettings_p.h"
+#include "q3dspresentation_p.h"
+#include "studioutils_p.h"
+#include "q3dsvariantconfig_p.h"
+
+#include <QtGui/qevent.h>
+#include <QtGui/qopenglcontext.h>
+#include <QtGui/QWindow>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qdebug.h>
+
+using namespace Q3DSViewer;
+
+QT_BEGIN_NAMESPACE
+
+typedef void (QWidget::*QWidgetVoidSlot)();
+
+Q3DSWidget::Q3DSWidget(QWidget *parent)
+ : QOpenGLWidget(parent)
+ , d_ptr(new Q3DSWidgetPrivate(this))
+{
+ // Get keyboard handling
+ setFocusPolicy(Qt::StrongFocus);
+ setMouseTracking(true);
+}
+
+Q3DSWidget::~Q3DSWidget()
+{
+ delete d_ptr;
+}
+
+bool Q3DSWidget::initialize()
+{
+ return d_ptr->initialize();
+}
+
+int Q3DSWidget::updateInterval() const
+{
+ return d_ptr->m_updateInterval;
+}
+
+bool Q3DSWidget::isRunning() const
+{
+ return d_ptr->m_viewerApp != nullptr;
+}
+
+Q3DSViewerSettings *Q3DSWidget::settings() const
+{
+ return d_ptr->settings();
+}
+
+Q3DSPresentation *Q3DSWidget::presentation() const
+{
+ return d_ptr->presentation();
+}
+
+void Q3DSWidget::initializeGL()
+{
+ // Find the native window to determine pixel ratio
+ QWidget *widget = this;
+ QWindow *window = windowHandle();
+ while (widget && window == nullptr) {
+ widget = qobject_cast<QWidget *>(widget->parent());
+ window = widget->windowHandle();
+ }
+ if (window)
+ d_ptr->m_pixelRatio = window->devicePixelRatio();
+}
+
+void Q3DSWidget::resizeGL(int w, int h)
+{
+ if (d_ptr->m_viewerApp)
+ d_ptr->m_viewerApp->Resize(int(w * d_ptr->m_pixelRatio), int(h * d_ptr->m_pixelRatio));
+}
+
+void Q3DSWidget::paintGL()
+{
+ if (d_ptr->m_viewerApp && d_ptr->m_viewerApp->IsInitialised())
+ d_ptr->m_viewerApp->Render();
+}
+
+void Q3DSWidget::setUpdateInterval(int interval)
+{
+ d_ptr->setUpdateInterval(interval);
+}
+
+void Q3DSWidget::shutdown()
+{
+ d_ptr->shutdown();
+}
+
+void Q3DSWidget::reset()
+{
+ d_ptr->reset();
+}
+
+void Q3DSWidget::mousePressEvent(QMouseEvent *event)
+{
+ if (d_ptr->m_pixelRatio != 1.0) {
+ QMouseEvent scaledEvent(event->type(), event->pos() * d_ptr->m_pixelRatio,
+ event->button(), event->buttons(), event->modifiers());
+ d_ptr->m_presentation->mousePressEvent(&scaledEvent);
+ } else {
+ d_ptr->m_presentation->mousePressEvent(event);
+ }
+}
+
+void Q3DSWidget::mouseReleaseEvent(QMouseEvent *event)
+{
+ if (d_ptr->m_pixelRatio != 1.0) {
+ QMouseEvent scaledEvent(event->type(), event->pos() * d_ptr->m_pixelRatio,
+ event->button(), event->buttons(), event->modifiers());
+ d_ptr->m_presentation->mouseReleaseEvent(&scaledEvent);
+ } else {
+ d_ptr->m_presentation->mouseReleaseEvent(event);
+ }
+}
+
+void Q3DSWidget::mouseMoveEvent(QMouseEvent *event)
+{
+ if (d_ptr->m_pixelRatio != 1.0) {
+ QMouseEvent scaledEvent(event->type(), event->pos() * d_ptr->m_pixelRatio,
+ event->button(), event->buttons(), event->modifiers());
+ d_ptr->m_presentation->mouseMoveEvent(&scaledEvent);
+ } else {
+ d_ptr->m_presentation->mouseMoveEvent(event);
+ }
+}
+
+void Q3DSWidget::wheelEvent(QWheelEvent *event)
+{
+ d_ptr->m_presentation->wheelEvent(event);
+}
+
+void Q3DSWidget::keyPressEvent(QKeyEvent *event)
+{
+ d_ptr->m_presentation->keyPressEvent(event);
+}
+
+void Q3DSWidget::keyReleaseEvent(QKeyEvent *event)
+{
+ d_ptr->m_presentation->keyReleaseEvent(event);
+}
+
+Q3DSWidgetPrivate::Q3DSWidgetPrivate(Q3DSWidget *q)
+ : QObject(q)
+ , q_ptr(q)
+ , m_viewerApp(nullptr)
+ , m_timer(nullptr)
+ , m_updateInterval(-1)
+ , m_pixelRatio(1.0)
+ , m_settings(new Q3DSViewerSettings(this))
+ , m_presentation(new Q3DSPresentation(this))
+{
+ m_startupTimer.start();
+ connect(m_presentation, &Q3DSPresentation::sourceChanged, this, &Q3DSWidgetPrivate::reset);
+}
+
+Q3DSWidgetPrivate::~Q3DSWidgetPrivate()
+{
+ releaseRuntime();
+
+ delete m_timer;
+}
+
+void Q3DSWidgetPrivate::reset()
+{
+ if (m_viewerApp) {
+ releaseRuntime();
+ initializeRuntime();
+ }
+}
+
+void Q3DSWidgetPrivate::setUpdateInterval(int interval)
+{
+ if (m_updateInterval != interval) {
+ m_updateInterval = interval;
+ resetUpdateTimer();
+ Q_EMIT q_ptr->updateIntervalChanged(m_updateInterval);
+ }
+}
+
+bool Q3DSWidgetPrivate::initialize()
+{
+ Q_ASSERT(q_ptr->context());
+
+ if (m_presentation->source().isEmpty()) {
+ qWarning("Failed to initialize Q3DSWidget,"
+ " presentation source must be set before calling initialize()");
+ return false;
+ }
+
+ QFileInfo info(Q3DSUtils::urlToLocalFileOrQrc(m_presentation->source()));
+ if (!info.exists()) {
+ qWarning() << "Failed to initialize Q3DSWidget, the presentation doesn't exist:"
+ << m_presentation->source().toString();
+ return false;
+ }
+
+ shutdown();
+
+ connect(q_ptr->context(), &QOpenGLContext::aboutToBeDestroyed,
+ this, &Q3DSWidgetPrivate::shutdown);
+
+ bool success = initializeRuntime();
+
+ if (success)
+ Q_EMIT q_ptr->runningChanged(true);
+
+ return success;
+}
+
+Q3DSViewerSettings *Q3DSWidgetPrivate::settings()
+{
+ return m_settings;
+}
+
+Q3DSPresentation *Q3DSWidgetPrivate::presentation()
+{
+ return m_presentation;
+}
+
+void Q3DSWidgetPrivate::shutdown()
+{
+ bool oldInitialized = (m_viewerApp != nullptr);
+
+ if (q_ptr->context()) {
+ disconnect(q_ptr->context(), &QOpenGLContext::aboutToBeDestroyed,
+ this, &Q3DSWidgetPrivate::shutdown);
+ }
+
+ releaseRuntime();
+
+ if (oldInitialized)
+ Q_EMIT q_ptr->runningChanged(false);
+}
+
+bool Q3DSWidgetPrivate::initializeRuntime()
+{
+ Q_ASSERT(!m_viewerApp);
+
+ q_ptr->makeCurrent();
+
+ m_viewerApp = &Q3DSViewerApp::Create(q_ptr->context(), new Qt3DSAudioPlayerImpl(),
+ &m_startupTimer);
+
+ Q_ASSERT(m_viewerApp);
+
+ const QString localSource = Q3DSUtils::urlToLocalFileOrQrc(m_presentation->source());
+
+ if (!m_viewerApp->InitializeApp(int(q_ptr->width() * m_pixelRatio),
+ int(q_ptr->height() * m_pixelRatio),
+ q_ptr->context()->format(),
+ q_ptr->defaultFramebufferObject(), localSource,
+ m_presentation->variantList(),
+ m_presentation->delayedLoading(),
+ m_presentation->d_ptr->streamProxy())) {
+ releaseRuntime();
+ qWarning("Failed to initialize runtime");
+ return false;
+ }
+
+ m_settings->d_ptr->setViewerApp(m_viewerApp);
+ m_presentation->d_ptr->setViewerApp(m_viewerApp);
+
+ resetUpdateTimer();
+
+ return true;
+}
+
+void Q3DSWidgetPrivate::releaseRuntime()
+{
+ m_settings->d_ptr->setViewerApp(nullptr);
+ m_presentation->d_ptr->setViewerApp(nullptr);
+
+ if (m_viewerApp) {
+ q_ptr->makeCurrent();
+ m_viewerApp->Release();
+ m_viewerApp = nullptr;
+ }
+
+ resetUpdateTimer();
+}
+
+void Q3DSWidgetPrivate::resetUpdateTimer()
+{
+ if (m_viewerApp && m_updateInterval >= 0) {
+ if (!m_timer) {
+ m_timer = new QTimer();
+ connect(m_timer, &QTimer::timeout,
+ q_ptr, static_cast<QWidgetVoidSlot>(&QWidget::update));
+ }
+ m_timer->start(m_updateInterval);
+ } else if (m_timer) {
+ m_timer->stop();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/Runtime/api/studio3d/q3dswidget.h b/src/Runtime/api/studio3d/q3dswidget.h
new file mode 100644
index 00000000..ad5d823d
--- /dev/null
+++ b/src/Runtime/api/studio3d/q3dswidget.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 - 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 Q3DSWIDGET_H
+#define Q3DSWIDGET_H
+
+#include <QtStudio3D/qstudio3dglobal.h>
+#include <QtWidgets/QOpenGLWidget>
+#include <QtCore/QUrl>
+
+QT_BEGIN_NAMESPACE
+
+class Q3DSWidgetPrivate;
+class Q3DSViewerSettings;
+class Q3DSPresentation;
+
+class Q_STUDIO3D_EXPORT Q3DSWidget : public QOpenGLWidget
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(Q3DSWidget)
+ Q_PROPERTY(int updateInterval READ updateInterval WRITE setUpdateInterval NOTIFY updateIntervalChanged)
+ Q_PROPERTY(bool running READ isRunning NOTIFY runningChanged)
+
+public:
+ explicit Q3DSWidget(QWidget *parent = nullptr);
+ virtual ~Q3DSWidget();
+
+ bool initialize();
+
+ // Property accessors
+ int updateInterval() const;
+ bool isRunning() const;
+
+ Q3DSViewerSettings *settings() const;
+ Q3DSPresentation *presentation() const;
+
+public Q_SLOTS:
+ void setUpdateInterval(int interval);
+ void shutdown();
+ void reset();
+
+Q_SIGNALS:
+ void updateIntervalChanged(bool autoUpdate);
+ void runningChanged(bool initialized);
+
+protected:
+ // Qt event handling
+ 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 *e) override;
+
+ // Qt overrides
+ void initializeGL() override;
+ void resizeGL(int w, int h) override;
+ void paintGL() override;
+
+private:
+ Q_DISABLE_COPY(Q3DSWidget)
+ Q3DSWidgetPrivate *d_ptr;
+};
+QT_END_NAMESPACE
+#endif // Q3DSWIDGET_H
diff --git a/src/Runtime/api/studio3d/q3dswidget_p.h b/src/Runtime/api/studio3d/q3dswidget_p.h
new file mode 100644
index 00000000..03ca6aac
--- /dev/null
+++ b/src/Runtime/api/studio3d/q3dswidget_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 - 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$
+**
+****************************************************************************/
+
+//
+// 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.
+
+#ifndef Q3DSWIDGET_P_H
+#define Q3DSWIDGET_P_H
+
+#include "q3dswidget.h"
+#include "Qt3DSViewerApp.h"
+
+#include <QtCore/qtimer.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q3DSViewerSettings;
+class Q3DSPresentation;
+
+class Q_STUDIO3D_EXPORT Q3DSWidgetPrivate : public QObject
+{
+public:
+ Q_OBJECT
+ Q_DECLARE_PUBLIC(Q3DSWidget)
+
+public:
+ explicit Q3DSWidgetPrivate(Q3DSWidget *q);
+ virtual ~Q3DSWidgetPrivate();
+
+ void reset();
+ void setUpdateInterval(int interval);
+ bool initialize();
+
+ Q3DSViewerSettings *settings();
+ Q3DSPresentation *presentation();
+
+private Q_SLOTS:
+ void shutdown();
+
+private:
+ bool initializeRuntime();
+ void releaseRuntime();
+ void resetUpdateTimer();
+
+ Q3DSWidget *q_ptr;
+
+ Q3DSViewer::Q3DSViewerApp *m_viewerApp;
+ QTimer *m_timer;
+ int m_updateInterval;
+ qreal m_pixelRatio;
+ QElapsedTimer m_startupTimer;
+
+ Q3DSViewerSettings *m_settings;
+ Q3DSPresentation *m_presentation;
+};
+
+QT_END_NAMESPACE
+
+#endif // Q3DSWIDGET_P_H
diff --git a/src/Runtime/api/studio3d/qstudio3dglobal.h b/src/Runtime/api/studio3d/qstudio3dglobal.h
new file mode 100644
index 00000000..d1960634
--- /dev/null
+++ b/src/Runtime/api/studio3d/qstudio3dglobal.h
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://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 QSTUDIO3D_GLOBAL_H
+#define QSTUDIO3D_GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_STATIC
+# if defined(QT_BUILD_STUDIO3D_LIB)
+# define Q_STUDIO3D_EXPORT Q_DECL_EXPORT
+# else
+# define Q_STUDIO3D_EXPORT Q_DECL_IMPORT
+# endif
+#else
+# define Q_STUDIO3D_EXPORT
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QSTUDIO3D_GLOBAL_H
diff --git a/src/Runtime/api/studio3d/studio3d.pro b/src/Runtime/api/studio3d/studio3d.pro
new file mode 100644
index 00000000..6c5e0585
--- /dev/null
+++ b/src/Runtime/api/studio3d/studio3d.pro
@@ -0,0 +1,53 @@
+TARGET = QtStudio3D
+
+include($$PWD/../../commoninclude.pri)
+QT += opengl widgets qml
+
+qtHaveModule(multimedia) {
+DEFINES += PLATFORM_HAS_QT_MULTIMEDIA_LIB
+QT += multimedia
+}
+CONFIG += console
+
+LIBS += \
+ -lqt3dsopengl$$qtPlatformTargetSuffix() \
+ -lqt3dsqmlstreamer$$qtPlatformTargetSuffix()
+
+HEADERS += \
+ q3dswidget.h \
+ q3dswidget_p.h \
+ q3dssurfaceviewer.h \
+ q3dssurfaceviewer_p.h \
+ qstudio3dglobal.h \
+ viewerqmlstreamproxy_p.h \
+ q3dsviewersettings.h \
+ q3dsviewersettings_p.h \
+ q3dspresentation.h \
+ q3dspresentation_p.h \
+ q3dssceneelement.h \
+ q3dssceneelement_p.h \
+ q3dselement.h \
+ q3dselement_p.h \
+ studioutils_p.h \
+ q3dscommandqueue_p.h \
+ q3dsimagesequencegenerator_p.h \
+ q3dsimagesequencegeneratorthread_p.h \
+ q3dsdatainput.h \
+ q3dsdatainput_p.h
+
+SOURCES += q3dswidget.cpp \
+ q3dssurfaceviewer.cpp \
+ viewerqmlstreamproxy.cpp \
+ q3dsviewersettings.cpp \
+ q3dspresentation.cpp \
+ q3dssceneelement.cpp \
+ q3dselement.cpp \
+ studioutils.cpp \
+ q3dscommandqueue.cpp \
+ q3dsimagesequencegenerator.cpp \
+ q3dsimagesequencegeneratorthread.cpp \
+ q3dsdatainput.cpp
+
+load(qt_module)
+
+OTHER_FILES += $$PWD/../../../doc/src/12-cpp-reference/*
diff --git a/src/Runtime/api/studio3d/studioutils.cpp b/src/Runtime/api/studio3d/studioutils.cpp
new file mode 100644
index 00000000..9156be7f
--- /dev/null
+++ b/src/Runtime/api/studio3d/studioutils.cpp
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** 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 "studioutils_p.h"
+
+#include <QtCore/QString>
+
+QT_BEGIN_NAMESPACE
+
+QString Q3DSUtils::urlToLocalFileOrQrc(const QUrl &url)
+{
+ const QString scheme(url.scheme().toLower());
+ if (scheme == QLatin1String("qrc")) {
+ if (url.authority().isEmpty())
+ return QLatin1Char(':') + url.path();
+ return QString();
+ }
+
+#if defined(Q_OS_ANDROID)
+ if (scheme == QLatin1String("assets")) {
+ if (url.authority().isEmpty())
+ return url.toString();
+ return QString();
+ }
+#endif
+
+ return url.toLocalFile();
+}
+
+QT_END_NAMESPACE
diff --git a/src/Runtime/api/studio3d/studioutils_p.h b/src/Runtime/api/studio3d/studioutils_p.h
new file mode 100644
index 00000000..afec688c
--- /dev/null
+++ b/src/Runtime/api/studio3d/studioutils_p.h
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+//
+// 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 "qstudio3dglobal.h"
+
+#include <QtCore/QUrl>
+
+QT_BEGIN_NAMESPACE
+
+class Q_STUDIO3D_EXPORT Q3DSUtils
+{
+public:
+ static QString urlToLocalFileOrQrc(const QUrl &url);
+};
+
+QT_END_NAMESPACE
diff --git a/src/Runtime/api/studio3d/viewerqmlstreamproxy.cpp b/src/Runtime/api/studio3d/viewerqmlstreamproxy.cpp
new file mode 100644
index 00000000..520dc8c6
--- /dev/null
+++ b/src/Runtime/api/studio3d/viewerqmlstreamproxy.cpp
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** 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 "viewerqmlstreamproxy_p.h"
+
+QT_BEGIN_NAMESPACE
+
+ViewerQmlStreamProxy::ViewerQmlStreamProxy(QObject *parent)
+ : Q3DSQmlStreamProxy(parent)
+{
+}
+
+ViewerQmlStreamProxy::~ViewerQmlStreamProxy()
+{
+}
+
+void ViewerQmlStreamProxy::visit(const char *path)
+{
+ setPath(QLatin1String(path));
+}
+
+void ViewerQmlStreamProxy::visit(const char *type, const char *id, const char *src,
+ const char *args)
+{
+ Q_UNUSED(src);
+ QString assetType = QLatin1String(type);
+ QString presentationId = QLatin1String(id);
+ QString presentationArgs = QLatin1String(args);
+ if (assetType == QLatin1String("presentation-qml"))
+ registerPresentation(presentationId, presentationArgs);
+}
+
+QT_END_NAMESPACE
diff --git a/src/Runtime/api/studio3d/viewerqmlstreamproxy_p.h b/src/Runtime/api/studio3d/viewerqmlstreamproxy_p.h
new file mode 100644
index 00000000..16569c1c
--- /dev/null
+++ b/src/Runtime/api/studio3d/viewerqmlstreamproxy_p.h
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+//
+// 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 "qstudio3dglobal.h"
+#include "q3dsqmlstreamproxy.h"
+#include "Qt3DSViewerApp.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q_STUDIO3D_EXPORT ViewerQmlStreamProxy : public Q3DSQmlStreamProxy,
+ public qt3ds::Qt3DSAssetVisitor
+{
+public:
+ ViewerQmlStreamProxy(QObject *parent = nullptr);
+ ~ViewerQmlStreamProxy();
+
+ void visit(const char *path) override;
+ void visit(const char *type, const char *id, const char *src, const char *args) override;
+};
+
+QT_END_NAMESPACE
diff --git a/src/Runtime/api/studio3dqml/q3dsplugin.cpp b/src/Runtime/api/studio3dqml/q3dsplugin.cpp
new file mode 100644
index 00000000..aa558775
--- /dev/null
+++ b/src/Runtime/api/studio3dqml/q3dsplugin.cpp
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** 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.h"
+#include "q3dspresentationitem.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");
+}
+
+QT_END_NAMESPACE
diff --git a/src/Runtime/api/studio3dqml/q3dsplugin.h b/src/Runtime/api/studio3dqml/q3dsplugin.h
new file mode 100644
index 00000000..999a0659
--- /dev/null
+++ b/src/Runtime/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);
+#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/Runtime/api/studio3dqml/q3dspresentationitem.cpp b/src/Runtime/api/studio3dqml/q3dspresentationitem.cpp
new file mode 100644
index 00000000..6c4c8e36
--- /dev/null
+++ b/src/Runtime/api/studio3dqml/q3dspresentationitem.cpp
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** 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.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
+
+Q3DSPresentationItem::Q3DSPresentationItem(QObject *parent)
+ : Q3DSPresentation(parent)
+ , m_subPresentationSettings(nullptr)
+{
+}
+
+Q3DSPresentationItem::~Q3DSPresentationItem()
+{
+}
+
+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 (item->registeredDataInput(dataInput->name())) {
+ qWarning() << __FUNCTION__
+ << "Duplicate DataInput defined for Presentation.";
+ } else {
+ item->registerDataInput(dataInput);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/Runtime/api/studio3dqml/q3dspresentationitem.h b/src/Runtime/api/studio3dqml/q3dspresentationitem.h
new file mode 100644
index 00000000..3ee2964f
--- /dev/null
+++ b/src/Runtime/api/studio3dqml/q3dspresentationitem.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** 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
+
+#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_PROPERTY(Q3DSSubPresentationSettings *subPresentationSettings READ subPresentationSettings CONSTANT)
+ 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/Runtime/api/studio3dqml/q3dsrenderer.cpp b/src/Runtime/api/studio3dqml/q3dsrenderer.cpp
new file mode 100644
index 00000000..7e063ab4
--- /dev/null
+++ b/src/Runtime/api/studio3dqml/q3dsrenderer.cpp
@@ -0,0 +1,400 @@
+/****************************************************************************
+**
+** 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.h"
+#include "Qt3DSViewerApp.h"
+#include "Qt3DSAudioPlayerImpl.h"
+#include "q3dspresentationitem.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 <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::SigElementCreated,
+ this, &Q3DSRenderer::elementCreated);
+ connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigMaterialCreated,
+ this, &Q3DSRenderer::materialCreated);
+
+ 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_CreateElement: {
+ m_runtime->createElement(cmd.m_elementPath, cmd.m_stringValue,
+ *static_cast<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<QHash<QString, QVariant> *>(command.m_data);
+ command.m_data = nullptr;
+ break;
+ }
+ case CommandType_DeleteElement: {
+ m_runtime->deleteElement(cmd.m_elementPath);
+ break;
+ }
+ case CommandType_CreateMaterial: {
+ m_runtime->createMaterial(cmd.m_elementPath, cmd.m_stringValue);
+ 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_presentation) {
+ const auto diList = m_presentation->dataInputs();
+
+ 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/Runtime/api/studio3dqml/q3dsrenderer.h b/src/Runtime/api/studio3dqml/q3dsrenderer.h
new file mode 100644
index 00000000..12f98aef
--- /dev/null
+++ b/src/Runtime/api/studio3dqml/q3dsrenderer.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** 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
+
+#include <QtGui/qopenglframebufferobject.h>
+#include <QtQuick/qquickframebufferobject.h>
+
+#include "Qt3DSViewerApp.h"
+#include "q3dsstudio3d.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 elementCreated(const QString &elementName, const QString &error);
+ void materialCreated(const QString &name, const QString &error);
+
+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/Runtime/api/studio3dqml/q3dsstudio3d.cpp b/src/Runtime/api/studio3dqml/q3dsstudio3d.cpp
new file mode 100644
index 00000000..2a6c7be2
--- /dev/null
+++ b/src/Runtime/api/studio3dqml/q3dsstudio3d.cpp
@@ -0,0 +1,326 @@
+/****************************************************************************
+**
+** 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.h"
+#include "q3dsrenderer.h"
+#include "q3dspresentationitem.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
+
+Q3DSStudio3D::Q3DSStudio3D()
+ : m_viewerSettings(nullptr)
+ , m_presentation(nullptr)
+ , m_emitRunningChange(false)
+ , m_isRunning(false)
+ , m_ignoreMouseEvents(false)
+ , m_ignoreWheelEvents(false)
+ , m_ignoreKeyboardEvents(false)
+ , m_pixelRatio(1.0)
+{
+ setMirrorVertically(true);
+ connect(this, &Q3DSStudio3D::windowChanged, this, &Q3DSStudio3D::handleWindowChanged);
+ connect(this, &Q3DSStudio3D::visibleChanged, this, &Q3DSStudio3D::handleVisibleChanged);
+
+ setIgnoreEvents(false, false, false);
+}
+
+Q3DSStudio3D::~Q3DSStudio3D()
+{
+}
+
+Q3DSPresentationItem *Q3DSStudio3D::presentation() const
+{
+ return m_presentation;
+}
+
+Q3DSViewerSettings *Q3DSStudio3D::viewerSettings() const
+{
+ return m_viewerSettings;
+}
+
+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);
+ }
+}
+
+void Q3DSStudio3D::setIgnoreEvents(bool mouse, bool wheel, bool keyboard)
+{
+ // TODO: It might be beneficial to have these as properties so they could be acceessed from QML
+ m_ignoreMouseEvents = mouse;
+ m_ignoreWheelEvents = wheel;
+ m_ignoreKeyboardEvents = keyboard;
+
+ if (mouse)
+ setAcceptedMouseButtons(Qt::NoButton);
+ else
+ setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton | Qt::MiddleButton);
+ setAcceptHoverEvents(!mouse);
+}
+
+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();
+}
+
+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);
+}
+
+// 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();
+}
+
+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();
+}
+
+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;
+ }
+ default:
+ qWarning() << __FUNCTION__ << "Unknown command type.";
+ break;
+ }
+}
+
+// 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::exitSlide,
+ m_presentation, &Q3DSPresentation::slideExited);
+ connect(renderer, &Q3DSRenderer::customSignalEmitted,
+ m_presentation, &Q3DSPresentation::customSignalEmitted);
+ connect(renderer, &Q3DSRenderer::elementCreated,
+ m_presentation, &Q3DSPresentation::elementCreated);
+ connect(renderer, &Q3DSRenderer::materialCreated,
+ m_presentation, &Q3DSPresentation::materialCreated);
+ connect(renderer, &Q3DSRenderer::requestResponse,
+ this, &Q3DSStudio3D::requestResponseHandler);
+ connect(renderer, &Q3DSRenderer::presentationLoaded,
+ this, &Q3DSStudio3D::presentationLoaded);
+ connect(renderer, &Q3DSRenderer::presentationReady,
+ this, &Q3DSStudio3D::presentationReady);
+ return renderer;
+}
+
+bool Q3DSStudio3D::isRunning() const
+{
+ return m_isRunning;
+}
+
+/** 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();
+ }
+}
+
+// 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);
+}
+
+void Q3DSStudio3D::mousePressEvent(QMouseEvent *event)
+{
+ if (!m_ignoreMouseEvents) {
+ 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);
+ }
+ }
+}
+
+void Q3DSStudio3D::mouseReleaseEvent(QMouseEvent *event)
+{
+ if (!m_ignoreMouseEvents) {
+ 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);
+ }
+ }
+}
+
+void Q3DSStudio3D::mouseMoveEvent(QMouseEvent *event)
+{
+ if (!m_ignoreMouseEvents) {
+ 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);
+ }
+ }
+}
+
+void Q3DSStudio3D::wheelEvent(QWheelEvent *event)
+{
+ if (!m_ignoreWheelEvents)
+ m_presentation->wheelEvent(event);
+}
+
+void Q3DSStudio3D::keyPressEvent(QKeyEvent *event)
+{
+ if (m_ignoreKeyboardEvents)
+ return;
+ m_presentation->keyPressEvent(event);
+}
+
+void Q3DSStudio3D::keyReleaseEvent(QKeyEvent *event)
+{
+ if (m_ignoreKeyboardEvents)
+ return;
+ if (!event->isAutoRepeat())
+ m_presentation->keyReleaseEvent(event);
+}
+
+QT_END_NAMESPACE
diff --git a/src/Runtime/api/studio3dqml/q3dsstudio3d.h b/src/Runtime/api/studio3dqml/q3dsstudio3d.h
new file mode 100644
index 00000000..484e9f65
--- /dev/null
+++ b/src/Runtime/api/studio3dqml/q3dsstudio3d.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** 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
+
+#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)
+
+public:
+ Q3DSStudio3D();
+ virtual ~Q3DSStudio3D();
+
+ 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;
+
+ void setIgnoreEvents(bool mouse, bool wheel, bool keyboard);
+
+ void componentComplete() override;
+
+Q_SIGNALS:
+ void frameUpdate();
+ void runningChanged(bool initialized);
+ void errorChanged(const QString &error);
+ 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);
+
+protected:
+ Q3DSViewerSettings *m_viewerSettings;
+ Q3DSPresentationItem *m_presentation;
+
+ bool m_emitRunningChange;
+ bool m_isRunning;
+ bool m_ignoreMouseEvents;
+ bool m_ignoreWheelEvents;
+ bool m_ignoreKeyboardEvents;
+
+ CommandQueue m_pendingCommands;
+ qreal m_pixelRatio;
+ QString m_error;
+};
+
+QT_END_NAMESPACE
+
+#endif // Q3DS_STUDIO3D_H
diff --git a/src/Runtime/api/studio3dqml/qmldir b/src/Runtime/api/studio3dqml/qmldir
new file mode 100644
index 00000000..1eaa8f2b
--- /dev/null
+++ b/src/Runtime/api/studio3dqml/qmldir
@@ -0,0 +1,3 @@
+module QtStudio3D.OpenGL
+plugin declarative_qtstudio3dopengl
+classname Q3DSPlugin
diff --git a/src/Runtime/api/studio3dqml/studio3dqml.pro b/src/Runtime/api/studio3dqml/studio3dqml.pro
new file mode 100644
index 00000000..a7bdc392
--- /dev/null
+++ b/src/Runtime/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 \
+ q3dsstudio3d.h \
+ q3dsrenderer.h \
+ q3dspresentationitem.h
+
+LIBS += \
+ -lqt3dsopengl$$qtPlatformTargetSuffix() \
+ -lqt3dsqmlstreamer$$qtPlatformTargetSuffix()
+
+OTHER_FILES += \
+ qmldir
+
+load(qml_plugin)