summaryrefslogtreecommitdiffstats
path: root/src/Runtime
diff options
context:
space:
mode:
Diffstat (limited to 'src/Runtime')
-rw-r--r--src/Runtime/Qt3DSRuntime/Qt3DSRuntime.pro1
-rw-r--r--src/Runtime/Runtime.pro3
-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
46 files changed, 6383 insertions, 2 deletions
diff --git a/src/Runtime/Qt3DSRuntime/Qt3DSRuntime.pro b/src/Runtime/Qt3DSRuntime/Qt3DSRuntime.pro
index ac5a3936..54aa0442 100644
--- a/src/Runtime/Qt3DSRuntime/Qt3DSRuntime.pro
+++ b/src/Runtime/Qt3DSRuntime/Qt3DSRuntime.pro
@@ -67,7 +67,6 @@ macos {
QMAKE_LFLAGS_SONAME = -Wl,-install_name,@rpath/
}
-
PREDEPS_LIBS = qt3dsruntimestatic
include(../../utils.pri)
diff --git a/src/Runtime/Runtime.pro b/src/Runtime/Runtime.pro
index abc3fe7b..aedfb1ee 100644
--- a/src/Runtime/Runtime.pro
+++ b/src/Runtime/Runtime.pro
@@ -2,7 +2,8 @@ TEMPLATE = subdirs
CONFIG += ordered
SUBDIRS += \
Qt3DSRuntimeStatic \
- Qt3DSRuntime
+ Qt3DSRuntime \
+ api
win32 {
SUBDIRS += \
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)