summaryrefslogtreecommitdiffstats
path: root/src/Runtime/ogl-runtime/src/api
diff options
context:
space:
mode:
Diffstat (limited to 'src/Runtime/ogl-runtime/src/api')
-rw-r--r--src/Runtime/ogl-runtime/src/api/api.pro5
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dscommandqueue.cpp346
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dscommandqueue_p.h172
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dsdatainput.cpp403
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dsdatainput.h94
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dsdatainput_p.h83
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dsdataoutput.cpp225
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dsdataoutput.h83
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dsdataoutput_p.h75
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dselement.cpp284
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dselement.h79
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dselement_p.h77
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dsgeometry.cpp152
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dsgeometry.h117
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dsgeometry_p.h67
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dsimagesequencegenerator.cpp56
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dsimagesequencegenerator_p.h67
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dsimagesequencegeneratorthread.cpp190
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dsimagesequencegeneratorthread_p.h90
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dspresentation.cpp1770
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dspresentation.h152
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dspresentation_p.h119
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dssceneelement.cpp436
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dssceneelement.h83
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dssceneelement_p.h81
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dssurfaceviewer.cpp688
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dssurfaceviewer.h116
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dssurfaceviewer_p.h105
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dsviewersettings.cpp401
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dsviewersettings.h104
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/q3dsviewersettings_p.h88
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/qstudio3dglobal.h49
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/studio3d.pro56
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/studioutils.cpp56
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/studioutils_p.h52
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/viewerqmlstreamproxy.cpp59
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3d/viewerqmlstreamproxy_p.h57
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3dqml/q3dsplugin.cpp62
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3dqml/q3dsplugin.h60
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3dqml/q3dspresentationitem.cpp158
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3dqml/q3dspresentationitem_p.h77
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3dqml/q3dsrenderer.cpp458
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3dqml/q3dsrenderer_p.h110
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3dqml/q3dsstudio3d.cpp535
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3dqml/q3dsstudio3d_p.h137
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3dqml/qmldir3
-rw-r--r--src/Runtime/ogl-runtime/src/api/studio3dqml/studio3dqml.pro34
47 files changed, 8771 insertions, 0 deletions
diff --git a/src/Runtime/ogl-runtime/src/api/api.pro b/src/Runtime/ogl-runtime/src/api/api.pro
new file mode 100644
index 00000000..7d5b27d0
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/api.pro
@@ -0,0 +1,5 @@
+TEMPLATE = subdirs
+CONFIG += ordered
+SUBDIRS += \
+ studio3d \
+ studio3dqml
diff --git a/src/Runtime/ogl-runtime/src/api/studio3d/q3dscommandqueue.cpp b/src/Runtime/ogl-runtime/src/api/studio3d/q3dscommandqueue.cpp
new file mode 100644
index 00000000..550dc24f
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3d/q3dscommandqueue.cpp
@@ -0,0 +1,346 @@
+/****************************************************************************
+**
+** 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"
+#include "Qt3DSViewerApp.h"
+
+#include <QtCore/qstringlist.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(CommandType commandType, void *commandData)
+{
+ ElementCommand &cmd = nextFreeCommand();
+
+ cmd.m_commandType = commandType;
+ 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;
+}
+
+ElementCommand &CommandQueue::queueCommand(const QString &elementPath, CommandType commandType,
+ void *commandData)
+{
+ ElementCommand &cmd = nextFreeCommand();
+
+ cmd.m_commandType = commandType;
+ cmd.m_elementPath = elementPath;
+ cmd.m_data = commandData;
+
+ 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:
+ 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_CreateElements:
+ 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_DeleteElements:
+ case CommandType_DeleteMeshes:
+ case CommandType_CreateMeshes:
+ queueCommand(source.m_commandType, source.m_data);
+ fromQueue.commandAt(i).m_data = nullptr; // This queue takes ownership of data
+ break;
+ case CommandType_CreateMaterials:
+ case CommandType_DeleteMaterials:
+ queueCommand(source.m_elementPath, source.m_commandType, source.m_data);
+ fromQueue.commandAt(i).m_data = nullptr; // This queue takes ownership of data
+ break;
+ case CommandType_RequestSlideInfo:
+ case CommandType_UnloadSlide:
+ case CommandType_PreloadSlide:
+ case CommandType_RequestDataInputs:
+ case CommandType_RequestDataOutputs:
+ 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_CreateElements:
+ delete static_cast<QVector<QHash<QString, QVariant>> *>(cmd.m_data);
+ break;
+ case CommandType_DeleteElements:
+ case CommandType_CreateMaterials:
+ case CommandType_DeleteMaterials:
+ case CommandType_DeleteMeshes:
+ delete static_cast<QStringList *>(cmd.m_data);
+ break;
+ case CommandType_CreateMeshes: {
+ delete static_cast<QHash<QString, Q3DSViewer::MeshData> *>(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/ogl-runtime/src/api/studio3d/q3dscommandqueue_p.h b/src/Runtime/ogl-runtime/src/api/studio3d/q3dscommandqueue_p.h
new file mode 100644
index 00000000..12d1b7e3
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3d/q3dscommandqueue_p.h
@@ -0,0 +1,172 @@
+/****************************************************************************
+**
+** 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_CreateElements,
+ CommandType_DeleteElements,
+ CommandType_CreateMaterials,
+ CommandType_DeleteMaterials,
+ CommandType_CreateMeshes,
+ CommandType_DeleteMeshes,
+
+ // Requests
+ CommandType_RequestSlideInfo,
+ CommandType_RequestDataInputs,
+ CommandType_PreloadSlide,
+ CommandType_UnloadSlide,
+ CommandType_RequestDataOutputs
+};
+
+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(CommandType commandType, void *commandData);
+ ElementCommand &queueCommand(const QString &elementPath, CommandType commandType);
+ ElementCommand &queueCommand(const QString &elementPath, CommandType commandType,
+ void *commandData);
+
+ 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/ogl-runtime/src/api/studio3d/q3dsdatainput.cpp b/src/Runtime/ogl-runtime/src/api/studio3d/q3dsdatainput.cpp
new file mode 100644
index 00000000..2e6281e6
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3d/q3dsdatainput.cpp
@@ -0,0 +1,403 @@
+/****************************************************************************
+**
+** 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
+
+/*!
+ \qmltype DataInput
+ \instantiates Q3DSDataInput
+ \inqmlmodule Qt3DStudio
+ \ingroup OpenGLRuntime
+ \brief Controls a data input entry in a Qt 3D Studio presentation.
+ This class is a convenience class for controlling a data input in a presentation.
+ DataInput provides a clean contract between the presentation design and the code.
+ It hides the presentation details from the code while providing a contractual access
+ point to code for controlling aspects of the presentation (e.g. timeline of a
+ subpresentation). It also allows the design to use a single DataInput to drive
+ multiple aspects of the design (e.g. DataInput for speed can change the color of
+ the speedometer, angle of the needle).
+
+ \note There is a performance cost for each registered DataInput, so try to avoid
+ creating unnecessary DataInputs.
+
+ \sa Presentation, DataOutput, Presentation::slideExited, Presentation::slideEntered
+ \sa Presentation::customSignalEmitted
+*/
+
+/*!
+ \class Q3DSDataInput
+ \inmodule OpenGLRuntime
+ \since Qt 3D Studio 2.0
+ \brief Controls a data input entry in a Qt 3D Studio presentation.
+ This class is a convenience class for controlling a data input in a presentation.
+ DataInput provides a clean contract between the presentation design and the code.
+ It hides the presentation details from the code while providing a contractual access
+ point to code for controlling aspects of the presentation (e.g. timeline of a
+ subpresentation). It also allows the design to use a single DataInput to drive
+ multiple aspects of the design (e.g. DataInput for speed can change the color of
+ the speedometer, angle of the needle).
+
+ \note There is a performance cost for each registered DataInput, so try to avoid
+ creating unnecessary DataInputs.
+
+ For other integration points between code and presentation see:
+ \sa Q3DSPresentation::customSignalEmitted
+ \sa Q3DSPresentation::slideEntered
+ \sa Q3DSPresentation::slideExited
+ \sa Q3DSDataOutput
+
+ \sa Q3DSPresentation
+*/
+
+/*!
+ \internal
+ */
+Q3DSDataInput::Q3DSDataInput(QObject *parent)
+ : QObject(parent)
+ , d_ptr(new Q3DSDataInputPrivate(this))
+{
+}
+
+/*!
+ \internal
+ */
+Q3DSDataInput::Q3DSDataInput(const QString &name, QObject *parent)
+ : QObject(parent)
+ , d_ptr(new Q3DSDataInputPrivate(this))
+{
+ d_ptr->m_name = name;
+}
+
+/*!
+ Constructs a Q3DSDataInput instance and initializes the \a name. The
+ constructed instance is automatically associated with the specified \a
+ presentation. An optional \a parent object can be specified.
+ */
+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);
+}
+
+/*!
+ \internal
+ */
+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);
+}
+
+/*!
+ Destructor.
+ */
+Q3DSDataInput::~Q3DSDataInput()
+{
+ delete d_ptr;
+}
+
+/*!
+ \qmlproperty string DataInput::name
+
+ Specifies the name of the controlled data input element in the
+ presentation. The name must match a name of a data input defined
+ in the presentation. This property must be set before setting the
+ value property.
+ */
+
+/*!
+ \property Q3DSDataInput::name
+
+ Specifies the name of the controlled data input element in the
+ presentation. The name must match a name of a data input defined
+ in the presentation.
+
+ This property must be set before setting the value property.
+ The initial value is provided via the constructor, but the name
+ can also be changed later on.
+ */
+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();
+ }
+}
+
+/*!
+ \qmlproperty variant DataInput::value
+
+ Specifies the value of the controlled data input element in the
+ presentation.
+
+ The value of this property only accounts for changes done via the same
+ Q3DSDataInput instance. If the value of the same data input in the
+ presentation is changed elsewhere, for example via animations or
+ Q3DSPresentation::setAttribute(), those changes are not reflected in the
+ value of this property. Due to this uncertainty, this property treats all
+ value sets as changes even if the newly set value is the same value as the
+ previous value.
+
+ To get actual values from the presentation, use DataOutput.
+ \sa DataOutput
+*/
+/*!
+ \property Q3DSDataInput::value
+
+ Specifies the value of the controlled data input element in the
+ presentation.
+
+ The value of this property only accounts for changes done via the same
+ Q3DSDataInput instance. If the value of the same data input in the
+ presentation is changed elsewhere, for example via animations or
+ Q3DSPresentation::setAttribute(), those changes are not reflected in the
+ value of this property. Due to this uncertainty, this property treats all
+ value sets as changes even if the newly set value is the same value as the
+ previous value.
+
+ To get actual values from the presentation, use DataOutput.
+ \sa DataOutput
+*/
+QVariant Q3DSDataInput::value() const
+{
+ return d_ptr->m_value;
+}
+
+/*!
+ \property Q3DSDataInput::min
+
+ Contains the minimum range value for datainput. Returned value is zero
+ for datainput types other than \e {Ranged Number}.
+
+ \note This value is read-only.
+ */
+float Q3DSDataInput::min() const
+{
+ if (!d_ptr->m_presentation)
+ return 0.0f;
+
+ return d_ptr->m_presentation->d_ptr->dataInputMin(d_ptr->m_name);
+}
+
+/*!
+ \property Q3DSDataInput::max
+
+ Contains the maximum range value for datainput. Returned value is zero
+ for datainput types other than \e {Ranged Number}.
+
+ \note This value is read-only.
+ */
+float Q3DSDataInput::max() const
+{
+ if (!d_ptr->m_presentation)
+ return 0.0f;
+
+ return d_ptr->m_presentation->d_ptr->dataInputMax(d_ptr->m_name);
+}
+
+/*!
+ Returns true if presentation (or its subpresentation) associated with
+ this datainput has a datainput definition with a matching name. Returns
+ false if the datainput has no associated presentation, or if a match is not found.
+ */
+bool Q3DSDataInput::isValid() const
+{
+ if (d_ptr->m_presentation)
+ return d_ptr->m_presentation->d_ptr->isValidDataInput(this);
+ else
+ return false;
+}
+
+/*!
+ \brief Q3DSDataInput::setValue Set value of the data input.
+ \param value New value to be set.
+ \note For performance reasons do not call setValue unnecessarily.
+ */
+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.
+ // In order to track an element property, see DataOutput API.
+ 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);
+}
+
+
+/*!
+ \qmltype DataInput
+ \instantiates Q3DSDataInput
+ \inqmlmodule QtStudio3D
+ \ingroup OpenGLRuntime
+
+ \brief Controls a data input entry in a Qt 3D Studio presentation.
+
+ This type is a convenience for controlling a data in a presentation. Its functionality is
+ equivalent to \c{Presentation::setDataInputValue()}, however it has a big advantage
+ of being able to use QML property bindings, thus avoiding the need to having to resort
+ to a JavaScript function call for every value change.
+
+ As an example:
+
+ \qml
+ Studio3D {
+ ...
+ Presentation {
+ id: presentation
+ ...
+ property string text: ""
+ DataInput {
+ name: "inputForSomeTextNode"
+ value: presentation.text
+ }
+ }
+ }
+
+ Button {
+ onClicked: presentation.text = "Hello World"
+ }
+ \endqml
+
+ The example assumes that a data input connection was made in Qt 3D Studio
+ presentation using Qt 3D Studio editor between the \c textstring property of
+ target property and a data input name \c inputForSomeTextNode. As the value
+ is now set via a property, the full set of QML property bindings techniques
+ are available.
+
+ \sa Studio3D, Presentation
+*/
+
+/*!
+ \qmlproperty string DataInput::name
+
+ Specifies the name of the controlled data input element in the
+ presentation. This property must be set as part of DataInput declaration,
+ although it is changeable afterwards, if desired.
+*/
+
+/*!
+ \qmlproperty variant DataInput::value
+
+ Specifies the value of the controlled data input element in the presentation.
+
+ The value of this property only accounts for changes done via the same
+ DataInput instance. If the value of the underlying attribute in the
+ presentation is changed elsewhere, for example via animations or
+ Presentation::setAttribute(), those changes are not reflected in the value
+ of this property. Due to this uncertainty, this property treats all value
+ sets as changes even if the newly set value is the same value as the
+ previous value.
+*/
+
+/*!
+ \qmlproperty real DataInput::min
+
+ Contains the minimum value of the controlled data input element range.
+
+ This property is applicable only to data input type \e {Ranged Number}. For other
+ types, value returned is zero.
+
+ \note This value is read-only.
+*/
+
+/*!
+ \qmlproperty real DataInput::max
+
+ Contains the maximum value of the controlled data input element range.
+
+ This property is applicable only to data input type \e {Ranged Number}. For other
+ types, value returned is zero.
+
+ \note This value is read-only.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/Runtime/ogl-runtime/src/api/studio3d/q3dsdatainput.h b/src/Runtime/ogl-runtime/src/api/studio3d/q3dsdatainput.h
new file mode 100644
index 00000000..4504e5d2
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3d/q3dsdatainput.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** 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)
+ Q_PROPERTY(float max READ max CONSTANT)
+ Q_PROPERTY(float min READ min CONSTANT)
+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);
+
+Q_SIGNALS:
+ void nameChanged();
+ void valueChanged();
+
+protected:
+ explicit Q3DSDataInput(Q3DSDataInputPrivate *d, Q3DSPresentation *presentation,
+ const QString &name, QObject *parent = nullptr);
+ Q3DSDataInputPrivate *d_ptr;
+
+private:
+ Q_DISABLE_COPY(Q3DSDataInput)
+ friend class Q3DSPresentationPrivate;
+ friend class Q3DSRenderer;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(Q3DSDataInput*)
+
+#endif // Q3DSDATAINPUT_H
diff --git a/src/Runtime/ogl-runtime/src/api/studio3d/q3dsdatainput_p.h b/src/Runtime/ogl-runtime/src/api/studio3d/q3dsdatainput_p.h
new file mode 100644
index 00000000..6107add9
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3d/q3dsdatainput_p.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** 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;
+ // Local cached values, used only when synchronous getter from runtime engine
+ // is not available (for QML -side that is behind command queue).
+ QVariant m_value;
+ float m_max = 0;
+ float m_min = 0;
+
+ friend class Q3DSPresentationPrivate;
+ friend class Q3DSRenderer;
+};
+
+QT_END_NAMESPACE
+
+#endif // Q3DSDATAINPUT_P_P_H
diff --git a/src/Runtime/ogl-runtime/src/api/studio3d/q3dsdataoutput.cpp b/src/Runtime/ogl-runtime/src/api/studio3d/q3dsdataoutput.cpp
new file mode 100644
index 00000000..3cb13a0e
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3d/q3dsdataoutput.cpp
@@ -0,0 +1,225 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "q3dsdataoutput_p.h"
+#include "q3dspresentation_p.h"
+#include "q3dscommandqueue_p.h"
+
+/*!
+ \qmltype DataOutput
+ \instantiates Q3DSDataOutput
+ \inqmlmodule Qt3DStudio
+ \ingroup OpenGLRuntime
+ \brief Provides notifications from data output entries in Qt 3D Studio presentation.
+ This class is a convenience class for listening for changes in the Qt 3D Studio
+ presentation attributes. DataOutput provides a clean contract between the presentation
+ design and the code. It hides the presentation details from the code while providing a
+ contractual access point to code to be notified when aspects of the presentation change
+ (e.g. movement of an element in the presentation due to timeline animation).
+
+ DataOutput can be attached to same attributes in the design as DataInput is, including
+ presentation timeline. Only exception is slide changes. Slide changes are already notified
+ through \c{Presentation::slideEntered} and \c{Presentation::slideExited} signals.
+
+ \note There is a performance cost for each registered DataOutput, so try to avoid
+ creating unnecessary DataOutputs.
+
+ \sa Presentation, DataInput, Presentation::slideExited, Presentation::slideEntered
+ \sa Presentation::customSignalEmitted
+*/
+
+/*!
+ \class Q3DSDataOutput
+ \inmodule OpenGLRuntime
+ \since Qt 3D Studio 2.4
+ \brief Provides notifications from data output entries in Qt 3D Studio presentation.
+ This class is a convenience class for listening for changes in the Qt 3D Studio
+ presentation attributes. DataOutput provides a clean contract between the presentation
+ design and the code. It hides the presentation details from the code while providing a
+ contractual access point to code to be notified when aspects of the presentation change
+ (e.g. movement of an element in the presentation due to timeline animation).
+
+ DataOutput can be attached to same attributes in the design as DataInput is, including
+ presentation timeline. Only excaption is slide changes Slide changes are already notified
+ through \c{Q3DSPresentation::slideEntered} and \c{Q3DSPresentation::slideExited} signals.
+
+ \note There is a performance cost for each registered DataOutput, so try to avoid
+ creating unnecessary DataOutputs.
+
+ For other integration points between code and presentation see:
+ \sa Q3DSPresentation::customSignalEmitted
+ \sa Q3DSPresentation::slideEntered
+ \sa Q3DSPresentation::slideExited
+ \sa Q3DSDataInput
+
+ \sa Q3DSPresentation
+*/
+Q3DSDataOutput::Q3DSDataOutput(QObject *parent)
+ : QObject(parent)
+ , d_ptr(new Q3DSDataOutputPrivate(this))
+{
+
+}
+
+Q3DSDataOutput::Q3DSDataOutput(const QString &name, QObject *parent)
+ : QObject(parent)
+ , d_ptr(new Q3DSDataOutputPrivate(this))
+{
+ d_ptr->m_name = name;
+}
+
+Q3DSDataOutput::~Q3DSDataOutput()
+{
+ delete d_ptr;
+}
+
+/*!
+ \qmlproperty string DataOutput::name
+
+ Specifies the name of the observed data output element in the
+ presentation. The name must match a name of a data output defined
+ in the presentation. This property must be set before setting the value
+ property.
+ */
+
+/*!
+ \property Q3DSDataOutput::name
+
+ Specifies the name of the observed data output element in the
+ presentation. The name must match a name of a data output defined
+ in the presentation.
+
+ This property must be set before setting the value property.
+ The initial value is provided via the constructor, but the name
+ can also be changed later on.
+ */
+QString Q3DSDataOutput::name() const
+{
+ return d_ptr->m_name;
+}
+
+void Q3DSDataOutput::setName(const QString &name)
+{
+ if (d_ptr->m_name != name) {
+ d_ptr->m_name = name;
+ if (d_ptr->m_presentation)
+ d_ptr->m_presentation->registerDataOutput(this);
+ Q_EMIT nameChanged(name);
+ }
+}
+
+/*!
+ \qmlproperty DataOutput::value
+
+ Contains the read-only value of the controlled data output element in the
+ presentation.
+
+ The value of this property accounts for actual value in the last processed
+ frame of the presentation. This includes animation timeline driven changes,
+ changes done via DataInput and changes done via Behavior scripts.
+*/
+
+/*!
+ \property Q3DSDataOutput::value
+
+ Contains the read-only value of the controlled data output element in the
+ presentation.
+
+ The value of this property accounts for actual value in the last processed
+ frame of the presentation. This includes animation timeline driven changes,
+ changes done via DataInput and changes done via Behavior scripts.
+*/
+QVariant Q3DSDataOutput::value() const
+{
+ return d_ptr->m_value;
+}
+
+/*!
+ * \qmlsignal DataOutput::valueChanged
+ Emitted when the value of the observed DataOutput has changed in the
+ presentation.
+ \param newValue The new value of the observed DataOutput.
+ */
+
+/*!
+ \fn Q3DSDataOutput::valueChanged
+ Emitted when the value of the observed DataOutput has changed in the
+ presentation.
+ \param newValue The new value of the observed DataOutput.
+ */
+
+/*!
+ * \internal
+ */
+void Q3DSDataOutput::setValue(const QVariant &value)
+{
+ if (d_ptr->m_value == value)
+ return;
+
+ d_ptr->m_value = value;
+ Q_EMIT valueChanged(value);
+}
+
+void Q3DSDataOutputPrivate::setPresentation(Q3DSPresentation *presentation)
+{
+ m_presentation = presentation;
+}
+
+Q3DSDataOutputPrivate::Q3DSDataOutputPrivate(Q3DSDataOutput *parent)
+ : q_ptr(parent)
+{
+}
+
+Q3DSDataOutputPrivate::~Q3DSDataOutputPrivate()
+{
+ if (m_presentation)
+ m_presentation->unregisterDataOutput(q_ptr);
+}
+
+void Q3DSDataOutputPrivate::setValue(const QVariant &value)
+{
+ m_value = value;
+ Q_EMIT q_ptr->valueChanged(value);
+}
+
+void Q3DSDataOutputPrivate::setViewerApp(Q3DSViewer::Q3DSViewerApp *app)
+{
+ m_viewerApp = app;
+
+ if (m_viewerApp && m_value.isValid())
+ setValue(m_value);
+}
+
+void Q3DSDataOutputPrivate::setCommandQueue(CommandQueue *queue)
+{
+ m_commandQueue = queue;
+
+ if (m_commandQueue && m_value.isValid())
+ setValue(m_value);
+}
diff --git a/src/Runtime/ogl-runtime/src/api/studio3d/q3dsdataoutput.h b/src/Runtime/ogl-runtime/src/api/studio3d/q3dsdataoutput.h
new file mode 100644
index 00000000..93f74267
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3d/q3dsdataoutput.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 Q3DSDATAOUTPUT_H
+#define Q3DSDATAOUTPUT_H
+
+#include <QtStudio3D/qstudio3dglobal.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q3DSDataOutputPrivate;
+class Q3DSPresentation;
+
+class Q_STUDIO3D_EXPORT Q3DSDataOutput : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(Q3DSDataOutput)
+
+ Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
+ Q_PROPERTY(QVariant value READ value NOTIFY valueChanged)
+
+public:
+
+ explicit Q3DSDataOutput(QObject *parent = nullptr);
+ explicit Q3DSDataOutput(const QString &name, QObject *parent = nullptr);
+ explicit Q3DSDataOutput(Q3DSPresentation *presentation, const QString &name,
+ QObject *parent = nullptr);
+ virtual ~Q3DSDataOutput();
+
+ QString name() const;
+ QVariant value() const;
+
+public Q_SLOTS:
+ void setName(const QString &name);
+
+Q_SIGNALS:
+ void nameChanged(const QString &newName);
+ void valueChanged(const QVariant &newValue);
+
+protected:
+ explicit Q3DSDataOutput(Q3DSDataOutputPrivate *d, Q3DSPresentation *presentation,
+ const QString &name, QObject *parent = nullptr);
+ Q3DSDataOutputPrivate *d_ptr;
+
+private:
+ Q_DISABLE_COPY(Q3DSDataOutput)
+ void setValue(const QVariant &newValue);
+ friend class Q3DSPresentationPrivate;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(Q3DSDataOutput*)
+
+#endif // Q3DSDATAOUTPUT_H
diff --git a/src/Runtime/ogl-runtime/src/api/studio3d/q3dsdataoutput_p.h b/src/Runtime/ogl-runtime/src/api/studio3d/q3dsdataoutput_p.h
new file mode 100644
index 00000000..c4745bfb
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3d/q3dsdataoutput_p.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 Q3DSDATAOUTPUT_P_H
+#define Q3DSDATAOUTPUT_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 "q3dsdataoutput.h"
+#include "q3dscommandqueue_p.h"
+#include "Qt3DSViewerApp.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q3DSPresentationPrivate;
+
+class Q_STUDIO3D_EXPORT Q3DSDataOutputPrivate
+{
+ Q_DECLARE_PUBLIC(Q3DSDataOutput)
+public:
+ explicit Q3DSDataOutputPrivate(Q3DSDataOutput *parent);
+ virtual ~Q3DSDataOutputPrivate();
+
+ void setValue(const QVariant &value);
+ void setViewerApp(Q3DSViewer::Q3DSViewerApp *app);
+ void setCommandQueue(CommandQueue *queue);
+ void setPresentation(Q3DSPresentation *presentation);
+
+protected:
+ Q3DSDataOutput *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 // Q3DSDATAOUTPUT_P_H
diff --git a/src/Runtime/ogl-runtime/src/api/studio3d/q3dselement.cpp b/src/Runtime/ogl-runtime/src/api/studio3d/q3dselement.cpp
new file mode 100644
index 00000000..16ae1102
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3d/q3dselement.cpp
@@ -0,0 +1,284 @@
+/****************************************************************************
+**
+** 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
+
+/*!
+ \qmltype Element
+ \instantiates Q3DSElement
+ \inqmlmodule Qt3DStudio
+ \ingroup OpenGLRuntime
+ \brief Control type for elements in a Qt 3D Studio presentation.
+
+ This class is provided for backwards compatibility. We recommend using
+ DataInput and DataOutput APIs for contractual and clean API between
+ the design and the code.
+
+ \sa DataInput, DataOutput
+
+ This type is a convenience for controlling the properties of a scene object
+ (such as, model, material, camera, layer) in a Qt 3D Studio presentation.
+
+ \note The functionality of Element is equivalent to
+ Presentation::setAttribute() and Presentation::fireEvent().
+
+ \sa Studio3D, SceneElement, Presentation, DataInput, DataOutput
+*/
+
+/*!
+ \class Q3DSElement
+ \inmodule OpenGLRuntime
+ \since Qt 3D Studio 2.0
+
+ \brief Controls a scene object (node) in a Qt 3D Studio presentation.
+
+ This class is provided for backwards compatibility. We recommend using
+ DataInput and DataOutput APIs for contractual and clean API between
+ the design and the code.
+
+ This class is a convenience class for controlling the properties of a scene
+ object (such as, model, material, camera, layer) in a Qt 3D Studio
+ presentation.
+
+ \sa Q3DSWidget, Q3DSSurfaceViewer, Q3DSSceneElement
+ */
+
+/*!
+ \internal
+ */
+Q3DSElement::Q3DSElement(QObject *parent)
+ : QObject(parent)
+ , d_ptr(new Q3DSElementPrivate(this))
+{
+}
+
+/*!
+ \internal
+ */
+Q3DSElement::Q3DSElement(const QString &elementPath, QObject *parent)
+ : QObject(parent)
+ , d_ptr(new Q3DSElementPrivate(this))
+{
+ d_ptr->m_elementPath = elementPath;
+}
+
+/*!
+ Constructs a Q3DSElement instance controlling the scene object specified by
+ \a elementPath. An optional \a parent object can be specified. The
+ constructed instance is automatically associated with the specified \a
+ presentation. An optional \a parent object can be specified.
+ */
+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);
+}
+
+/*!
+ \internal
+ */
+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);
+}
+
+/*!
+ Destructor.
+ */
+Q3DSElement::~Q3DSElement()
+{
+ // Private class isn't QObject, so we need to delete it explicitly
+ delete d_ptr;
+}
+
+/*!
+ \qmlproperty string Element::elementPath
+
+ Holds the element path of the presentation element.
+
+ An element path refers to an object in the scene by name, for example,
+ \c{Scene.Layer.Camera}. Here the right camera object gets chosen even if
+ the scene contains other layers with the default camera names (for instance
+ \c{Scene.Layer2.Camera}).
+
+ To reference an object stored in a property of another object, the dot
+ syntax can be used. The most typical example of this is changing the source
+ of a texture map by changing the \c sourcepath property on the object
+ selected by \c{SomeMaterial.diffusemap}.
+
+ To access an object in a sub-presentation, prepend the name of the
+ sub-presentation followed by a colon, for example,
+ \c{SubPresentationOne:Scene.Layer.Camera}.
+ */
+
+/*!
+ \property Q3DSElement::elementPath
+
+ Holds the element path of the presentation element.
+
+ An element path refers to an object in the scene by name, for example,
+ \c{Scene.Layer.Camera}. Here the right camera object gets chosen even if
+ the scene contains other layers with the default camera names (for instance
+ \c{Scene.Layer2.Camera}).
+
+ To reference an object stored in a property of another object, the dot
+ syntax can be used. The most typical example of this is changing the source
+ of a texture map by changing the \c sourcepath property on the object
+ selected by \c{SomeMaterial.diffusemap}.
+
+ To access an object in a sub-presentation, prepend the name of the
+ sub-presentation followed by a colon, for example,
+ \c{SubPresentationOne:Scene.Layer.Camera}.
+ */
+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);
+ }
+}
+
+/*!
+ \qmlmethod void Element::setAttribute(string attributeName, variant value)
+
+ Sets the \a value of an attribute (property) of the scene object specified
+ by this Element instance. The \a attributeName is the \l{Attribute
+ Names}{scripting name} of the attribute.
+*/
+
+/*!
+ Sets the \a value of an attribute (property) of the scene object
+ specified by elementPath.
+
+ The \a attributeName is the \l{Attribute Names}{scripting name} of the attribute.
+ */
+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!";
+}
+
+/*!
+ \qmlmethod void Element::fireEvent(string eventName)
+
+ Dispatches an event with \a eventName on the scene object
+ specified by elementPath.
+
+ Appropriate actions created in Qt 3D Studio or callbacks registered using
+ the registerForEvent() method in attached \c{behavior scripts} will be
+ executed in response to the event.
+*/
+
+/*!
+ Dispatches an event with \a eventName on the scene object
+ specified by elementPath.
+
+ Appropriate actions created in Qt 3D Studio or callbacks registered using
+ the registerForEvent() method in attached (behavior) scripts will be
+ executed in response to the event.
+ */
+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/ogl-runtime/src/api/studio3d/q3dselement.h b/src/Runtime/ogl-runtime/src/api/studio3d/q3dselement.h
new file mode 100644
index 00000000..04c43f52
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/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/ogl-runtime/src/api/studio3d/q3dselement_p.h b/src/Runtime/ogl-runtime/src/api/studio3d/q3dselement_p.h
new file mode 100644
index 00000000..d4e77b1c
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/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/ogl-runtime/src/api/studio3d/q3dsgeometry.cpp b/src/Runtime/ogl-runtime/src/api/studio3d/q3dsgeometry.cpp
new file mode 100644
index 00000000..bfc66a96
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3d/q3dsgeometry.cpp
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "q3dsgeometry_p.h"
+
+QT_BEGIN_NAMESPACE
+
+Q3DSGeometry::Q3DSGeometry()
+ : d_ptr(new Q3DSGeometryPrivate(this))
+{
+}
+
+Q3DSGeometry::~Q3DSGeometry()
+{
+ delete d_ptr;
+}
+
+void Q3DSGeometry::setVertexData(const QByteArray &data)
+{
+ d_ptr->m_meshData.m_vertexBuffer = data;
+}
+
+void Q3DSGeometry::setIndexData(const QByteArray &data)
+{
+ d_ptr->m_meshData.m_indexBuffer = data;
+}
+
+const QByteArray &Q3DSGeometry::vertexBuffer() const
+{
+ return d_ptr->m_meshData.m_vertexBuffer;
+}
+
+QByteArray &Q3DSGeometry::vertexBuffer()
+{
+ return d_ptr->m_meshData.m_vertexBuffer;
+}
+
+const QByteArray &Q3DSGeometry::indexBuffer() const
+{
+ return d_ptr->m_meshData.m_indexBuffer;
+}
+
+QByteArray &Q3DSGeometry::indexBuffer()
+{
+ return d_ptr->m_meshData.m_indexBuffer;
+}
+
+int Q3DSGeometry::attributeCount() const
+{
+ return d_ptr->m_meshData.m_attributeCount;
+}
+
+void Q3DSGeometry::addAttribute(Q3DSGeometry::Attribute::Semantic semantic,
+ Q3DSGeometry::Attribute::ComponentType componentType)
+{
+ Q_ASSERT(d_ptr->m_meshData.m_attributeCount < Q3DSViewer::MeshData::MAX_ATTRIBUTES);
+
+ Q3DSViewer::MeshData::Attribute &att
+ = d_ptr->m_meshData.m_attributes[d_ptr->m_meshData.m_attributeCount];
+
+ Q3DSGeometry::Attribute::ComponentType theCompType = componentType;
+ if (theCompType == Attribute::DefaultType) {
+ theCompType = semantic == Attribute::IndexSemantic ? Attribute::U32Type
+ : Attribute::F32Type;
+ }
+ att.semantic = static_cast<Q3DSViewer::MeshData::Attribute::Semantic>(semantic);
+ att.componentType = static_cast<Q3DSViewer::MeshData::Attribute::ComponentType>(theCompType);
+ if (semantic != Q3DSGeometry::Attribute::IndexSemantic)
+ att.offset = d_ptr->getNextAttributeOffset();
+
+ d_ptr->m_meshData.m_attributeCount++;
+ d_ptr->m_meshData.m_stride = d_ptr->getNextAttributeOffset();
+}
+
+void Q3DSGeometry::addAttribute(const Q3DSGeometry::Attribute &att)
+{
+ addAttribute(att.semantic, att.componentType);
+}
+
+Q3DSGeometry::Attribute Q3DSGeometry::attribute(int idx) const
+{
+ Attribute att;
+ att.semantic = static_cast<Q3DSGeometry::Attribute::Semantic>(
+ d_ptr->m_meshData.m_attributes[idx].semantic);
+ att.componentType = static_cast<Q3DSGeometry::Attribute::ComponentType>(
+ d_ptr->m_meshData.m_attributes[idx].componentType);
+ return att;
+}
+
+Q3DSGeometry::PrimitiveType Q3DSGeometry::primitiveType() const
+{
+ return static_cast<Q3DSGeometry::PrimitiveType>(d_ptr->m_meshData.m_primitiveType);
+}
+
+void Q3DSGeometry::setPrimitiveType(Q3DSGeometry::PrimitiveType type)
+{
+ d_ptr->m_meshData.m_primitiveType = static_cast<Q3DSViewer::MeshData::PrimitiveType>(type);
+}
+
+void Q3DSGeometry::clear()
+{
+ d_ptr->m_meshData.clear();
+}
+
+Q3DSGeometryPrivate::Q3DSGeometryPrivate(Q3DSGeometry *parent)
+ : q_ptr(parent)
+{
+}
+
+Q3DSGeometryPrivate::~Q3DSGeometryPrivate()
+{
+}
+
+int Q3DSGeometryPrivate::getNextAttributeOffset() const
+{
+ int retval = 0;
+ for (int i = 0; i < m_meshData.m_attributeCount; ++i) {
+ if (m_meshData.m_attributes[i].semantic != Q3DSViewer::MeshData::Attribute::IndexSemantic) {
+ retval += m_meshData.m_attributes[i].typeSize()
+ * m_meshData.m_attributes[i].componentCount();
+ }
+ }
+ return retval;
+}
+
+QT_END_NAMESPACE
diff --git a/src/Runtime/ogl-runtime/src/api/studio3d/q3dsgeometry.h b/src/Runtime/ogl-runtime/src/api/studio3d/q3dsgeometry.h
new file mode 100644
index 00000000..b9b66e98
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3d/q3dsgeometry.h
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 Q3DSGEOMETRY_H
+#define Q3DSGEOMETRY_H
+
+#include <QtStudio3D/qstudio3dglobal.h>
+#include <QtCore/qbytearray.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q3DSGeometryPrivate;
+
+class Q_STUDIO3D_EXPORT Q3DSGeometry
+{
+public:
+ Q_DECLARE_PRIVATE(Q3DSGeometry)
+
+ // All enums must match the ones defined by MeshData::Attribute struct in Qt3DSViewerApp.h
+ enum PrimitiveType {
+ UnknownType = 0,
+ Points,
+ LineStrip,
+ LineLoop,
+ Lines,
+ TriangleStrip,
+ TriangleFan,
+ Triangles, // Default primitive type
+ Patches
+ };
+
+ struct Attribute {
+ enum Semantic {
+ UnknownSemantic = 0,
+ IndexSemantic,
+ PositionSemantic, // attr_pos
+ NormalSemantic, // attr_norm
+ TexCoordSemantic, // attr_uv0
+ TangentSemantic, // attr_textan
+ BinormalSemantic // attr_binormal
+ };
+ enum ComponentType {
+ DefaultType = 0,
+ U8Type,
+ I8Type,
+ U16Type,
+ I16Type,
+ U32Type, // Default for IndexSemantic
+ I32Type,
+ U64Type,
+ I64Type,
+ F16Type,
+ F32Type, // Default for other semantics
+ F64Type
+ };
+ Semantic semantic = PositionSemantic;
+ ComponentType componentType = DefaultType;
+ };
+
+ explicit Q3DSGeometry();
+ virtual ~Q3DSGeometry();
+
+ void setVertexData(const QByteArray &data);
+ void setIndexData(const QByteArray &data);
+
+ const QByteArray &vertexBuffer() const;
+ QByteArray &vertexBuffer();
+ const QByteArray &indexBuffer() const;
+ QByteArray &indexBuffer();
+
+ int attributeCount() const;
+ void addAttribute(Attribute::Semantic semantic,
+ Attribute::ComponentType componentType = Attribute::DefaultType);
+ void addAttribute(const Attribute &att);
+ Attribute attribute(int idx) const;
+
+ PrimitiveType primitiveType() const;
+ void setPrimitiveType(PrimitiveType type);
+
+ void clear();
+
+protected:
+ Q_DISABLE_COPY(Q3DSGeometry)
+ Q3DSGeometryPrivate *d_ptr;
+
+ friend class Q3DSPresentation;
+};
+
+QT_END_NAMESPACE
+
+#endif // Q3DSGEOMETRY_H
diff --git a/src/Runtime/ogl-runtime/src/api/studio3d/q3dsgeometry_p.h b/src/Runtime/ogl-runtime/src/api/studio3d/q3dsgeometry_p.h
new file mode 100644
index 00000000..586b0d7b
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3d/q3dsgeometry_p.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 Q3DSGEOMETRY_P_H
+#define Q3DSGEOMETRY_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 "q3dsgeometry.h"
+#include "Qt3DSViewerApp.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q_STUDIO3D_EXPORT Q3DSGeometryPrivate
+{
+ Q_DECLARE_PUBLIC(Q3DSGeometry)
+public:
+ explicit Q3DSGeometryPrivate(Q3DSGeometry *parent);
+ virtual ~Q3DSGeometryPrivate();
+
+ Q3DSViewer::MeshData &meshData() { return m_meshData; }
+
+private:
+ int getNextAttributeOffset() const;
+
+ Q3DSGeometry *q_ptr;
+ Q3DSViewer::MeshData m_meshData;
+};
+
+QT_END_NAMESPACE
+
+#endif // Q3DSGEOMETRY_P_H
diff --git a/src/Runtime/ogl-runtime/src/api/studio3d/q3dsimagesequencegenerator.cpp b/src/Runtime/ogl-runtime/src/api/studio3d/q3dsimagesequencegenerator.cpp
new file mode 100644
index 00000000..d0b8251b
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/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/ogl-runtime/src/api/studio3d/q3dsimagesequencegenerator_p.h b/src/Runtime/ogl-runtime/src/api/studio3d/q3dsimagesequencegenerator_p.h
new file mode 100644
index 00000000..bc56fb1e
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/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/ogl-runtime/src/api/studio3d/q3dsimagesequencegeneratorthread.cpp b/src/Runtime/ogl-runtime/src/api/studio3d/q3dsimagesequencegeneratorthread.cpp
new file mode 100644
index 00000000..0968e3f1
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/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.create(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/ogl-runtime/src/api/studio3d/q3dsimagesequencegeneratorthread_p.h b/src/Runtime/ogl-runtime/src/api/studio3d/q3dsimagesequencegeneratorthread_p.h
new file mode 100644
index 00000000..45869a69
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/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/ogl-runtime/src/api/studio3d/q3dspresentation.cpp b/src/Runtime/ogl-runtime/src/api/studio3d/q3dspresentation.cpp
new file mode 100644
index 00000000..204b2035
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3d/q3dspresentation.cpp
@@ -0,0 +1,1770 @@
+/****************************************************************************
+**
+** 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 "q3dsdataoutput_p.h"
+#include "q3dsgeometry_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qsettings.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtGui/qevent.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class Q3DSPresentation
+ \inmodule OpenGLRuntime
+ \since Qt 3D Studio 2.0
+
+ \brief Represents a Qt 3D Studio presentation.
+
+ This class provides properties and methods for controlling a
+ presentation.
+
+ Qt 3D Studio supports multiple presentations in one project. There
+ is always a main presentation and zero or more
+ subpresentations. The subpresentations are composed into the
+ main presentations either as contents of Qt 3D Studio layers or as
+ texture maps.
+
+ In the filesystem each presentation corresponds to one \c{.uip}
+ presentation file. When present, the \c{.uia} project file ties
+ these together by specifying a name for each of the
+ (sub-)presentations and specifies which one is the main one.
+
+ The \c{.uia} project also defines \l{DataInput}s and
+ \l{DataOutput}s that are exported by the presentations.
+ \l{DataInput}s provide a way to provide input to the presentation
+ to e.g. control a timeline of a subpresentation from code.
+ \c{DataOutput}s provide a way to get notified when an attribute
+ is changed in the presentation by animation timeline,
+ by behavior scripts or by a \l{DataInput}.
+
+ From the API point of view Q3DSPresentation corresponds to the
+ main presentation. The source property can refer either to a
+ \c{.uia} or \c{.uip} file. When specifying a file with \c{.uip}
+ extension and a \c{.uia} is present with the same name, the
+ \c{.uia} is loaded automatically and thus sub-presentation
+ information is available regardless.
+
+ \note This class should not be instantiated directly when working with the
+ C++ APIs. Q3DSSurfaceViewer and Q3DSWidget create a Q3DSPresentation
+ instance implicitly. This can be queried via
+ Q3DSSurfaceViewer::presentation() or Q3DSWidget::presentation().
+ */
+
+/*!
+ Constructs a new Q3DSPresentation with the given \a parent.
+ */
+Q3DSPresentation::Q3DSPresentation(QObject *parent)
+ : QObject(parent)
+ , d_ptr(new Q3DSPresentationPrivate(this))
+{
+}
+
+/*!
+ Destructor.
+ */
+Q3DSPresentation::~Q3DSPresentation()
+{
+}
+
+/*!
+ \qmlproperty string Presentation::source
+
+ Holds the name of the main presentation file (\c{*.uia} or
+ \c{*.uip}). This may be either a local file or qrc URL.
+
+ The names of all further assets (image files for texture maps, qml
+ behavior scripts, mesh files) will be resolved relative to the
+ location of the presentation, unless they use absolute paths. This
+ allows bundling all assets next to the presentation in the Qt
+ resource system.
+
+ Currently set \c{variantList} property will modify which variant groups
+ and tags are loaded from the presentations. See
+ Q3DSPresentation::variantList property.
+*/
+
+/*!
+ \property Q3DSPresentation::source
+
+ Holds the name of the main presentation file (\c{*.uia} or
+ \c{*.uip}). This may be either a local file or qrc URL.
+
+ The names of all further assets (image files for texture maps, qml
+ behavior scripts, mesh files) will be resolved relative to the
+ location of the presentation, unless they use absolute paths. This
+ allows bundling all assets next to the presentation in the Qt
+ resource system.
+
+ Currently set variantList will modify which variant groups
+ and tags are loaded from the presentations. See
+ Q3DSPresentation::variantList property.
+*/
+QUrl Q3DSPresentation::source() const
+{
+ return d_ptr->m_source;
+}
+
+void Q3DSPresentation::setSource(const QUrl &source)
+{
+ if (d_ptr->m_source != source) {
+ d_ptr->setSource(source);
+ Q_EMIT sourceChanged(source);
+ }
+}
+
+/*!
+ \qmlproperty variant Presentation::variantList
+
+ Holds a list of (variant group):(variant) tags that are loaded when the
+ \c{source} property is set. If this list is left empty (default), no variant
+ filtering is applied and all items are loaded regardless of variant tags in
+ the presentation. Variant mechanism allows one presentation project to
+ contain multiple variants of the presentation and the decision which variant
+ set is loaded is determined during runtime based on the \c{variantList}.
+
+ Variants are divided to variant groups, e.g. one variant group could be
+ \c{region} and the variants within that group could be e.g. \c{US, EU, CH}.
+ Another variant group could be e.g. \c{power} and variants within that could
+ be e.g. \c{gas, electric, diesel}. To filter in this example an electric
+ variant for the EU region, the variantList needs to contain two strings
+ "region:EU" and "power:electric". Also of course the presentation project
+ needs to contain these variant groups and tags applied appropriately to the
+ presentation content.
+
+ When variant filters are used, the decision what gets loaded and what is not
+ loaded is based on checking every item in the presentation:
+ \list
+ \li If the item has no variant tags, it will be loaded.
+ \li If the item has no tags defined for the checked variant group(s),
+ it will be loaded.
+ \li If the item has tag(s) for the variant group, any of those tags must
+ match any of the variants defined in the filter for that group.
+ \endlist
+
+ If the item doesn't fulfill the above rules it will not be loaded.
+*/
+
+/*!
+ \property Q3DSPresentation::variantList
+
+ Holds a list of (variant group):(variant) tags that are loaded when the
+ \c{source} property is set. If this list is left empty (default), no variant
+ filtering is applied and all items are loaded regardless of variant tags in
+ the presentation. Variant mechanism allows one presentation project to
+ contain multiple variants of the presentation and the decision which variant
+ set is loaded is determined during runtime based on the \c{variantList}.
+
+ Variants are divided to variant groups, e.g. one variant group could be
+ \c{region} and the variants within that group could be e.g. \c{US, EU, CH}.
+ Another variant group could be e.g. \c{power} and variants within that could
+ be e.g. \c{gas, electric, diesel}. To filter in this example an electric
+ variant for the EU region, the variantList needs to contain two strings
+ "region:EU" and "power:electric". Also of course the presentation project
+ needs to contain these variant groups and tags applied appropriately to the
+ presentation content.
+
+ When variant filters are used, the decision what gets loaded and what is not
+ loaded is based on checking every item in the presentation:
+ \list
+ \li If the item has no variant tags, it will be loaded.
+ \li If the item has no tags defined for the checked variant group(s),
+ it will be loaded.
+ \li If the item has tag(s) for the variant group, any of those tags must
+ match any of the variants defined in the filter for that group.
+ \endlist
+
+ If the item doesn't fulfill the above rules it will not be loaded.
+*/
+QStringList Q3DSPresentation::variantList() const
+{
+ return d_ptr->m_variantList;
+}
+
+void Q3DSPresentation::setVariantList(const QStringList &variantList)
+{
+ if (d_ptr->m_variantList != variantList) {
+ d_ptr->setVariantList(variantList);
+ Q_EMIT variantListChanged(variantList);
+ }
+}
+
+/*!
+ \internal
+ */
+void Q3DSPresentation::registerElement(Q3DSElement *element)
+{
+ d_ptr->registerElement(element);
+}
+
+/*!
+ \internal
+ */
+void Q3DSPresentation::unregisterElement(Q3DSElement *element)
+{
+ d_ptr->unregisterElement(element);
+}
+
+/*!
+ \internal
+ */
+Q3DSElement *Q3DSPresentation::registeredElement(const QString &elementPath) const
+{
+ return d_ptr->m_elements.value(elementPath, nullptr);
+}
+
+/*!
+ \internal
+ */
+void Q3DSPresentation::registerDataInput(Q3DSDataInput *dataInput)
+{
+ d_ptr->registerDataInput(dataInput);
+}
+
+/*!
+ \internal
+ */
+void Q3DSPresentation::unregisterDataInput(Q3DSDataInput *dataInput)
+{
+ d_ptr->unregisterDataInput(dataInput);
+}
+
+/*!
+ \internal
+ */
+Q3DSDataInput *Q3DSPresentation::registeredDataInput(const QString &name) const
+{
+ return d_ptr->m_dataInputs.value(name, nullptr);
+}
+
+/*!
+ \internal
+ */
+void Q3DSPresentation::registerDataOutput(Q3DSDataOutput *dataOutput)
+{
+ d_ptr->registerDataOutput(dataOutput);
+}
+
+/*!
+ \internal
+ */
+void Q3DSPresentation::unregisterDataOutput(Q3DSDataOutput *dataOutput)
+{
+ d_ptr->unregisterDataOutput(dataOutput);
+}
+
+/*!
+ \internal
+ */
+Q3DSDataOutput *Q3DSPresentation::registeredDataOutput(const QString &name) const
+{
+ return d_ptr->m_dataOutputs.value(name, nullptr);
+}
+
+/*!
+ Returns a list of datainputs defined for this presentation. Use setDataInputValue()
+ interface to set a datainput value using datainput name, or call Q3DSDataInput::setValue
+ directly for a specific datainput.
+
+ \sa setDataInputValue
+ \sa Q3DSDataInput
+ */
+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;
+}
+
+/*!
+ \qmlmethod variant Presentation::getDataInputs
+ Returns a list of datainputs defined for this presentation. Use setDataInputValue()
+ interface to set a datainput value using datainput name, or call Q3DSDataInput::setValue
+ directly for a specific datainput.
+
+ \sa DataInput
+ */
+
+/*!
+ Returns a list of datainputs defined for this presentation. Use setDataInputValue()
+ interface to set a datainput value using datainput name, or call Q3DSDataInput::setValue
+ directly for a specific datainput.
+
+ \sa setDataInputValue
+ \sa Q3DSDataInput
+ */
+QVariantList Q3DSPresentation::getDataInputs() const
+{
+ QVariantList ret;
+ const auto datainputs = dataInputs();
+
+ for (const auto &it : datainputs)
+ ret.append(QVariant::fromValue(it));
+
+ return ret;
+}
+
+/*!
+ Returns a list of dataoutputs defined for this presentation. Use Qt's connect() method
+ to connect slots to the valueChanged() signal in the required \l{DataOutput}s to get notified
+ when the value tracked by the DataOutput is changed.
+
+ \sa Q3DSDataOutput
+ */
+QVector<Q3DSDataOutput *> Q3DSPresentation::dataOutputs() const
+{
+ QVector<Q3DSDataOutput *> ret;
+ const auto datainputs = d_ptr->m_dataOutputs;
+ for (const auto &it : datainputs)
+ ret.append(it);
+
+ return ret;
+}
+
+/*!
+ \qmlmethod variant Presentation::getDataOutputs
+
+ Returns a list of dataoutputs defined for this presentation. Connect slots to the
+ \c{valueChanged()} signal in the required \l{DataOutput}s to get notified
+ when the value tracked by the DataOutput is changed.
+
+ \sa SDataOutput
+ */
+/*!
+ * \brief Q3DSPresentation::getDataOutputs Returns \l{DataOutput}s.
+ Returns a list of dataoutputs defined for this presentation. Use Qt's connect() method
+ to connect slots to the valueChanged() signal in the required \l{DataOutput}s to get notified
+ when the value tracked by the DataOutput is changed.
+
+ \sa Q3DSDataOutput
+ */
+QVariantList Q3DSPresentation::getDataOutputs() const
+{
+ QVariantList ret;
+ const auto dataoutputs = dataOutputs();
+
+ for (const auto &it : dataoutputs)
+ ret.append(QVariant::fromValue(it));
+
+ return ret;
+}
+
+/*!
+ \qmlproperty bool Presentation::delayedLoading
+
+ This property controls whether the presentation resources are loaded while loading
+ the presentation(false) or afterwards when they are actually used in the presentation(true).
+ The resources are loaded per slide basis so that all resources required by a slide will be
+ loaded at once.
+
+ The resources can be images, subpresentations, materials, effects and meshes.
+
+ Default is \c{false}.
+ */
+
+/*!
+ \property Q3DSPresentation::delayedLoading
+
+ This property controls whether the presentation resources are loaded while loading
+ the presentation(false) or afterwards when they are actually used in the presentation(true).
+ The resources are loaded per slide basis so that all resources required by a slide will be
+ loaded at once.
+
+ The resources can be images, subpresentations, materials, effects and meshes.
+
+ Default is \c{false}.
+ */
+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);
+ }
+}
+
+/*!
+ \qmlmethod Presentation::preloadSlide
+ Preloads slide resources to memory. All resources required by the given slide will be
+ loaded in the background. This function has effect only when delayed loading is enabled.
+ \param elementPath
+ */
+/*!
+ \brief Q3DSPresentation::preloadSlide
+ Preloads slide resources to memory. All resources required by the given slide will be
+ loaded in the background. This function has effect only when delayed loading is enabled.
+ \param elementPath
+ */
+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);
+}
+
+/*!
+ \qmlmethod Presentation::unloadSlide
+ Unloads slide resources from memory. If the slide is current, then the resources are unloaded
+ when the slide is changed. This function has effect only when delayed loading is enabled.
+ \param elementPath
+ */
+
+/*!
+ \brief Q3DSPresentation::unloadSlide
+ Unloads slide resources from memory. If the slide is current, then the resources are unloaded
+ when the slide is changed. This function has effect only when delayed loading is enabled.
+ \param elementPath
+ */
+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);
+}
+
+/*!
+ This API is for backwards compatibility. We recommend using \l{DataInput}s to control
+ slide changes. \l{DataInput} provides stronger contract between the design and
+ code as it avoids use of elementPath (a reference to design's internal structure).
+
+ Requests a time context (a Scene or a Component object) to change
+ to a specific slide by \a index. If the context is already on that
+ slide, playback will start over.
+
+ If \a elementPath points to a time context, that element is
+ controlled. For all other element types the time context owning
+ that element is controlled instead. You can target the command to
+ a specific sub-presentation by adding "SubPresentationId:" in
+ front of the element path, for example \c{"SubPresentationOne:Scene"}.
+ */
+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));
+ }
+}
+
+/*!
+ This API is for backwards compatibility. We recommend using \l{DataInput}s to control
+ slide changes. \l{DataInput} provides stronger contract between the design and
+ code as it avoids use of elementPath (a reference to design's internal structure).
+
+ Requests a time context (a Scene or a Component object) to change
+ to a specific slide by \a name. If the context is already on that
+ slide, playback will start over.
+
+ If \a elementPath points to a time context, that element is
+ controlled. For all other element types the time context owning
+ that element is controlled instead. You can target the command to
+ a specific sub-presentation by adding "SubPresentationId:" in
+ front of the element path, for example \c{"SubPresentationOne:Scene"}.
+ */
+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);
+ }
+}
+
+/*!
+ This API is for backwards compatibility. We recommend using \l{DataInput}s to control
+ slide changes. \l{DataInput} provides stronger contract between the design and
+ code as it avoids use of elementPath (a reference to design's internal structure).
+
+ Requests a time context (a Scene or a Component object) to change to the
+ next or previous slide, depending on the value of \a next. If the context
+ is already at the last or first slide, \a wrap defines if wrapping over to
+ the first or last slide, respectively, occurs.
+
+ If \a elementPath points to a time context, that element is controlled. For
+ all other element types the time context owning that element is controlled
+ instead. You can target the command to a specific sub-presentation by
+ adding "SubPresentationId:" in front of the element path, for example
+ \c{"SubPresentationOne:Scene"}.
+ */
+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));
+ }
+}
+
+/*!
+ This API is for backwards compatibility. We recommend using \l{DataInput}s to control
+ slide changes. \l{DataInput} provides stronger contract between the design and
+ code as it avoids use of elementPath (a reference to design's internal structure).
+
+ Moves the timeline for a time context (a Scene or a Component element) to a
+ specific position. The position is given in seconds in \a timeSeconds.
+
+ If \a elementPath points to a time context, that element is
+ controlled. For all other element types the time context owning
+ that element is controlled instead. You can target the command to
+ a specific sub-presentation by adding "SubPresentationId:" in
+ front of the element path, for example
+ \c{"SubPresentationOne:Scene"}.
+
+ The behavior when specifying a time before 0 or after the end time
+ for the current slide depends on the play mode of the slide:
+
+ \list
+ \li \c{Stop at End} - values outside the valid time range instead clamp to the boundaries.
+ For example, going to time -5 is the same as going to time 0.
+ \li \c{Looping} - values outside the valid time range mod into the valid range. For example,
+ going to time -4 on a 10 second slide is the same as going to time 6.
+ \li \c{Ping Pong} - values outside the valid time range bounce off the ends. For example,
+ going to time -4 is the same as going to time 4 (assuming the time context is at least 4 seconds
+ long), while going to time 12 on a 10 second slide is the same as going to time 8.
+ \li \c{Ping} - values less than 0 are treated as time 0, while values greater than the endtime
+ bounce off the end (eventually hitting 0.)
+ \endlist
+ */
+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);
+ }
+}
+
+/*!
+ This API is for backwards compatibility. We recommend using \l{DataInput}s to control
+ attributes in the presentation. \l{DataInput} provides stronger contract between the
+ design and code as it avoids use of elementPath (a reference to design's
+ internal structure).
+
+ Sets the \a value of an attribute (property) on the object specified by
+ \a elementPath. The \a attributeName is the \l{Attribute Names}{scripting
+ name} of the attribute.
+
+ An element path refers to an object in the scene by name, for example,
+ \c{Scene.Layer.Camera}. Here the right camera object gets chosen even if
+ the scene contains other layers with the default camera names (for instance
+ \c{Scene.Layer2.Camera}).
+
+ To reference an object stored in a property of another object, the dot
+ syntax can be used. The most typical example of this is changing the source
+ of a texture map by changing the \c sourcepath property on the object
+ selected by \c{SomeMaterial.diffusemap}.
+
+ To access an object in a sub-presentation, prepend the name of the
+ sub-presentation followed by a colon, for example,
+ \c{SubPresentationOne:Scene.Layer.Camera}.
+ */
+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);
+ }
+}
+
+// #TODO: QT3DS-3558
+/*!
+ \brief Q3DSPresentation::setPresentationActive
+ \param id
+ \param active
+ */
+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);
+ }
+}
+
+/*!
+ Dispatches a Qt 3D Studio presentation event with \a eventName on
+ scene object specified by \a elementPath. These events provide a
+ way to communicate with the \c .qml based \c{behavior scripts}
+ attached to scene objects since they can register to be notified
+ via Behavior::registerForEvent().
+
+ See setAttribute() for a description of \a elementPath.
+ */
+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);
+ }
+}
+
+// #TODO: QT3DS-3559
+/*!
+ \brief Q3DSPresentation::setGlobalAnimationTime
+ \param milliseconds
+ */
+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;
+ }
+}
+
+/*!
+ Sets the \a value of a data input element \a name in the presentation.
+
+ Data input provides a higher level, designer-driven alternative to
+ Q3DSElement and setAttribute(). Instead of exposing a large set of
+ properties with their internal engine names, data input allows designers to
+ decide which properties should be writable by the application, and can
+ assign custom names to these data input entries, thus forming a
+ well-defined contract between the designer and the developer.
+
+ In addition, data input also allows controlling the time line and the
+ current slide for time context objects (Scene or Component). Therefore it
+ is also an alternative to the goToSlide() and goToTime() family of APIs and
+ to Q3DSSceneElement.
+
+ \sa DataInput
+ */
+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));
+ }
+}
+
+/*!
+ * \brief Q3DSPresentation::createElement Adds a new child element for the specified element.
+ 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)
+{
+ QVector<QHash<QString, QVariant>> theProperties;
+ theProperties << properties;
+ createElements(parentElementPath, slideName, theProperties);
+}
+
+// #TODO: QT3DS-3560
+/*!
+ \brief Q3DSPresentation::createElements
+ \param parentElementPath
+ \param slideName
+ \param properties
+ */
+void Q3DSPresentation::createElements(const QString &parentElementPath, const QString &slideName,
+ const QVector<QHash<QString, QVariant>> &properties)
+{
+ if (d_ptr->m_viewerApp) {
+ d_ptr->m_viewerApp->createElements(parentElementPath, slideName, properties);
+ } else if (d_ptr->m_commandQueue) {
+ // We need to copy the properties map as queue takes ownership of it
+ QVector<QHash<QString, QVariant>> *theProperties
+ = new QVector<QHash<QString, QVariant>>(properties);
+ d_ptr->m_commandQueue->queueCommand(parentElementPath, CommandType_CreateElements,
+ slideName, theProperties);
+ }
+}
+
+/*!
+ \brief Q3DSPresentation::deleteElement
+ Removes an element added by createElement and all its child elements.
+ \param elementPath
+ */
+void Q3DSPresentation::deleteElement(const QString &elementPath)
+{
+ QStringList elementPaths;
+ elementPaths << elementPath;
+ deleteElements(elementPaths);
+}
+
+/*!
+ \brief Q3DSPresentation::deleteElements
+ Removes the given list of elements added by createElement and all their child elements.
+ \param elementPaths QStringList containing the elementPaths of dynamically created objects.
+ */
+void Q3DSPresentation::deleteElements(const QStringList &elementPaths)
+{
+ if (d_ptr->m_viewerApp) {
+ d_ptr->m_viewerApp->deleteElements(elementPaths);
+ } else if (d_ptr->m_commandQueue) {
+ // We need to copy the list as queue takes ownership of it
+ QStringList *theElementPaths = new QStringList(elementPaths);
+ d_ptr->m_commandQueue->queueCommand(CommandType_DeleteElements, theElementPaths);
+ }
+}
+
+/*!
+ \brief Q3DSPresentation::createMaterial
+ 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.
+ \param elementPath
+ \param materialDefinition
+ */
+void Q3DSPresentation::createMaterial(const QString &elementPath,
+ const QString &materialDefinition)
+{
+ QStringList materialDefinitions;
+ materialDefinitions << materialDefinition;
+ createMaterials(elementPath, materialDefinitions);
+}
+
+/*!
+ \brief Q3DSPresentation::createMaterials
+ Same as createMaterial, but creates multiple materials.
+ \param elementPath
+ \param materialDefinitions
+ */
+void Q3DSPresentation::createMaterials(const QString &elementPath,
+ const QStringList &materialDefinitions)
+{
+ if (d_ptr->m_viewerApp) {
+ d_ptr->m_viewerApp->createMaterials(elementPath, materialDefinitions);
+ } else if (d_ptr->m_commandQueue) {
+ // We need to copy the list as queue takes ownership of it
+ QStringList *theMaterialDefinitions = new QStringList(materialDefinitions);
+ d_ptr->m_commandQueue->queueCommand(elementPath, CommandType_CreateMaterials,
+ theMaterialDefinitions);
+ }
+}
+
+void Q3DSPresentation::deleteMaterial(const QString &elementPath, const QString &materialName)
+{
+ QStringList materialNames;
+ materialNames << materialName;
+ deleteMaterials(elementPath, materialNames);
+}
+
+void Q3DSPresentation::deleteMaterials(const QString &elementPath, const QStringList &materialNames)
+{
+ if (d_ptr->m_viewerApp) {
+ d_ptr->m_viewerApp->deleteMaterials(elementPath, materialNames);
+ } else if (d_ptr->m_commandQueue) {
+ // We need to copy the list as queue takes ownership of it
+ QStringList *theMaterialNames = new QStringList(materialNames);
+ d_ptr->m_commandQueue->queueCommand(elementPath, CommandType_DeleteMaterials,
+ theMaterialNames);
+ }
+}
+
+/**
+ Creates a mesh specified by given geometry. The given meshName can be used as sourcepath
+ property value for model elements created with future createElement calls.
+*/
+void Q3DSPresentation::createMesh(const QString &meshName, const Q3DSGeometry &geometry)
+{
+ QHash<QString, const Q3DSGeometry *> meshData;
+ meshData.insert(meshName, &geometry);
+ createMeshes(meshData);
+}
+
+// The ownership of supplied geometries stays with the caller
+void Q3DSPresentation::createMeshes(const QHash<QString, const Q3DSGeometry *> &meshData)
+{
+ // We can't refer to API class Q3DSGeometry on the runtime side, so let's grab the meshdata
+ // from Q3DSGeometryPrivate that is in runtime approved format and pass that on instead
+ auto theMeshData = new QHash<QString, Q3DSViewer::MeshData>;
+ QHashIterator<QString, const Q3DSGeometry *> it(meshData);
+ while (it.hasNext()) {
+ it.next();
+ theMeshData->insert(it.key(), it.value()->d_ptr->meshData());
+ }
+
+ if (d_ptr->m_viewerApp) {
+ d_ptr->m_viewerApp->createMeshes(*theMeshData);
+ delete theMeshData;
+ } else if (d_ptr->m_commandQueue) {
+ d_ptr->m_commandQueue->queueCommand(CommandType_CreateMeshes, theMeshData);
+ }
+}
+
+void Q3DSPresentation::deleteMesh(const QString &meshName)
+{
+ QStringList meshNames;
+ meshNames << meshName;
+ deleteMeshes(meshNames);
+}
+
+void Q3DSPresentation::deleteMeshes(const QStringList &meshNames)
+{
+ if (d_ptr->m_viewerApp) {
+ d_ptr->m_viewerApp->deleteMeshes(meshNames);
+ } else if (d_ptr->m_commandQueue) {
+ // We need to copy the list as queue takes ownership of it
+ QStringList *theMeshNames = new QStringList(meshNames);
+ d_ptr->m_commandQueue->queueCommand(CommandType_DeleteMeshes, theMeshNames);
+ }
+}
+
+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()));
+ }
+}
+
+/*!
+ * \internal
+ */
+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()));
+ }
+}
+
+/*!
+ * \internal
+ */
+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());
+ }
+}
+
+/*!
+ * \internal
+ */
+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);
+ }
+ }
+}
+
+/*!
+ * \internal
+ */
+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));
+ }
+}
+
+/*!
+ * \internal
+ */
+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));
+ }
+}
+
+// #TODO: QT3DS-3562 Most Presentation signals missing documentation
+/*!
+ * \qmlsignal Presentation::slideEntered
+ * Emitted when
+ * \param elementPath
+ * \param index
+ * \param name
+ */
+
+/*!
+ * \fn Q3DSPresentation::slideEntered
+ * Emitted when
+ * \param elementPath
+ * \param index
+ * \param name
+ */
+
+/*!
+ * \qmlsignal Presentation::slideExited
+ * Emitted when
+ * \param elementPath
+ * \param index
+ * \param name
+ */
+
+/*!
+ * \fn Q3DSPresentation::slideExited
+ * Emitted when
+ * \param elementPath
+ * \param index
+ * \param name
+ */
+
+/*!
+ * \fn Q3DSPresentation::dataInputsReady
+ * Emitted when \l{DataInput}s in the Studio project have been parsed and data inputs are available
+ * through dataInputs() and getDataInputs() methods.
+ */
+
+/*!
+ * \fn Q3DSPresentation::dataOutputsReady
+ * Emitted when \l{DataOutput}s in the Studio project have been parsed and data outputs are available
+ * through dataOutputs() and getDataOutputs() methods.
+ */
+
+/*!
+ * \qmlsignal Presentation::customSignalEmitted
+ * Emitted when
+ * \param elementPath
+ * \param name
+ */
+
+/*!
+ * \fn Q3DSPresentation::customSignalEmitted
+ * Emitted when
+ * \param elementPath
+ * \param name
+ */
+
+/*!
+ * \qmlsignal Presentation::elementsCreated
+ * Emitted when
+ * \param elementPaths
+ * \param error
+ */
+
+/*!
+ * \fn Q3DSPresentation::elementsCreated
+ * Emitted when
+ * \param elementPaths
+ * \param error
+ */
+
+/*!
+ * \qmlsignal Presentation::materialsCreated
+ * Emitted when
+ * \param materialNames
+ * \param error
+ */
+
+/*!
+ * \fn Q3DSPresentation::materialsCreated
+ * Emitted when
+ * \param materialNames
+ * \param error
+ */
+
+
+/*!
+ * \internal
+ */
+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();
+ unregisterAllDataOutputs();
+ 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)) {
+ // Name is sufficient for C++ side APIs, as other parameters
+ // (max/min) are queried synchronously.
+ 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::SigDataOutputValueUpdated,
+ this, &Q3DSPresentationPrivate::handleDataOutputValueUpdate);
+ connect(app, &Q3DSViewer::Q3DSViewerApp::SigElementsCreated,
+ q_ptr, &Q3DSPresentation::elementsCreated);
+ connect(app, &Q3DSViewer::Q3DSViewerApp::SigMaterialsCreated,
+ q_ptr, &Q3DSPresentation::materialsCreated);
+ connect(app, &Q3DSViewer::Q3DSViewerApp::SigMeshesCreated,
+ q_ptr, &Q3DSPresentation::meshesCreated);
+ }
+ 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::SigDataOutputValueUpdated,
+ this, &Q3DSPresentationPrivate::handleDataOutputValueUpdate);
+ disconnect(oldApp, &Q3DSViewer::Q3DSViewerApp::SigElementsCreated,
+ q_ptr, &Q3DSPresentation::elementsCreated);
+ disconnect(oldApp, &Q3DSViewer::Q3DSViewerApp::SigMaterialsCreated,
+ q_ptr, &Q3DSPresentation::materialsCreated);
+ disconnect(oldApp, &Q3DSViewer::Q3DSViewerApp::SigMeshesCreated,
+ q_ptr, &Q3DSPresentation::meshesCreated);
+ }
+ }
+}
+
+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 and outputs defined in UIA file so that
+ // getDataInputs has up-to-date info at the earliest and that data outputs
+ // connect from source to destination
+ m_commandQueue->queueCommand({}, CommandType_RequestDataInputs);
+ m_commandQueue->queueCommand({}, CommandType_RequestDataOutputs);
+ 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.
+ auto receivedDI = response->at(i).value<Q3DSDataInput *>();
+ // For QML behind async command queue, we cache min/max values in addition
+ // to name, in order to be able to return values initially set in UIA file (in QML
+ // getters).
+ if (!m_dataInputs.contains(receivedDI->name())) {
+ auto newDI = new Q3DSDataInput(receivedDI->name(), nullptr);
+ newDI->d_ptr->m_min = receivedDI->d_ptr->m_min;
+ newDI->d_ptr->m_max = receivedDI->d_ptr->m_max;
+ registerDataInput(newDI);
+ } else {
+ m_dataInputs[receivedDI->name()]->d_ptr->m_min = receivedDI->d_ptr->m_min;
+ m_dataInputs[receivedDI->name()]->d_ptr->m_max = receivedDI->d_ptr->m_max;
+ }
+ }
+ delete response;
+ Q_EMIT q_ptr->dataInputsReady();
+ break;
+ }
+ case CommandType_RequestDataOutputs: {
+ 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
+ // dataoutputs that are not explicitly defined in QML code.
+ if (!m_dataOutputs.contains(response->at(i).value<QString>()))
+ registerDataOutput(new Q3DSDataOutput(response->at(i).value<QString>(), nullptr));
+ }
+ delete response;
+ Q_EMIT q_ptr->dataOutputsReady();
+ 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
+{
+ // For QML instance separated from runtime engine by command queue,
+ // check locally cached list for this datainput (initialised at presentation load).
+ if (!m_viewerApp) {
+ if (m_dataInputs.contains(dataInput->name()))
+ return true;
+ else
+ return false;
+ }
+
+ return m_viewerApp->dataInputs().contains(dataInput->name());
+}
+
+float Q3DSPresentationPrivate::dataInputMin(const QString &name) const
+{
+ // For QML instance separated from runtime engine by command queue,
+ // return locally cached value (initialised at presentation load).
+ if (!m_viewerApp) {
+ if (m_dataInputs.contains(name))
+ return m_dataInputs[name]->d_ptr->m_min;
+ else
+ return 0.0f;
+ }
+ return m_viewerApp->dataInputMin(name);
+}
+
+float Q3DSPresentationPrivate::dataInputMax(const QString &name) const
+{
+ // For QML instance separated from runtime engine by command queue,
+ // return locally cached value (initialised at presentation load).
+ if (!m_viewerApp) {
+ if (m_dataInputs.contains(name))
+ return m_dataInputs[name]->d_ptr->m_max;
+ else
+ return 0.0f;
+ }
+ return m_viewerApp->dataInputMax(name);
+}
+
+void Q3DSPresentationPrivate::registerDataOutput(Q3DSDataOutput *dataOutput)
+{
+ Q_ASSERT(!dataOutput->name().isEmpty());
+
+ // Allow only single registration for each DataOutput
+ QMutableHashIterator<QString, Q3DSDataOutput *> i(m_dataOutputs);
+ while (i.hasNext()) {
+ i.next();
+ if (i.value() == dataOutput) {
+ // If the same DataOutput object is already registered with different name,
+ // remove it from the map to avoid duplication.
+ if (i.key() != dataOutput->name())
+ i.remove();
+ } else if (i.key() == dataOutput->name()) {
+ // If the same name is registered by another DataOutput object, the old
+ // DataOutput object is unregistered.
+ i.value()->d_ptr->setViewerApp(nullptr);
+ i.value()->d_ptr->setPresentation(nullptr);
+ i.value()->d_ptr->setCommandQueue(nullptr);
+ i.remove();
+ }
+ }
+
+ dataOutput->d_ptr->setPresentation(q_ptr);
+ dataOutput->d_ptr->setViewerApp(m_viewerApp);
+ dataOutput->d_ptr->setCommandQueue(m_commandQueue);
+
+ m_dataOutputs.insert(dataOutput->name(), dataOutput);
+}
+
+void Q3DSPresentationPrivate::unregisterDataOutput(Q3DSDataOutput *dataOutput)
+{
+ Q3DSDataOutput *oldDout = m_dataOutputs.value(dataOutput->name());
+ if (oldDout == dataOutput) {
+ dataOutput->d_ptr->setCommandQueue(nullptr);
+ dataOutput->d_ptr->setViewerApp(nullptr);
+ dataOutput->d_ptr->setPresentation(nullptr);
+ m_dataOutputs.remove(dataOutput->name());
+ }
+}
+
+void Q3DSPresentationPrivate::unregisterAllDataOutputs()
+{
+ const auto values = m_dataOutputs.values();
+ for (Q3DSDataOutput *dout : values) {
+ dout->d_ptr->setViewerApp(nullptr);
+ dout->d_ptr->setCommandQueue(nullptr);
+ dout->d_ptr->setPresentation(nullptr);
+ }
+ m_dataOutputs.clear();
+}
+
+bool Q3DSPresentationPrivate::isValidDataOutput(const Q3DSDataOutput *dataOutput) const
+{
+ if (!m_viewerApp)
+ return false;
+
+ return m_viewerApp->dataOutputs().contains(dataOutput->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);
+}
+
+void Q3DSPresentationPrivate::handleDataOutputValueUpdate(const QString &name,
+ const QVariant &newValue)
+{
+ if (!m_dataOutputs.contains(name))
+ return;
+
+ Q3DSDataOutput *node = m_dataOutputs[name];
+ node->setValue(newValue);
+}
+
+QT_END_NAMESPACE
diff --git a/src/Runtime/ogl-runtime/src/api/studio3d/q3dspresentation.h b/src/Runtime/ogl-runtime/src/api/studio3d/q3dspresentation.h
new file mode 100644
index 00000000..436e6844
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3d/q3dspresentation.h
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** 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 <QtStudio3D/q3dsdatainput.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qstringlist.h>
+#include <QtStudio3D/q3dsdatainput.h>
+#include <QtStudio3D/q3dsdataoutput.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q3DSPresentationPrivate;
+class Q3DSElement;
+class Q3DSGeometry;
+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;
+ void registerDataOutput(Q3DSDataOutput *dataOutput);
+ void unregisterDataOutput(Q3DSDataOutput *dataOutput);
+ Q3DSDataOutput *registeredDataOutput(const QString &name) const;
+
+ Q_INVOKABLE QVariantList getDataInputs() const;
+ QVector<Q3DSDataInput *> dataInputs() const;
+ Q_INVOKABLE QVariantList getDataOutputs() const;
+ QVector<Q3DSDataOutput *> dataOutputs() 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 createElements(const QString &parentElementPath, const QString &slideName,
+ const QVector<QHash<QString, QVariant>> &properties);
+ void deleteElement(const QString &elementPath);
+ void deleteElements(const QStringList &elementPaths);
+ void createMaterial(const QString &elementPath, const QString &materialDefinition);
+ void createMaterials(const QString &elementPath, const QStringList &materialDefinitions);
+ void deleteMaterial(const QString &elementPath, const QString &materialName);
+ void deleteMaterials(const QString &elementPath, const QStringList &materialNames);
+ void createMesh(const QString &meshName, const Q3DSGeometry &geometry);
+ void createMeshes(const QHash<QString, const Q3DSGeometry *> &meshData);
+ void deleteMesh(const QString &meshName);
+ void deleteMeshes(const QStringList &meshNames);
+
+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);
+ void dataInputsReady();
+ void dataOutputsReady();
+ void customSignalEmitted(const QString &elementPath, const QString &name);
+ void delayedLoadingChanged(bool enable);
+ void elementsCreated(const QStringList &elementPaths, const QString &error);
+ void materialsCreated(const QStringList &materialNames, const QString &error);
+ void meshesCreated(const QStringList &meshNames, const QString &error);
+
+private:
+ Q_DISABLE_COPY(Q3DSPresentation)
+ Q3DSPresentationPrivate *d_ptr;
+
+ friend class Q3DSPresentationItem;
+ friend class Q3DSSurfaceViewerPrivate;
+ friend class Q3DSRenderer;
+ friend class Q3DSStudio3D;
+ friend class Q3DSDataInput;
+};
+
+QT_END_NAMESPACE
+
+#endif // Q3DSPRESENTATION_H
diff --git a/src/Runtime/ogl-runtime/src/api/studio3d/q3dspresentation_p.h b/src/Runtime/ogl-runtime/src/api/studio3d/q3dspresentation_p.h
new file mode 100644
index 00000000..7b4877d9
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3d/q3dspresentation_p.h
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** 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;
+ typedef QHash<QString, Q3DSDataOutput *> DataOutputMap;
+
+ 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();
+ void registerDataOutput(Q3DSDataOutput *dataOutput);
+ void unregisterDataOutput(Q3DSDataOutput *dataOutput);
+ void unregisterAllDataOutputs();
+
+ bool isValidDataInput(const Q3DSDataInput *dataInput) const;
+ float dataInputMin(const QString &name) const;
+ float dataInputMax(const QString &name) const;
+ bool isValidDataOutput(const Q3DSDataOutput *dataOutput) 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);
+ void handleDataOutputValueUpdate(const QString &name, const QVariant &newValue);
+
+public:
+ Q3DSPresentation *q_ptr;
+
+private:
+ Q3DSViewer::Q3DSViewerApp *m_viewerApp; // Not owned
+ CommandQueue *m_commandQueue; // Not owned
+ ElementMap m_elements;
+ DataInputMap m_dataInputs;
+ DataOutputMap m_dataOutputs;
+ 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/ogl-runtime/src/api/studio3d/q3dssceneelement.cpp b/src/Runtime/ogl-runtime/src/api/studio3d/q3dssceneelement.cpp
new file mode 100644
index 00000000..3f860d65
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3d/q3dssceneelement.cpp
@@ -0,0 +1,436 @@
+/****************************************************************************
+**
+** 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
+
+/*!
+ \qmltype SceneElement
+ \instantiates Q3DSSceneElement
+ \inqmlmodule Qt3DStudio
+ \ingroup OpenGLRuntime
+ \brief Controls the special Scene or Component scene objects in a Qt 3D
+ Studio presentation.
+
+ This class is a convenience class for controlling the properties of Scene
+ and Component objects in the scene. These are special since they have a
+ time context, meaning they control a timeline and a set of associated
+ slides.
+
+ \sa Studio3D, Element, Presentation
+*/
+
+/*!
+ \class Q3DSSceneElement
+ \inherits Q3DSElement
+ \inmodule OpenGLRuntime
+ \since Qt 3D Studio 2.0
+
+ \brief Controls the special Scene or Component scene objects in a Qt 3D
+ Studio presentation.
+
+ This class is a convenience class for controlling the properties of Scene
+ and Component objects in the scene. These are special since they have a
+ time context, meaning they control a timline and a set of associated
+ slides.
+
+ \note The functionality of Q3DSSceneElement is equivalent to
+ Q3DSPresentation::goToTime() and Q3DSPresentation::goToSlide().
+
+ \sa Q3DSPresentation, Q3DSWidget, Q3DSSurfaceViewer, Q3DSElement
+ */
+
+/*!
+ \internal
+ */
+Q3DSSceneElement::Q3DSSceneElement(QObject *parent)
+ : Q3DSElement(new Q3DSSceneElementPrivate(this), nullptr, QString(), parent)
+{
+}
+
+/*!
+ \internal
+ */
+Q3DSSceneElement::Q3DSSceneElement(const QString &elementPath, QObject *parent)
+ : Q3DSElement(new Q3DSSceneElementPrivate(this), nullptr, elementPath, parent)
+{
+}
+
+/*!
+ Constructs a Q3DSSceneElement instance and associated it with the object
+ specified by \a elementPath and the given \a presentation. An optional \a
+ parent object can be specified.
+ */
+Q3DSSceneElement::Q3DSSceneElement(Q3DSPresentation *presentation, const QString &elementPath,
+ QObject *parent)
+ : Q3DSElement(new Q3DSSceneElementPrivate(this), presentation, elementPath, parent)
+{
+
+}
+
+/*!
+ Destructor.
+ */
+Q3DSSceneElement::~Q3DSSceneElement()
+{
+}
+
+/*!
+ \qmlproperty int SceneElement::currentSlideIndex
+
+ Holds the index of the currently active slide of the tracked time context.
+
+ \note If this property is set to something else than the default slide for
+ the scene at the initial declaration of SceneElement, a changed signal for
+ the default slide may still be emitted before the slide changes to the
+ desired one. This happens in order to ensure we end up with the index of
+ the slide that is actually shown even if the slide specified in the initial
+ declaration is invalid.
+*/
+
+/*!
+ \property Q3DSSceneElement::currentSlideIndex
+
+ Holds the index of the currently active slide of the tracked time context.
+
+ \note If this property is set to something else than the default slide for
+ the scene at the initial declaration of SceneElement, a changed signal for
+ the default slide may still be emitted before the slide changes to the
+ desired one. This happens in order to ensure we end up with the index of
+ the slide that is actually shown even if the slide specified in the initial
+ declaration is invalid.
+*/
+int Q3DSSceneElement::currentSlideIndex() const
+{
+ Q_D(const Q3DSSceneElement);
+ return d->m_currentSlideIndex;
+}
+
+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();
+ }
+}
+
+/*!
+ \property int SceneElement::previousSlideIndex
+
+ Holds the index of the previously active slide of the tracked time context.
+
+ Note: This property is read-only.
+*/
+/*!
+ \property Q3DSSceneElement::previousSlideIndex
+
+ Holds the index of the previously active slide of the tracked time context.
+
+ This property is read-only.
+*/
+int Q3DSSceneElement::previousSlideIndex() const
+{
+ Q_D(const Q3DSSceneElement);
+ return d->m_previousSlideIndex;
+}
+
+/*!
+ \qmlproperty string SceneElement::currentSlideName
+
+ Holds the name of the currently active slide of the tracked time context.
+
+ \note If this property is set to something else than the default slide for
+ the scene at the initial declaration of SceneElement, a changed signal for
+ the default slide may still be emitted before the slide changes to the
+ desired one. This happens in order to ensure we end up with the index of
+ the slide that is actually shown even if the slide specified in the initial
+ declaration is invalid.
+*/
+
+/*!
+ \property Q3DSSceneElement::currentSlideName
+
+ Holds the name of the currently active slide of the tracked time context.
+
+ \note If this property is set to something else than the default slide for
+ the scene at the initial declaration of SceneElement, a changed signal for
+ the default slide may still be emitted before the slide changes to the
+ desired one. This happens in order to ensure we end up with the index of
+ the slide that is actually shown even if the slide specified in the initial
+ declaration is invalid.
+*/
+QString Q3DSSceneElement::currentSlideName() const
+{
+ Q_D(const Q3DSSceneElement);
+ return d->m_currentSlideName;
+}
+
+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;
+ }
+}
+
+/*!
+ \qmlmproperty string SceneElement::previousSlideName
+
+ Holds the name of the previously active slide of the tracked time context.
+
+ Note: This property is read-only.
+*/
+/*!
+ \property Q3DSSceneElement::previousSlideName
+
+ Holds the name of the previously active slide of the tracked time context.
+
+ This property is read-only.
+*/
+QString Q3DSSceneElement::previousSlideName() const
+{
+ Q_D(const Q3DSSceneElement);
+ return d->m_previousSlideName;
+}
+
+/*!
+ Requests a time context (a Scene or a Component object) to change to the
+ next or previous slide, depending on the value of \a next. If the context
+ is already at the last or first slide, \a wrap defines if wrapping over to
+ the first or last slide, respectively, occurs.
+ */
+void Q3DSSceneElement::goToSlide(bool next, bool wrap)
+{
+ Q_D(Q3DSSceneElement);
+ d->goToSlide(next, wrap);
+}
+
+/*!
+ Moves the timeline for a time context (a Scene or a Component element) to a
+ specific position. The position is given in seconds in \a timeSeconds.
+ */
+void Q3DSSceneElement::goToTime(float time)
+{
+ Q_D(Q3DSSceneElement);
+ d->goToTime(time);
+}
+
+
+/*!
+ \internal
+ */
+Q3DSSceneElementPrivate::Q3DSSceneElementPrivate(Q3DSSceneElement *parent)
+ : Q3DSElementPrivate(parent)
+ , m_currentSlideIndex(0)
+ , m_previousSlideIndex(0)
+ , m_initialSlideIndex(0)
+ , m_slideInfoRequestPending(false)
+{
+}
+
+/*!
+ \internal
+ */
+Q3DSSceneElementPrivate::~Q3DSSceneElementPrivate()
+{
+}
+
+/*!
+ \internal
+ */
+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);
+ }
+}
+
+/*!
+ \internal
+ */
+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!";
+}
+
+/*!
+ \internal
+ */
+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!";
+}
+
+/*!
+ \internal
+ */
+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();
+ }
+}
+
+/*!
+ \internal
+ */
+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();
+ }
+}
+
+/*!
+ \internal
+ */
+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/ogl-runtime/src/api/studio3d/q3dssceneelement.h b/src/Runtime/ogl-runtime/src/api/studio3d/q3dssceneelement.h
new file mode 100644
index 00000000..2d96255c
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/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/ogl-runtime/src/api/studio3d/q3dssceneelement_p.h b/src/Runtime/ogl-runtime/src/api/studio3d/q3dssceneelement_p.h
new file mode 100644
index 00000000..02d2bdff
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/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/ogl-runtime/src/api/studio3d/q3dssurfaceviewer.cpp b/src/Runtime/ogl-runtime/src/api/studio3d/q3dssurfaceviewer.cpp
new file mode 100644
index 00000000..23782f2f
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3d/q3dssurfaceviewer.cpp
@@ -0,0 +1,688 @@
+/****************************************************************************
+**
+** 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
+
+/*!
+ \class Q3DSSurfaceViewer
+ \inmodule OpenGLRuntime
+ \since Qt 3D Studio 2.0
+
+ \brief Renders a Qt 3D Studio presentation on a QWindow or an offscreen
+ render target using OpenGL.
+
+ Q3DSSurfaceViewer is used to render Qt 3D Studio presentations onto a
+ QSurface. In practice this means two types of uses: rendering to an
+ on-screen QWindow, or rendering to an offscreen render target (typically an
+ OpenGL texture via a framebuffer object and a QOffscreenSurface).
+
+ \section2 Example Usage
+
+ \code
+ int main(int argc, char *argv[])
+ {
+ QGuiApplication app(argc, argv);
+
+ QOpenGLContext context;
+ context.create();
+
+ QWindow window;
+ window.setSurfaceType(QSurface::OpenGLSurface);
+ window.setFormat(context.format());
+ window.create();
+
+ Q3DSSurfaceViewer viewer;
+ viewer.presentation()->setSource(QUrl(QStringLiteral("qrc:/my_presentation.uip")));
+ viewer.setUpdateInterval(0); // enable automatic updates
+
+ // Register a scene object for slide management (optional)
+ Q3DSSceneElement scene(viewer.presentation(), QStringLiteral("Scene"));
+
+ // Register an element object for attribute setting (optional)
+ Q3DSElement element(viewer.presentation(), QStringLiteral("Scene.Layer.myCarModel"));
+
+ viewer.create(&window, &context);
+
+ w.resize(1024, 768);
+ w.show();
+
+ return app.exec();
+ }
+ \endcode
+
+ \sa Q3DSWidget
+ */
+
+/*!
+ * \brief Q3DSSurfaceViewer::Q3DSSurfaceViewer Constructor.
+ * \param parent Optional parent of the object.
+ */
+Q3DSSurfaceViewer::Q3DSSurfaceViewer(QObject *parent)
+ : QObject(parent)
+ , d_ptr(new Q3DSSurfaceViewerPrivate(this))
+{
+}
+
+/*!
+ * \brief Q3DSSurfaceViewer::~Q3DSSurfaceViewer Destructor
+ */
+Q3DSSurfaceViewer::~Q3DSSurfaceViewer()
+{
+ delete d_ptr;
+}
+
+/*!
+ Initializes Q3DSSurfaceViewer to render the presentation to the given
+ \a surface using the \a context.
+
+ The source property of the attached presentation must be set before the
+ viewer can be initialized.
+
+ Returns whether the initialization succeeded.
+
+ \sa running, Q3DSPresentation::source, presentation()
+*/
+bool Q3DSSurfaceViewer::create(QSurface *surface, QOpenGLContext *context)
+{
+ // #TODO: QT3DS-3531 Fix this to behave as in RT2
+ return create(surface, context, 0);
+}
+
+
+/*!
+ Initializes Q3DSSurfaceViewer to render the presentation to the given
+ \a surface using the \a context and optional framebuffer id (\a fboId). If
+ \a fboId is omitted, it defaults to zero.
+
+ The source property of the attached presentation must be set before the
+ viewer can be initialized.
+
+ Returns whether the initialization succeeded.
+
+ \sa running, Q3DSPresentation::source, presentation()
+*/
+bool Q3DSSurfaceViewer::create(QSurface *surface, QOpenGLContext *context, GLuint fboId)
+{
+ return d_ptr->initialize(surface, context, fboId);
+}
+
+/*!
+ Releases the presentation and all related resources.
+ The Q3DSSurfaceViewer instance can be reused by calling create() again.
+ */
+void Q3DSSurfaceViewer::destroy()
+{
+ d_ptr->destroy();
+}
+
+/*!
+ Updates the surface viewer with a new frame.
+*/
+void Q3DSSurfaceViewer::update()
+{
+ d_ptr->update();
+}
+
+/*!
+ Grabs the data rendered to the framebuffer into an image using the given \a
+ rect. The \a rect parameter is optional. If it is omitted, the whole
+ framebuffer is captured.
+
+ \note This is a potentially expensive operation.
+*/
+QImage Q3DSSurfaceViewer::grab(const QRect &rect)
+{
+ return d_ptr->grab(rect);
+}
+
+/*!
+ \property Q3DSSurfaceViewer::size
+
+ Holds the desired size of the presentation. Relevant only when
+ autoSize is set to \c false.
+
+ \sa autoSize
+*/
+QSize Q3DSSurfaceViewer::size() const
+{
+ return d_ptr->m_size;
+}
+
+void Q3DSSurfaceViewer::setSize(const QSize &size)
+{
+ d_ptr->setSize(size);
+}
+
+/*!
+ \property Q3DSSurfaceViewer::autoSize
+
+ Specifies whether the viewer should change the size of the presentation
+ automatically to match the surface size when surface size changes. The
+ \l{Q3DSSurfaceViewer::size}{size} property is updated automatically
+ whenever the viewer is \l{Q3DSSurfaceViewer::update()}{updated} if this
+ property value is \c{true}.
+
+ When rendering offscreen, via a QOffscreenSurface, this property must be
+ set to \c{false} by the application since it is then up to the application
+ to provide a QOpenGLFramebufferObject with the desired size. The size of
+ the Q3DSSurfaceViewer must be set to the same value.
+
+ The default value is \c{true}.
+*/
+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);
+ }
+}
+
+/*!
+ \property Q3DSSurfaceViewer::updateInterval
+
+ Holds the viewer update interval in milliseconds. If the value is negative,
+ the viewer doesn't update the presentation automatically.
+
+ The default value is -1, meaning there are no automatic updates and
+ update() must be called manually.
+
+ \sa update()
+*/
+int Q3DSSurfaceViewer::updateInterval() const
+{
+ return d_ptr->m_updateInterval;
+}
+
+void Q3DSSurfaceViewer::setUpdateInterval(int interval)
+{
+ d_ptr->setUpdateInterval(interval);
+}
+
+/*!
+ \property Q3DSSurfaceViewer::running
+
+ The value of this property is \c true when the presentation has been loaded
+ and is ready to be shown.
+
+ This property is read-only.
+*/
+bool Q3DSSurfaceViewer::isRunning() const
+{
+ return d_ptr->m_viewerApp != nullptr;
+}
+
+// #TODO QT3DS-3534
+
+/*!
+ \property Q3DSSurfaceViewer::presentationId
+ */
+QString Q3DSSurfaceViewer::presentationId() const
+{
+ return d_ptr->m_id;
+}
+
+/*!
+ Returns the framebuffer id given in initialization.
+
+ \sa create()
+*/
+int Q3DSSurfaceViewer::fboId() const
+{
+ return d_ptr->m_fboId;
+}
+
+/*!
+ Returns the surface given in initialization.
+
+ \sa create()
+*/
+QSurface *Q3DSSurfaceViewer::surface() const
+{
+ return d_ptr->m_surface;
+}
+
+/*!
+ Returns the context given in initialization.
+
+ \sa create()
+*/
+QOpenGLContext *Q3DSSurfaceViewer::context() const
+{
+ return d_ptr->m_context;
+}
+
+/*!
+ Returns the settings object used by the Q3DSSurfaceViewer.
+*/
+Q3DSViewerSettings *Q3DSSurfaceViewer::settings() const
+{
+ return d_ptr->m_settings;
+}
+
+/*!
+ Returns the presentation object used by the Q3DSSurfaceViewer.
+*/
+Q3DSPresentation *Q3DSSurfaceViewer::presentation() const
+{
+ return d_ptr->m_presentation;
+}
+
+/*!
+ * \internal
+ */
+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);
+ }
+}
+
+// TODO: QT3DS-3563
+
+/*!
+ * \brief Q3DSSurfaceViewer::qmlEngine
+ * \return
+ */
+QQmlEngine *Q3DSSurfaceViewer::qmlEngine() const
+{
+ Q_D(const Q3DSSurfaceViewer);
+ return d->qmlEngine;
+}
+
+/*!
+ * \brief Q3DSSurfaceViewer::setQmlEngine
+ * \param qmlEngine
+ */
+void Q3DSSurfaceViewer::setQmlEngine(QQmlEngine *qmlEngine)
+{
+ Q_D(Q3DSSurfaceViewer);
+ d->qmlEngine = qmlEngine;
+}
+
+
+/*!
+ \fn Q3DSSurfaceViewer::frameUpdate()
+
+ Emitted each time a frame has been rendered.
+*/
+
+/*!
+ \fn Q3DSSurfaceViewer::presentationLoaded()
+
+ Emitted when the presentation has been loaded and is ready
+ to be shown.
+*/
+
+/*!
+ \fn Q3DSSurfaceViewer::presentationReady()
+ Emitted when first frame is about to be shown. DataInputs and setAttribute
+ are ready to be used after this signal.
+ */
+
+/*!
+ * \internal
+ */
+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);
+}
+
+/*!
+ * \internal
+ */
+Q3DSSurfaceViewerPrivate::~Q3DSSurfaceViewerPrivate()
+{
+ releaseRuntime();
+
+ delete m_timer;
+}
+
+/*!
+ * \internal
+ */
+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);
+ }
+}
+
+/*!
+ * \internal
+ */
+void Q3DSSurfaceViewerPrivate::setUpdateInterval(int interval)
+{
+ if (m_updateInterval != interval) {
+ m_updateInterval = interval;
+ resetUpdateTimer();
+ Q_EMIT q_ptr->updateIntervalChanged(m_updateInterval);
+ }
+}
+
+/*!
+ * \internal
+ */
+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;
+ }
+
+ destroy();
+
+ 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::destroy);
+
+ bool success = initializeRuntime();
+
+ if (success)
+ Q_EMIT q_ptr->runningChanged(true);
+
+ return success;
+}
+
+/*!
+ * \internal
+ */
+void Q3DSSurfaceViewerPrivate::destroy()
+{
+ bool oldInitialized = (m_viewerApp != nullptr);
+
+ if (m_context) {
+ disconnect(m_context, &QOpenGLContext::aboutToBeDestroyed,
+ this, &Q3DSSurfaceViewerPrivate::destroy);
+ }
+
+ if (m_surface)
+ surfaceObject()->removeEventFilter(this);
+
+ releaseRuntime();
+
+ m_surface = nullptr;
+ m_context = nullptr;
+ m_fboId = 0;
+
+ if (oldInitialized)
+ Q_EMIT q_ptr->runningChanged(false);
+}
+
+/*!
+ * \internal
+ */
+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->frameUpdate();
+ }
+ }
+}
+
+extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format,
+ bool include_alpha);
+
+/*!
+ * \internal
+ */
+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;
+}
+
+/*!
+ * \internal
+ */
+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)
+ destroy();
+ }
+ }
+ return QObject::eventFilter(obj, e);
+}
+
+/*!
+ * \internal
+ */
+void Q3DSSurfaceViewerPrivate::reset()
+{
+ if (m_viewerApp) {
+ releaseRuntime();
+ initializeRuntime();
+ }
+}
+
+/*!
+ * \internal
+ */
+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 (nullptr != qmlEngine)
+ m_presentation->d_ptr->streamProxy()->setEngine(qmlEngine);
+
+ 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;
+}
+
+/*!
+ * \internal
+ */
+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();
+}
+
+/*!
+ * \internal
+ */
+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();
+ }
+}
+
+/*!
+ * \internal
+ */
+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/ogl-runtime/src/api/studio3d/q3dssurfaceviewer.h b/src/Runtime/ogl-runtime/src/api/studio3d/q3dssurfaceviewer.h
new file mode 100644
index 00000000..5c166af9
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3d/q3dssurfaceviewer.h
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** 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 QQmlEngine;
+
+class Q_STUDIO3D_EXPORT Q3DSSurfaceViewer : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(Q3DSSurfaceViewer)
+
+ // #TODO: QT3DS-3532 SurfaceViewer API missing error string
+ //Q_PROPERTY(QString error READ error NOTIFY errorChanged)
+ Q_PROPERTY(bool running READ isRunning NOTIFY runningChanged)
+ 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(QString presentationId READ presentationId WRITE setPresentationId NOTIFY presentationIdChanged)
+
+public:
+ explicit Q3DSSurfaceViewer(QObject *parent = nullptr);
+ ~Q3DSSurfaceViewer();
+
+ bool create(QSurface *surface, QOpenGLContext *context);
+ bool create(QSurface *surface, QOpenGLContext *context, GLuint fboId);
+ void destroy();
+
+ Q3DSPresentation *presentation() const;
+ Q3DSViewerSettings *settings() const;
+
+ bool isRunning() const;
+
+ QSize size() const;
+ void setSize(const QSize &size);
+
+ bool autoSize() const;
+ void setAutoSize(bool autoSize);
+
+ int updateInterval() const;
+ void setUpdateInterval(int interval);
+
+ int fboId() const;
+ QSurface *surface() const;
+ QOpenGLContext *context() const;
+
+ QImage grab(const QRect &rect = QRect());
+
+ QQmlEngine *qmlEngine() const;
+ void setQmlEngine(QQmlEngine *qmlEngine);
+ QString presentationId() const;
+
+public Q_SLOTS:
+ void update();
+ void setPresentationId(const QString &id);
+
+Q_SIGNALS:
+ void presentationLoaded();
+ void presentationReady();
+ void frameUpdate();
+
+ void presentationIdChanged(const QString &id);
+ void sizeChanged(const QSize &size);
+ void autoSizeChanged(bool autoSize);
+ void updateIntervalChanged(bool autoUpdate);
+ void runningChanged(bool initialized);
+
+private:
+ Q_DISABLE_COPY(Q3DSSurfaceViewer)
+ Q3DSSurfaceViewerPrivate *d_ptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // Q3DSSURFACEVIEWER_H
diff --git a/src/Runtime/ogl-runtime/src/api/studio3d/q3dssurfaceviewer_p.h b/src/Runtime/ogl-runtime/src/api/studio3d/q3dssurfaceviewer_p.h
new file mode 100644
index 00000000..fc6b4cc8
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3d/q3dssurfaceviewer_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** 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 QQmlEngine;
+
+class Q_STUDIO3D_EXPORT Q3DSSurfaceViewerPrivate : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PUBLIC(Q3DSSurfaceViewer)
+public:
+ explicit Q3DSSurfaceViewerPrivate(Q3DSSurfaceViewer *parent = nullptr);
+ ~Q3DSSurfaceViewerPrivate();
+
+ 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 destroy();
+
+protected:
+ bool eventFilter(QObject *obj, QEvent *e) override;
+
+private:
+ void reset();
+ 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;
+ QQmlEngine *qmlEngine = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // Q3DSSURFACEVIEWER_P_H
diff --git a/src/Runtime/ogl-runtime/src/api/studio3d/q3dsviewersettings.cpp b/src/Runtime/ogl-runtime/src/api/studio3d/q3dsviewersettings.cpp
new file mode 100644
index 00000000..187729a0
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3d/q3dsviewersettings.cpp
@@ -0,0 +1,401 @@
+/****************************************************************************
+**
+** 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
+
+/*!
+ \qmltype ViewerSettings
+ \instantiates Q3DSViewerSettings
+ \inqmlmodule Qt3DStudio
+ \ingroup OpenGLRuntime
+ \brief Qt 3D Studio presentation viewer settings.
+
+ This type provides properties to define presentation independent viewer settings.
+
+ \note ViewerSettings are only applicable when \l Studio3D is used in the
+ default mode, showing the final, composed image from the Qt 3D Studio
+ renderer.
+
+ \sa Studio3D
+*/
+
+/*!
+ \class Q3DSViewerSettings
+ \inmodule OpenGLRuntime
+ \since Qt 3D Studio 2.0
+
+ \brief Qt 3D Studio presentation viewer settings.
+
+ Q3DSViewerSettings provides properties to define presentation independent
+ viewer settings.
+
+ \note This class should not be instantiated directly when working with the
+ C++ APIs. Q3DSSurfaceViewer and Q3DSWidget create a Q3DSViewerSettings
+ instance implicitly. This can be queried via Q3DSSurfaceViewer::settings()
+ or Q3DSWidget::settings().
+ */
+
+/*!
+ * \internal
+ */
+Q3DSViewerSettings::Q3DSViewerSettings(QObject *parent)
+ : QObject(parent)
+ , d_ptr(new Q3DSViewerSettingsPrivate(this))
+{
+}
+
+/*!
+ * \internal
+ */
+Q3DSViewerSettings::~Q3DSViewerSettings()
+{
+}
+
+/*!
+ \enum Q3DSViewerSettings::ScaleMode
+
+ This enumeration specifies the possible scaling modes.
+
+ \value ScaleModeFit Scales the presentation to fit the output area.
+ \value ScaleModeFill Scales the presentation to completely fill the output area.
+ This is the default.
+ \value ScaleModeCenter Centers the presentation in the output area without scaling it.
+*/
+
+/*!
+ \qmlproperty QColor ViewerSettings::matteColor
+
+ Specifies the matte color.
+ */
+
+/*!
+ \property Q3DSViewerSettings::matteColor
+
+ Specifies the matte color.
+ */
+QColor Q3DSViewerSettings::matteColor() const
+{
+ return d_ptr->m_matteColor;
+}
+
+void Q3DSViewerSettings::setMatteColor(const QColor &color)
+{
+ if (d_ptr->m_matteColor != color) {
+ d_ptr->setMatteColor(color);
+ Q_EMIT matteColorChanged(color);
+ }
+}
+
+/*!
+ \qmlproperty bool ViewerSettings::showRenderStats
+
+ If this property is set to \c true, the simple profile
+ view is displayed in-scene, on top of the 3D content.
+
+ \note this feature can be disabled at build time, in which case this
+ property has no effect.
+
+ The default value is \c{false}.
+*/
+
+/*!
+ \property Q3DSViewerSettings::showRenderStats
+
+ When this property is \c{true}, the simple profile
+ view is displayed in-scene, on top of the 3D content.
+
+ \note This feature can be disabled at build time, in which case this
+ property has no effect.
+
+ Default value is \c{false}.
+*/
+bool Q3DSViewerSettings::isShowRenderStats() const
+{
+ return d_ptr->m_showRenderStats;
+}
+
+void Q3DSViewerSettings::setShowRenderStats(bool show)
+{
+ if (d_ptr->m_showRenderStats != show) {
+ d_ptr->setShowRenderStats(show);
+ Q_EMIT showRenderStatsChanged(show);
+ }
+}
+
+/*!
+ \qmlproperty ViewerSettings::shadeMode
+ */
+
+/*!
+ \property Q3DSViewerSettings::shadeMode
+ */
+Q3DSViewerSettings::ShadeMode Q3DSViewerSettings::shadeMode() const
+{
+ return d_ptr->m_shadeMode;
+}
+
+void Q3DSViewerSettings::setShadeMode(Q3DSViewerSettings::ShadeMode mode)
+{
+ if (d_ptr->m_shadeMode != mode) {
+ d_ptr->setShadeMode(mode);
+ Q_EMIT shadeModeChanged(mode);
+ }
+}
+
+/*!
+ \qmlproperty enumeration ViewerSettings::scaleMode
+
+ Specifies the scaling mode. The default value \c is ScaleModeFill where the
+ size of the presentation on-screen follows and fills the size of the output
+ area (the window, the screen, or the area occupied by the Studio3D
+ element).
+
+ During the design phase it can be valuable to see the presentation with
+ some other scaling approach. For example, the Qt 3D Studio Viewer
+ application uses ScaleModeCenter by default.
+
+ \value ScaleModeFit Scales the presentation to fit the output area.
+ \value ScaleModeFill Scales the presentation to completely fill the output area.
+ \value ScaleModeCenter Centers the presentation in the output area without scaling it.
+
+ The default value is \c{ScaleModeFill}.
+*/
+/*!
+ \property Q3DSViewerSettings::scaleMode
+
+ Specifies the scaling mode. The default value \c is ScaleModeFill where the
+ size of the presentation on-screen follows and fills the size of the output
+ area (the window, the screen, or the area occupied by the \l Studio3D
+ element).
+
+ During the design phase it can be valuable to see the presentation with
+ some other scaling approach. For example, the Qt 3D Studio Viewer
+ application uses ScaleModeCenter by default.
+
+ \value ScaleModeFit Scales the presentation to fit the output area.
+ \value ScaleModeFill Scales the presentation to completely fill the output area.
+ \value ScaleModeCenter Centers the presentation in the output area without scaling it.
+
+ The default value is \c{ScaleModeFill}.
+ */
+Q3DSViewerSettings::ScaleMode Q3DSViewerSettings::scaleMode() const
+{
+ return d_ptr->m_scaleMode;
+}
+
+void Q3DSViewerSettings::setScaleMode(Q3DSViewerSettings::ScaleMode mode)
+{
+ if (d_ptr->m_scaleMode != mode) {
+ d_ptr->setScaleMode(mode);
+ Q_EMIT scaleModeChanged(mode);
+ }
+}
+
+/*!
+ \qmmlmethod ViewerSettings::save
+ Persistently saves the viewer \l{QSettings}{settings} using \a group, \a organization and
+ \a application.
+ \param group
+ \param organization
+ \param application
+ */
+/*!
+ * \brief Q3DSViewerSettings::save Persistently saves the viewer \l{QSettings}{settings}
+ Persistently saves the viewer \l{QSettings}{settings} using \a group, \a organization and
+ \a application.
+ \param group
+ \param organization
+ \param application
+ */
+void Q3DSViewerSettings::save(const QString &group, const QString &organization,
+ const QString &application)
+{
+ d_ptr->save(group, organization, application);
+}
+
+/*!
+ \qmlmethod ViewerSettings::load
+ Loads previously saved viewer \l{QSettings}{settings} using \a group, \a organization and
+ \a application.
+ \param group
+ \param organization
+ \param application
+ */
+/*!
+ * \brief Q3DSViewerSettings::load Loads previously saved viewer \l{QSettings}{settings}
+ Loads previously saved viewer \l{QSettings}{settings} using \a group, \a organization and
+ \a application.
+ \param group
+ \param organization
+ \param application
+ */
+void Q3DSViewerSettings::load(const QString &group, const QString &organization,
+ const QString &application)
+{
+ d_ptr->load(group, organization, application);
+}
+
+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/ogl-runtime/src/api/studio3d/q3dsviewersettings.h b/src/Runtime/ogl-runtime/src/api/studio3d/q3dsviewersettings.h
new file mode 100644
index 00000000..5d7abf68
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3d/q3dsviewersettings.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** 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)
+
+// #TODO: QT3DS-3542 Q3DSViewerSettings API is missing property matteEnabled compared to 2.3
+// Q_PROPERTY(bool matteEnabled READ matteEnabled WRITE setMatteEnabled NOTIFY matteEnabledChanged)
+
+ Q_PROPERTY(QColor matteColor READ matteColor WRITE setMatteColor NOTIFY matteColorChanged)
+ Q_PROPERTY(bool showRenderStats READ isShowRenderStats WRITE setShowRenderStats NOTIFY showRenderStatsChanged)
+ 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;
+ 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 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;
+
+ ShadeMode shadeMode() const;
+ void setShadeMode(ShadeMode mode);
+
+ friend class Q3DSSurfaceViewerPrivate;
+ friend class Q3DSRenderer;
+ friend class Q3DSStudio3D;
+};
+
+QT_END_NAMESPACE
+
+#endif // Q3DSVIEWERSETTINGS_H
diff --git a/src/Runtime/ogl-runtime/src/api/studio3d/q3dsviewersettings_p.h b/src/Runtime/ogl-runtime/src/api/studio3d/q3dsviewersettings_p.h
new file mode 100644
index 00000000..48fbae3a
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/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/ogl-runtime/src/api/studio3d/qstudio3dglobal.h b/src/Runtime/ogl-runtime/src/api/studio3d/qstudio3dglobal.h
new file mode 100644
index 00000000..d1960634
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/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/ogl-runtime/src/api/studio3d/studio3d.pro b/src/Runtime/ogl-runtime/src/api/studio3d/studio3d.pro
new file mode 100644
index 00000000..62d0613f
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3d/studio3d.pro
@@ -0,0 +1,56 @@
+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 += \
+ q3dsdataoutput.h \
+ q3dsdataoutput_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 \
+ q3dsgeometry.h \
+ q3dsgeometry_p.h
+
+SOURCES += q3dsdataoutput.cpp \
+ q3dssurfaceviewer.cpp \
+ viewerqmlstreamproxy.cpp \
+ q3dsviewersettings.cpp \
+ q3dspresentation.cpp \
+ q3dssceneelement.cpp \
+ q3dselement.cpp \
+ studioutils.cpp \
+ q3dscommandqueue.cpp \
+ q3dsimagesequencegenerator.cpp \
+ q3dsimagesequencegeneratorthread.cpp \
+ q3dsdatainput.cpp \
+ q3dsgeometry.cpp
+
+load(qt_module)
+
+OTHER_FILES += $$PWD/../../../doc/src/12-cpp-reference/*
diff --git a/src/Runtime/ogl-runtime/src/api/studio3d/studioutils.cpp b/src/Runtime/ogl-runtime/src/api/studio3d/studioutils.cpp
new file mode 100644
index 00000000..9156be7f
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/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/ogl-runtime/src/api/studio3d/studioutils_p.h b/src/Runtime/ogl-runtime/src/api/studio3d/studioutils_p.h
new file mode 100644
index 00000000..afec688c
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/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/ogl-runtime/src/api/studio3d/viewerqmlstreamproxy.cpp b/src/Runtime/ogl-runtime/src/api/studio3d/viewerqmlstreamproxy.cpp
new file mode 100644
index 00000000..520dc8c6
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/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/ogl-runtime/src/api/studio3d/viewerqmlstreamproxy_p.h b/src/Runtime/ogl-runtime/src/api/studio3d/viewerqmlstreamproxy_p.h
new file mode 100644
index 00000000..16569c1c
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/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/ogl-runtime/src/api/studio3dqml/q3dsplugin.cpp b/src/Runtime/ogl-runtime/src/api/studio3dqml/q3dsplugin.cpp
new file mode 100644
index 00000000..640018f4
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3dqml/q3dsplugin.cpp
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 NVIDIA CORPORATION.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "q3dsplugin.h"
+
+#include <QtQml/qqml.h>
+
+#include <QtStudio3D/private/q3dsviewersettings_p.h>
+
+#include "q3dsstudio3d_p.h"
+#include "q3dspresentationitem_p.h"
+#include "q3dsqmlstream.h"
+#include "q3dsqmlsubpresentationsettings.h"
+#include "q3dssceneelement.h"
+#include "q3dsdatainput.h"
+
+QT_BEGIN_NAMESPACE
+
+void Q3DSPlugin::registerTypes(const char *uri)
+{
+ Q_ASSERT(uri == QLatin1String("QtStudio3D.OpenGL"));
+
+ // @uri QtStudio3D.OpenGL
+ qmlRegisterType<Q3DSStudio3D>(uri, 2, 4, "Studio3D");
+ qmlRegisterType<Q3DSViewerSettings>(uri, 2, 4, "ViewerSettings");
+ qmlRegisterType<Q3DSPresentationItem>(uri, 2, 4, "Presentation");
+ qmlRegisterType<Q3DSSceneElement>(uri, 2, 4, "SceneElement");
+ qmlRegisterType<Q3DSElement>(uri, 2, 4, "Element");
+ qmlRegisterType<Q3DSQmlStream>(uri, 2, 4, "QmlStream");
+ qmlRegisterType<Q3DSSubPresentationSettings>(uri, 2, 4, "SubPresentationSettings");
+ qmlRegisterType<Q3DSDataInput>(uri, 2, 4, "DataInput");
+ qmlRegisterType<Q3DSDataOutput>(uri, 2, 4, "DataOutput");
+}
+
+QT_END_NAMESPACE
diff --git a/src/Runtime/ogl-runtime/src/api/studio3dqml/q3dsplugin.h b/src/Runtime/ogl-runtime/src/api/studio3dqml/q3dsplugin.h
new file mode 100644
index 00000000..04f69429
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3dqml/q3dsplugin.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 NVIDIA CORPORATION.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3DS_PLUGIN_H
+#define Q3DS_PLUGIN_H
+
+#include <QtQml/qqmlextensionplugin.h>
+
+static void initResources()
+{
+#ifdef QT_STATIC
+ Q_INIT_RESOURCE(qmake_QtStudio3D_OpenGL);
+#endif
+}
+
+QT_BEGIN_NAMESPACE
+
+class Q3DSPlugin : public QQmlExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
+
+public:
+ Q3DSPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent)
+ {
+ initResources();
+ }
+ void registerTypes(const char *uri) override;
+};
+
+QT_END_NAMESPACE
+
+#endif // Q3DS_PLUGIN_H
diff --git a/src/Runtime/ogl-runtime/src/api/studio3dqml/q3dspresentationitem.cpp b/src/Runtime/ogl-runtime/src/api/studio3dqml/q3dspresentationitem.cpp
new file mode 100644
index 00000000..407739e5
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3dqml/q3dspresentationitem.cpp
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "q3dspresentationitem_p.h"
+
+#include <QtStudio3D/q3dssceneelement.h>
+#include <QtStudio3D/q3dsdatainput.h>
+#include <QtStudio3D/private/q3dspresentation_p.h>
+#include <QtStudio3D/private/viewerqmlstreamproxy_p.h>
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Presentation
+ \instantiates Q3DSPresentationItem
+ \inqmlmodule QtStudio3D
+ \ingroup OpenGLRuntime
+ \inherits Q3DSPresentation
+ \keyword Studio3D
+
+ \brief Represents a Qt 3D Studio presentation.
+
+ This item provides properties and methods for controlling a
+ presentation.
+
+ Qt 3D Studio supports multiple presentations in one project. There
+ is always a main presentation and zero or more
+ sub-presentations. The sub-presentations are composed into the
+ main presentations either as contents of Qt 3D Studio layers or as
+ texture maps.
+
+ In the filesystem each presentation corresponds to one \c{.uip}
+ presentation file. When present, the \c{.uia} project file ties
+ these together by specifying a name for each of the
+ (sub-)presentations and specifies which one is the main one.
+
+ The \c{.uia} project also defines \l{DataInput}s and
+ \l{DataOutput}s that are exported by the presentations.
+ \l{DataInput}s provide a way to provide input to the presentation
+ to e.g. control a timeline of a subpresentation from code.
+ \l{DataOutput}s provide a way to get notified when an attribute
+ is changed in the presentation by animation timeline,
+ by behavior scripts or by a \l{DataInput}.
+
+ From the API point of view Presentation corresponds to the
+ main presentation. The source property can refer either to a
+ \c{.uia} or \c{.uip} file. When specifying a file with \c{.uip}
+ extension and a \c{.uia} is present with the same name, the
+ \c{.uia} is loaded automatically and thus sub-presentation
+ information is available regardless.
+ */
+Q3DSPresentationItem::Q3DSPresentationItem(QObject *parent)
+ : Q3DSPresentation(parent)
+ , m_subPresentationSettings(nullptr)
+{
+}
+
+Q3DSPresentationItem::~Q3DSPresentationItem()
+{
+}
+
+// #TODO: QT3DS-3565 subPresentationSettings is missing documentation
+/*!
+ \qmlproperty SubPresentationSettings Presentation::subPresentationSettings
+
+ Note: This property is read-only.
+ */
+Q3DSSubPresentationSettings *Q3DSPresentationItem::subPresentationSettings() const
+{
+ return m_subPresentationSettings;
+}
+
+QQmlListProperty<QObject> Q3DSPresentationItem::qmlChildren()
+{
+ return QQmlListProperty<QObject>(this, nullptr, &appendQmlChildren, nullptr, nullptr, nullptr);
+}
+
+void Q3DSPresentationItem::appendQmlChildren(QQmlListProperty<QObject> *list, QObject *obj)
+{
+ auto item = qobject_cast<Q3DSPresentationItem *>(list->object);
+ if (item) {
+ auto scene = qobject_cast<Q3DSSceneElement *>(obj);
+ if (scene) {
+ if (item->registeredElement(scene->elementPath()))
+ qWarning() << __FUNCTION__ << "A duplicate SceneElement defined for Presentation.";
+ else
+ item->registerElement(scene);
+ } else {
+ auto studioElement = qobject_cast<Q3DSElement *>(obj);
+ if (studioElement) {
+ if (item->registeredElement(studioElement->elementPath()))
+ qWarning() << __FUNCTION__ << "A duplicate Element defined for Presentation.";
+ else
+ item->registerElement(studioElement);
+ } else {
+ auto subPresSettings = qobject_cast<Q3DSSubPresentationSettings *>(obj);
+ if (subPresSettings) {
+ if (item->m_subPresentationSettings) {
+ qWarning() << __FUNCTION__
+ << "Duplicate SubPresentationSettings defined for Presentation.";
+ } else {
+ item->m_subPresentationSettings = subPresSettings;
+ item->d_ptr->streamProxy()->setSettings(subPresSettings);
+ }
+ } else {
+ auto dataInput = qobject_cast<Q3DSDataInput *>(obj);
+ if (dataInput) {
+ if (item->registeredDataInput(dataInput->name())) {
+ qWarning() << __FUNCTION__
+ << "Duplicate DataInput defined for Presentation.";
+ } else {
+ item->registerDataInput(dataInput);
+ }
+ } else {
+ auto dataOutput = qobject_cast<Q3DSDataOutput *>(obj);
+ if (dataOutput) {
+ if (item->registeredDataOutput(dataOutput->name())) {
+ qWarning() << __FUNCTION__
+ << "Duplicate DataOutput defined for Presentation.";
+ } else {
+ item->registerDataOutput(dataOutput);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/Runtime/ogl-runtime/src/api/studio3dqml/q3dspresentationitem_p.h b/src/Runtime/ogl-runtime/src/api/studio3dqml/q3dspresentationitem_p.h
new file mode 100644
index 00000000..757f34fa
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3dqml/q3dspresentationitem_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 Q3DSPRESENTATIONITEM_H
+#define Q3DSPRESENTATIONITEM_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtStudio3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "q3dsqmlsubpresentationsettings.h"
+
+#include <QtStudio3D/q3dspresentation.h>
+#include <QtQml/qqmllist.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q3DSPresentationItem : public Q3DSPresentation
+{
+ Q_OBJECT
+ Q_PROPERTY(QQmlListProperty<QObject> qmlChildren READ qmlChildren DESIGNABLE false)
+ Q_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/ogl-runtime/src/api/studio3dqml/q3dsrenderer.cpp b/src/Runtime/ogl-runtime/src/api/studio3dqml/q3dsrenderer.cpp
new file mode 100644
index 00000000..bbfee502
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3dqml/q3dsrenderer.cpp
@@ -0,0 +1,458 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 NVIDIA CORPORATION.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "q3dsrenderer_p.h"
+#include "Qt3DSViewerApp.h"
+#include "Qt3DSAudioPlayerImpl.h"
+#include "q3dspresentationitem_p.h"
+
+#include <QtStudio3D/private/q3dscommandqueue_p.h>
+#include <QtStudio3D/private/q3dsviewersettings_p.h>
+#include <QtStudio3D/private/q3dspresentation_p.h>
+#include <QtStudio3D/private/studioutils_p.h>
+#include <QtStudio3D/private/q3dsdatainput_p.h>
+
+#include <QtCore/qdebug.h>
+#include <QtGui/qwindow.h>
+#include <QtGui/qopenglcontext.h>
+#include <QtQuick/qquickwindow.h>
+
+using namespace Q3DSViewer;
+
+QT_BEGIN_NAMESPACE
+
+Q3DSRenderer::Q3DSRenderer(bool visibleFlag, qt3ds::Qt3DSAssetVisitor *assetVisitor)
+ : m_visibleFlag(visibleFlag)
+ , m_initElements(false)
+ , m_runtime(0)
+ , m_window(nullptr)
+ , m_initialized(false)
+ , m_initializationFailure(false)
+ , m_visitor(assetVisitor)
+ , m_settings(new Q3DSViewerSettings(this))
+ , m_presentation(new Q3DSPresentation(this))
+{
+ m_startupTimer.start();
+}
+
+Q3DSRenderer::~Q3DSRenderer()
+{
+ releaseRuntime();
+}
+
+QOpenGLFramebufferObject *Q3DSRenderer::createFramebufferObject(const QSize &size)
+{
+ QOpenGLFramebufferObjectFormat theFormat;
+ theFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
+ QOpenGLFramebufferObject *frameBuffer =
+ new QOpenGLFramebufferObject(size, theFormat);
+ if (m_runtime && m_runtime->IsInitialised())
+ m_runtime->setOffscreenId(frameBuffer->handle());
+ return frameBuffer;
+}
+
+/** Pull pending commands from the plugin.
+ * Invoked automatically by the QML scene graph.
+ *
+ * This is the only place where it is valid for the Q3DSStudio3D plugin and render to communicate.
+ */
+void Q3DSRenderer::synchronize(QQuickFramebufferObject *inView)
+{
+ // Passing m_InitElements here is a bit of a hack to easily set the flag on the plugin.
+ static_cast<Q3DSStudio3D *>(inView)->getCommands(m_initElements, m_commands);
+
+ if (m_initializationFailure)
+ static_cast<Q3DSStudio3D *>(inView)->setError(m_error);
+
+ if (m_commands.m_sourceChanged || m_commands.m_variantListChanged) {
+ releaseRuntime();
+ // Need to update source and variant list here rather than
+ // processCommands, as both are needed for init
+ m_presentation->setVariantList(m_commands.m_variantList);
+ m_presentation->setSource(m_commands.m_source);
+ m_presentation->setDelayedLoading(m_commands.m_delayedLoading);
+ m_initialized = false;
+ m_initializationFailure = false;
+ m_error.clear();
+ static_cast<Q3DSStudio3D *>(inView)->setError(QString());
+ }
+
+ m_initElements = false;
+
+ // We need a handle to the window to be able to reset the GL state inside of Draw().
+ // See https://bugreports.qt.io/browse/QTBUG-47213
+ if (!m_window)
+ m_window = inView->window();
+}
+
+void Q3DSRenderer::releaseRuntime()
+{
+ m_settings->d_ptr->setViewerApp(nullptr);
+ m_presentation->d_ptr->setViewerApp(nullptr);
+
+ if (m_runtime) {
+ m_runtime->Release();
+ m_runtime = nullptr;
+ }
+}
+
+/** Invoked by the QML scene graph indicating that it's time to render.
+ * Calls `draw()` if the plugin is visible, or `processCommands()` otherwise.
+ *
+ * Note that this will still render if the plugin is opacity:0. To avoid this,
+ * add a line to your QML to hide the object when opacity is zero, like:
+ *
+ * visible: opacity != 0
+ */
+void Q3DSRenderer::render()
+{
+ // We may start in a non visible state but we still need
+ // to init the runtime otherwise the commands are never processed
+ if (!m_initialized && !m_initializationFailure) {
+ m_initialized = initializeRuntime(this->framebufferObject());
+ m_initializationFailure = !m_initialized;
+ if (m_initializationFailure)
+ m_commands.clear(true);
+ }
+
+ // Don't render if the plugin is hidden; however, if hidden, but sure
+ // to process pending commands so we can be shown again.
+ if (m_initialized) {
+ if (m_visibleFlag)
+ draw();
+ else
+ processCommands();
+ update(); // mark as dirty to ensure update again
+ }
+}
+
+/** Cause Qt3DS runtime to render content.
+ * Initializes GL and the runtime when called the first time.
+ */
+void Q3DSRenderer::draw()
+{
+ if (m_runtime && m_runtime->IsInitialised() && m_window) {
+ if (m_initialized)
+ m_runtime->RestoreState();
+ m_runtime->Render();
+ m_runtime->SaveState();
+
+ m_window->resetOpenGLState();
+ }
+}
+
+bool Q3DSRenderer::initializeRuntime(QOpenGLFramebufferObject *inFbo)
+{
+ m_runtime = &Q3DSViewerApp::Create(nullptr, new Qt3DSAudioPlayerImpl(), &m_startupTimer);
+ Q_ASSERT(m_runtime);
+
+ // Connect presentation ready signal before initializing the app
+ connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigPresentationReady,
+ this, &Q3DSRenderer::presentationReady);
+ connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigPresentationLoaded,
+ this, &Q3DSRenderer::presentationLoaded);
+
+ int theWidth = inFbo->width();
+ int theHeight = inFbo->height();
+
+ const QString localSource = Q3DSUtils::urlToLocalFileOrQrc(m_presentation->source());
+
+ if (!m_runtime->InitializeApp(theWidth, theHeight,
+ QOpenGLContext::currentContext()->format(),
+ inFbo->handle(), localSource,
+ m_presentation->variantList(),
+ m_presentation->delayedLoading(),
+ m_visitor)) {
+ m_error = m_runtime->error();
+ releaseRuntime();
+ return false;
+ }
+
+ m_runtime->RegisterScriptCallback(Q3DSViewer::ViewerCallbackType::Enum::CALLBACK_ON_INIT,
+ reinterpret_cast<qml_Function>(Q3DSRenderer::onInitHandler),
+ this);
+ m_runtime->RegisterScriptCallback(Q3DSViewer::ViewerCallbackType::Enum::CALLBACK_ON_UPDATE,
+ reinterpret_cast<qml_Function>(Q3DSRenderer::onUpdateHandler),
+ this);
+
+ m_settings->d_ptr->setViewerApp(m_runtime);
+ m_presentation->d_ptr->setViewerApp(m_runtime, false);
+
+ // Connect signals
+ connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigSlideEntered,
+ this, &Q3DSRenderer::enterSlide);
+ connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigSlideExited,
+ this, &Q3DSRenderer::exitSlide);
+ connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigCustomSignal,
+ this, &Q3DSRenderer::customSignalEmitted);
+ connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigElementsCreated,
+ this, &Q3DSRenderer::elementsCreated);
+ connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigMaterialsCreated,
+ this, &Q3DSRenderer::materialsCreated);
+ connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigMeshesCreated,
+ this, &Q3DSRenderer::meshesCreated);
+ connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigDataOutputValueUpdated,
+ this, &Q3DSRenderer::dataOutputValueUpdated);
+
+ return true;
+}
+
+/** Accept user commands (e.g. setAttribute) needed to initialize the code.
+ *
+ * If we attempt to run Qt3DS methods like setAttribute() before the runtime
+ * has been initialized, they will be lost. This method is the correct place
+ * to accept user commands.
+ *
+ * Currently this method just sets a flag needed to pass a flag to the
+ * plugin next time syncronize() is called, which eventually gets the plugin
+ * to emit an `runningChanged` signal the next time `tick()` is called.
+ * As a result, code specified in an `onRunningChanged` handler may be run
+ * after one or more frames have already rendered.
+ */
+void Q3DSRenderer::onInitHandler(void *userData)
+{
+ Q3DSRenderer *theRenderer = static_cast<Q3DSRenderer *>(userData);
+ theRenderer->setInitElements(true);
+}
+
+/** Accept the latest pending user commands (e.g. setAttribute).
+ *
+ * This method just calls `ProcessCommands` to avoid unnecessary
+ * pointer dereferencing and accessor methods (or public member variables).
+ */
+void Q3DSRenderer::onUpdateHandler(void *userData)
+{
+ Q3DSRenderer *theRenderer = static_cast<Q3DSRenderer *>(userData);
+ theRenderer->processCommands();
+}
+
+/** Apply commands queued up by the user (e.g. setAttribute).
+ *
+ * Note that these commands are executed even if the plugin is not visible,
+ * in part to allow changes to the visible flag to be noticed, but also
+ * to allow specialty code to continue to be queued up even when not rendering.
+ */
+void Q3DSRenderer::processCommands()
+{
+ if (!m_runtime) {
+ m_commands.clear(true);
+ return;
+ }
+
+ if (m_commands.m_visibleChanged)
+ m_visibleFlag = m_commands.m_visible;
+
+ if (QOpenGLFramebufferObject *inFbo = this->framebufferObject()) {
+ if (inFbo->isValid() && (inFbo->width() != m_runtime->GetWindowWidth()
+ || inFbo->height() != m_runtime->GetWindowHeight())) {
+ m_runtime->Resize(inFbo->width(), inFbo->height());
+ }
+ }
+
+ if (m_commands.m_scaleModeChanged)
+ m_settings->setScaleMode(m_commands.m_scaleMode);
+ if (m_commands.m_shadeModeChanged)
+ m_settings->setShadeMode(m_commands.m_shadeMode);
+ if (m_commands.m_matteColorChanged)
+ m_settings->setMatteColor(m_commands.m_matteColor);
+ if (m_commands.m_showRenderStatsChanged)
+ m_settings->setShowRenderStats(m_commands.m_showRenderStats);
+ if (m_commands.m_delayedLoadingChanged)
+ this->m_runtime->setDelayedLoading(m_commands.m_delayedLoading);
+
+ if (m_commands.m_globalAnimationTimeChanged)
+ m_presentation->setGlobalAnimationTime(m_commands.m_globalAnimationTime);
+
+ // Send scene graph changes over to Q3DS
+ for (int i = 0; i < m_commands.size(); i++) {
+ const ElementCommand &cmd = m_commands.constCommandAt(i);
+ switch (cmd.m_commandType) {
+ case CommandType_SetAttribute:
+ m_presentation->setAttribute(cmd.m_elementPath, cmd.m_stringValue, cmd.m_variantValue);
+ break;
+ case CommandType_SetPresentationActive:
+ m_presentation->setPresentationActive(cmd.m_elementPath, cmd.m_boolValue);
+ break;
+ case CommandType_GoToTime:
+ m_presentation->goToTime(cmd.m_elementPath, cmd.m_floatValue);
+ break;
+ case CommandType_GoToSlide:
+ m_presentation->goToSlide(cmd.m_elementPath, cmd.m_intValues[0]);
+ break;
+ case CommandType_GoToSlideByName:
+ m_presentation->goToSlide(cmd.m_elementPath, cmd.m_stringValue);
+ break;
+ case CommandType_GoToSlideRelative:
+ m_presentation->goToSlide(cmd.m_elementPath, bool(cmd.m_intValues[0]),
+ bool(cmd.m_intValues[1]));
+ break;
+ case CommandType_FireEvent:
+ m_presentation->fireEvent(cmd.m_elementPath, cmd.m_stringValue);
+ break;
+ case CommandType_MousePress:
+ m_runtime->HandleMousePress(cmd.m_intValues[0],
+ cmd.m_intValues[1], cmd.m_intValues[2], true);
+ break;
+ case CommandType_MouseRelease:
+ m_runtime->HandleMousePress(cmd.m_intValues[0],
+ cmd.m_intValues[1], cmd.m_intValues[2], false);
+ break;
+ case CommandType_MouseMove:
+ m_runtime->HandleMouseMove(cmd.m_intValues[0], cmd.m_intValues[1], true);
+ break;
+ case CommandType_MouseWheel:
+ m_runtime->HandleMouseWheel(cmd.m_intValues[0], cmd.m_intValues[1],
+ bool(cmd.m_intValues[2]), cmd.m_intValues[3]);
+ break;
+ case CommandType_KeyPress:
+ m_runtime->HandleKeyInput(Q3DStudio::EKeyCode(cmd.m_intValues[0]), true);
+ break;
+ case CommandType_KeyRelease:
+ m_runtime->HandleKeyInput(Q3DStudio::EKeyCode(cmd.m_intValues[0]), false);
+ break;
+ case CommandType_SetDataInputValue:
+ m_runtime->SetDataInputValue(
+ cmd.m_stringValue, cmd.m_variantValue,
+ static_cast<qt3ds::runtime::DataInputValueRole>(cmd.m_intValues[0]));
+ break;
+ case CommandType_CreateElements: {
+ m_runtime->createElements(
+ cmd.m_elementPath, cmd.m_stringValue,
+ *static_cast<QVector<QHash<QString, QVariant>> *>(cmd.m_data));
+ // Runtime makes copy of the data in its own format, so we can delete it now
+ auto &command = m_commands.commandAt(i);
+ delete reinterpret_cast<QVector<QHash<QString, QVariant>> *>(command.m_data);
+ command.m_data = nullptr;
+ break;
+ }
+ case CommandType_DeleteElements: {
+ m_runtime->deleteElements(*static_cast<QStringList *>(cmd.m_data));
+ // Runtime makes copy of the data in its own format, so we can delete it now
+ auto &command = m_commands.commandAt(i);
+ delete reinterpret_cast<QStringList *>(command.m_data);
+ command.m_data = nullptr;
+ break;
+ }
+ case CommandType_CreateMaterials: {
+ m_runtime->createMaterials(cmd.m_elementPath, *static_cast<QStringList *>(cmd.m_data));
+ // Runtime makes copy of the data in its own format, so we can delete it now
+ auto &command = m_commands.commandAt(i);
+ delete reinterpret_cast<QStringList *>(command.m_data);
+ command.m_data = nullptr;
+ break;
+ }
+ case CommandType_DeleteMaterials: {
+ m_runtime->deleteMaterials(cmd.m_elementPath, *static_cast<QStringList *>(cmd.m_data));
+ // Runtime makes copy of the data in its own format, so we can delete it now
+ auto &command = m_commands.commandAt(i);
+ delete reinterpret_cast<QStringList *>(command.m_data);
+ command.m_data = nullptr;
+ break;
+ }
+ case CommandType_CreateMeshes: {
+ m_runtime->createMeshes(*static_cast<QHash<QString, Q3DSViewer::MeshData> *>(
+ cmd.m_data));
+ // Runtime makes copy of the data, so we can delete it now
+ auto &command = m_commands.commandAt(i);
+ auto meshData = reinterpret_cast<QHash<QString, Q3DSViewer::MeshData> *>(
+ command.m_data);
+ delete meshData;
+ command.m_data = nullptr;
+ break;
+ }
+ case CommandType_DeleteMeshes: {
+ m_runtime->deleteMeshes(*static_cast<QStringList *>(cmd.m_data));
+ // Runtime makes copy of the data in its own format, so we can delete it now
+ auto &command = m_commands.commandAt(i);
+ delete reinterpret_cast<QStringList *>(command.m_data);
+ command.m_data = nullptr;
+ break;
+ }
+ case CommandType_RequestSlideInfo: {
+ int current = 0;
+ int previous = 0;
+ QString currentName;
+ QString previousName;
+ const QByteArray path(cmd.m_elementPath.toUtf8());
+ m_runtime->GetSlideInfo(path, current, previous, currentName, previousName);
+ QVariantList *requestData = new QVariantList();
+ requestData->append(QVariant(current));
+ requestData->append(QVariant(previous));
+ requestData->append(QVariant(currentName));
+ requestData->append(QVariant(previousName));
+
+ Q_EMIT requestResponse(cmd.m_elementPath, cmd.m_commandType, requestData);
+
+ break;
+ }
+ case CommandType_RequestDataInputs: {
+ QVariantList *requestData = new QVariantList();
+ if (m_runtime) {
+ const auto diList = m_runtime->dataInputs();
+
+ for (const auto &it : diList) {
+ Q3DSDataInput *newIt = new Q3DSDataInput(it, nullptr);
+ newIt->d_ptr->m_max = m_runtime->dataInputMax(it);
+ newIt->d_ptr->m_min = m_runtime->dataInputMin(it);
+
+ requestData->append(QVariant::fromValue(newIt));
+ }
+ }
+
+ Q_EMIT requestResponse(cmd.m_elementPath, cmd.m_commandType, requestData);
+ break;
+ }
+ case CommandType_RequestDataOutputs: {
+ QVariantList *requestData = new QVariantList();
+ if (m_presentation) {
+ const auto diList = m_presentation->dataOutputs();
+
+ for (const auto &it : diList)
+ requestData->append(QVariant::fromValue(it->name()));
+ }
+
+ Q_EMIT requestResponse(cmd.m_elementPath, cmd.m_commandType, requestData);
+ break;
+ }
+ case CommandType_PreloadSlide:
+ m_runtime->preloadSlide(cmd.m_elementPath);
+ break;
+ case CommandType_UnloadSlide:
+ m_runtime->unloadSlide(cmd.m_elementPath);
+ break;
+ default:
+ qWarning() << __FUNCTION__ << "Unrecognized CommandType in command list!";
+ }
+ }
+
+ m_commands.clear(false);
+}
+
+QT_END_NAMESPACE
diff --git a/src/Runtime/ogl-runtime/src/api/studio3dqml/q3dsrenderer_p.h b/src/Runtime/ogl-runtime/src/api/studio3dqml/q3dsrenderer_p.h
new file mode 100644
index 00000000..6d044ff7
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3dqml/q3dsrenderer_p.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 NVIDIA CORPORATION.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3DS_RENDERER_H
+#define Q3DS_RENDERER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtStudio3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/qopenglframebufferobject.h>
+#include <QtQuick/qquickframebufferobject.h>
+
+#include "Qt3DSViewerApp.h"
+#include "q3dsstudio3d_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q3DSViewerSettings;
+class Q3DSPresentation;
+
+class Q3DSRenderer : public QObject,
+ public QQuickFramebufferObject::Renderer
+{
+ Q_OBJECT
+
+public:
+ Q3DSRenderer(bool visibleFlag, qt3ds::Qt3DSAssetVisitor *assetVisitor);
+ ~Q3DSRenderer();
+
+ QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) override;
+
+ void setInitElements(bool inFlag) { m_initElements = inFlag; }
+ void processCommands();
+
+Q_SIGNALS:
+ void enterSlide(const QString &elementPath, unsigned int slide, const QString &slideName);
+ void exitSlide(const QString &elementPath, unsigned int slide, const QString &slideName);
+ void requestResponse(const QString &elementPath, CommandType commandType, void *requestData);
+ void presentationReady();
+ void presentationLoaded();
+ void customSignalEmitted(const QString &elNmentPath, const QString &name);
+ void elementsCreated(const QStringList &elementPaths, const QString &error);
+ void materialsCreated(const QStringList &materialNames, const QString &error);
+ void meshesCreated(const QStringList &meshNames, const QString &error);
+ void dataOutputValueUpdated(const QString &name, const QVariant &newValue);
+
+protected:
+ static void onInitHandler(void *userData);
+ static void onUpdateHandler(void *userData);
+ bool initializeRuntime(QOpenGLFramebufferObject *inFbo);
+ void draw();
+ void render() override;
+ void synchronize(QQuickFramebufferObject *inView) override;
+ void releaseRuntime();
+
+protected:
+ bool m_visibleFlag; // Is the plugin visible? Prevents rendering hidden content.
+ CommandQueue m_commands; // A list of commands retrieved by the plugin to be applied.
+ bool m_initElements; // Flag set when the runtime is first ready to render.
+ Q3DSViewer::Q3DSViewerApp *m_runtime; // The Qt3DS viewer that renders all content.
+ QQuickWindow *m_window; // Window associated with the plugin; needed to reset OpenGL state.
+
+ bool m_initialized; // Has the runtime and OpenGL state been initialized?
+ bool m_initializationFailure; // Initialization failed, no point in trying to init again
+ qt3ds::Qt3DSAssetVisitor *m_visitor;
+
+ Q3DSViewerSettings *m_settings;
+ Q3DSPresentation *m_presentation;
+ QString m_error;
+ QElapsedTimer m_startupTimer;
+};
+
+QT_END_NAMESPACE
+
+#endif // Q3DS_RENDERER_H
diff --git a/src/Runtime/ogl-runtime/src/api/studio3dqml/q3dsstudio3d.cpp b/src/Runtime/ogl-runtime/src/api/studio3dqml/q3dsstudio3d.cpp
new file mode 100644
index 00000000..3d48babc
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3dqml/q3dsstudio3d.cpp
@@ -0,0 +1,535 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 NVIDIA CORPORATION.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "q3dsstudio3d_p.h"
+#include "q3dsrenderer_p.h"
+#include "q3dspresentationitem_p.h"
+
+#include <QtStudio3D/private/q3dsviewersettings_p.h>
+#include <QtStudio3D/private/q3dspresentation_p.h>
+#include <QtStudio3D/private/q3dssceneelement_p.h>
+#include <QtStudio3D/private/viewerqmlstreamproxy_p.h>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qfileinfo.h>
+#include <QtQuick/qquickwindow.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Studio3D
+ \instantiates Q3DSStudio3D
+ \inqmlmodule QtStudio3D
+ \ingroup OpenGLRuntime
+ \inherits Item
+ \keyword Studio3D
+
+ \brief Qt 3D Studio presentation viewer.
+
+ This type enables developers to embed Qt 3D Studio presentations in Qt
+ Quick.
+
+ \section2 Example Usage
+
+ \qml
+ Studio3D {
+ id: studio3D
+ anchors.fill: parent
+
+ Presentation {
+ source: "qrc:///presentation.uia"
+ SceneElement {
+ id: scene
+ elementPath: "Scene"
+ currentSlideIndex: 2
+ }
+ Element {
+ id: textLabel
+ elementPath: "Scene.Layer.myLabel"
+ }
+ }
+ ViewerSettings {
+ showRenderStats: true
+ }
+ onRunningChanged: {
+ console.log("Presentation ready!");
+ }
+ }
+ \endqml
+
+ \section2 Controlling the presentation
+
+ Like the example above suggests, Studio3D and the other types under the
+ QtStudio3D import offer more than simply rendering the animated Qt 3D
+ Studio presentation. They also offer scene manipulation, including
+
+ \list
+
+ \li querying and changing scene object properties (for example, the
+ transform of a model, colors and other settings of a material, etc.) via
+ Presentation::getAttribute(), Presentation::setAttribute(), \l Element, and
+ \l DataInput,
+
+ \li changing slides (and thus starting the relevant animations and applying
+ the scene object property changes associated with the new slide) via
+ Presentation::goToSlide(), \l SceneElement, and \l DataInput,
+
+ \li and controlling the timeline (the current playback position for the
+ key-frame based animations) both on the main scene and on individual
+ Component nodes via Presentation::goToTime(), \l SceneElement, and \l DataInput.
+
+ \endlist
+
+ \sa Presentation
+*/
+
+/*!
+ \qmlsignal Studio3D::frameUpdate()
+
+ This signal is emitted each time a frame has been rendered.
+*/
+
+/*!
+ \qmlsignal Studio3D::presentationLoaded()
+
+ This signal is emitted when the presentation has been loaded and is ready
+ to be shown.
+*/
+
+/*!
+ \qmlsignal Studio3D::presentationReady()
+
+ This signal is emitted when the presentation has fully initialized its 3D
+ scene for the first frame.
+
+ The difference to presentationLoaded() is that this signal is emitted only
+ when the asynchronous operations needed to build to 3D scene and the first
+ frame have completed.
+
+ When implementing splash screens via Loader items and the Item::visible
+ property, this is the signal that should be used to trigger hiding the
+ splash screen.
+*/
+
+Q3DSStudio3D::Q3DSStudio3D()
+ : m_viewerSettings(nullptr)
+ , m_presentation(nullptr)
+ , m_emitRunningChange(false)
+ , m_isRunning(false)
+ , m_eventIgnoreFlags(EnableAllEvents)
+ , m_pixelRatio(1.0)
+{
+ setMirrorVertically(true);
+ connect(this, &Q3DSStudio3D::windowChanged, this, &Q3DSStudio3D::handleWindowChanged);
+ connect(this, &Q3DSStudio3D::visibleChanged, this, &Q3DSStudio3D::handleVisibleChanged);
+
+ updateEventMasks();
+}
+
+Q3DSStudio3D::~Q3DSStudio3D()
+{
+}
+
+/*!
+ \qmlproperty Presentation Studio3D::presentation
+
+ Accessor for the presentation. Applications are expected to create a single
+ Presentation child object for Studio3D. If this is omitted, a presentation
+ is created automatically.
+
+ This property is read-only.
+*/
+Q3DSPresentationItem *Q3DSStudio3D::presentation() const
+{
+ return m_presentation;
+}
+
+// #TODO: QT3DS-3566 viewerSettings is missing documentation
+/*!
+ \qmlproperty ViewerSettings Studio3D::viewerSettings
+
+ This property is read-only.
+*/
+Q3DSViewerSettings *Q3DSStudio3D::viewerSettings() const
+{
+ return m_viewerSettings;
+}
+
+/*!
+ \qmlproperty string Studio3D::error
+
+ Contains the text for the error message that was generated during the
+ loading of the presentation. When no error occurred or there is no
+ presentation loaded, the value is an empty string.
+
+ This property is read-only.
+*/
+QString Q3DSStudio3D::error() const
+{
+ return m_error;
+}
+
+void Q3DSStudio3D::setError(const QString &error)
+{
+ if (error != m_error) {
+ m_error = error;
+ Q_EMIT errorChanged(m_error);
+ }
+}
+
+/*!
+ \qmlproperty EventIgnoreFlags Studio3D::ignoredEvents
+
+ This property can be used to ignore mouse/wheel/keyboard events.
+ By default all events are enabled.
+*/
+
+Q3DSStudio3D::EventIgnoreFlags Q3DSStudio3D::ignoredEvents() const
+{
+ return m_eventIgnoreFlags;
+}
+
+void Q3DSStudio3D::setIgnoredEvents(EventIgnoreFlags flags)
+{
+ if (m_eventIgnoreFlags == flags)
+ return;
+
+ m_eventIgnoreFlags = flags;
+ updateEventMasks();
+ Q_EMIT ignoredEventsChanged();
+}
+
+/*!
+ \internal
+ */
+void Q3DSStudio3D::updateEventMasks()
+{
+ if (m_eventIgnoreFlags.testFlag(IgnoreMouseEvents)) {
+ setAcceptedMouseButtons(Qt::NoButton);
+ setAcceptHoverEvents(false);
+ } else {
+ setAcceptedMouseButtons(Qt::MouseButtonMask);
+ setAcceptHoverEvents(true);
+ }
+}
+
+/*!
+ \internal
+ */
+void Q3DSStudio3D::componentComplete()
+{
+ const auto childObjs = children();
+ for (QObject *child : childObjs) {
+ auto settings = qobject_cast<Q3DSViewerSettings *>(child);
+ if (settings) {
+ if (m_viewerSettings)
+ qWarning("Duplicate ViewerSettings defined for Studio3D.");
+ else
+ m_viewerSettings = settings;
+ }
+ auto presentation = qobject_cast<Q3DSPresentationItem *>(child);
+ if (presentation) {
+ if (m_presentation)
+ qWarning("Duplicate Presentation defined for Studio3D.");
+ else
+ m_presentation = presentation;
+ }
+ }
+ if (!m_viewerSettings)
+ m_viewerSettings = new Q3DSViewerSettings(this);
+ if (!m_presentation)
+ m_presentation = new Q3DSPresentationItem(this);
+
+ m_viewerSettings->d_ptr->setCommandQueue(&m_pendingCommands);
+ m_presentation->d_ptr->setCommandQueue(&m_pendingCommands);
+
+ // Ensure qml stream proxy gets created on main thread
+ m_presentation->d_ptr->streamProxy();
+
+ QQuickFramebufferObject::componentComplete();
+}
+
+/*!
+ \internal
+ */
+void Q3DSStudio3D::handleWindowChanged(QQuickWindow *window)
+{
+ if (!window)
+ return;
+
+ window->setClearBeforeRendering(false);
+ m_pixelRatio = window->devicePixelRatio();
+
+ // Call tick every frame of the GUI thread to notify QML about new frame via frameUpdate signal
+ connect(window, &QQuickWindow::afterAnimating, this, &Q3DSStudio3D::tick);
+ // Call update after the frame is handled to queue another frame
+ connect(window, &QQuickWindow::afterSynchronizing, this, &Q3DSStudio3D::update);
+}
+
+/*!
+ \internal
+ Queue up a command to inform the renderer of a newly-changed visible/hidden status.
+ */
+void Q3DSStudio3D::handleVisibleChanged()
+{
+ m_pendingCommands.m_visibleChanged = true;
+ m_pendingCommands.m_visible = isVisible();
+}
+
+/*!
+ \brief internal
+ */
+void Q3DSStudio3D::reset()
+{
+ // Fake a source change to trigger a reloading of the presentation
+ m_pendingCommands.m_sourceChanged = true;
+ m_pendingCommands.m_source = m_presentation->source();
+ m_pendingCommands.m_variantListChanged = true;
+ m_pendingCommands.m_variantList = m_presentation->variantList();
+}
+
+/*!
+ \internal
+ */
+void Q3DSStudio3D::requestResponseHandler(const QString &elementPath, CommandType commandType,
+ void *requestData)
+{
+ switch (commandType) {
+ case CommandType_RequestSlideInfo: {
+ Q3DSSceneElement *handler = qobject_cast<Q3DSSceneElement *>(
+ m_presentation->registeredElement(elementPath));
+ if (handler)
+ handler->d_ptr->requestResponseHandler(commandType, requestData);
+ else
+ qWarning() << __FUNCTION__ << "RequestSlideInfo response got for unregistered scene.";
+ break;
+ }
+ case CommandType_RequestDataInputs: {
+ Q3DSPresentation *handler = qobject_cast<Q3DSPresentation *>(m_presentation);
+ if (handler) {
+ handler->d_ptr->requestResponseHandler(commandType, requestData);
+ } else {
+ qWarning() << __FUNCTION__
+ << "RequestDataInputs response got for invalid presentation.";
+ }
+ break;
+ }
+ case CommandType_RequestDataOutputs: {
+ Q3DSPresentation *handler = qobject_cast<Q3DSPresentation *>(m_presentation);
+ if (handler) {
+ handler->d_ptr->requestResponseHandler(commandType, requestData);
+ } else {
+ qWarning() << __FUNCTION__
+ << "RequestDataOutputs response got for invalid presentation.";
+ }
+ break;
+ }
+ default:
+ qWarning() << __FUNCTION__ << "Unknown command type.";
+ break;
+ }
+}
+
+/*!
+ \internal
+ Create the Q3DSRenderer. Invoked automatically by the QML scene graph.
+ */
+QQuickFramebufferObject::Renderer *Q3DSStudio3D::createRenderer() const
+{
+ // It is "illegal" to create a connection between the renderer
+ // and the plugin, and vice-versa. The only valid time the two
+ // may communicate is during Q3DSRenderer::synchronize().
+ Q3DSRenderer *renderer = new Q3DSRenderer(isVisible(), m_presentation->d_ptr->streamProxy());
+
+ connect(renderer, &Q3DSRenderer::enterSlide,
+ m_presentation->d_ptr, &Q3DSPresentationPrivate::handleSlideEntered);
+ connect(renderer, &Q3DSRenderer::dataOutputValueUpdated,
+ m_presentation->d_ptr, &Q3DSPresentationPrivate::handleDataOutputValueUpdate);
+ connect(renderer, &Q3DSRenderer::exitSlide,
+ m_presentation, &Q3DSPresentation::slideExited);
+ connect(renderer, &Q3DSRenderer::customSignalEmitted,
+ m_presentation, &Q3DSPresentation::customSignalEmitted);
+ connect(renderer, &Q3DSRenderer::elementsCreated,
+ m_presentation, &Q3DSPresentation::elementsCreated);
+ connect(renderer, &Q3DSRenderer::materialsCreated,
+ m_presentation, &Q3DSPresentation::materialsCreated);
+ connect(renderer, &Q3DSRenderer::meshesCreated,
+ m_presentation, &Q3DSPresentation::meshesCreated);
+ connect(renderer, &Q3DSRenderer::requestResponse,
+ this, &Q3DSStudio3D::requestResponseHandler);
+ connect(renderer, &Q3DSRenderer::presentationLoaded,
+ this, &Q3DSStudio3D::presentationLoaded);
+ connect(renderer, &Q3DSRenderer::presentationReady,
+ this, &Q3DSStudio3D::presentationReady);
+ return renderer;
+}
+
+/*!
+ \qmlproperty bool Studio3D::running
+
+ The value of this property is \c true when the presentation has been loaded
+ and is ready to be shown.
+
+ This property is read-only.
+*/
+bool Q3DSStudio3D::isRunning() const
+{
+ return m_isRunning;
+}
+
+/*!
+ \internal
+ Emit QML `runningChanged` and `frameUpdate` and signals.
+ This method is called every frame, and emits the `frameUpdate` signal every frame,
+ regardless of plugin visibility. This allows a hidden Qt3DSView to still process
+ information every frame, even though the Renderer is not rendering.
+
+ To prevent expensive onFrameUpdate handlers from being processed when hidden,
+ add an early return to the top like:
+
+ onFrameUpdate: {
+ if (!visible) return;
+ ...
+ }
+ */
+void Q3DSStudio3D::tick()
+{
+ if (m_emitRunningChange) {
+ m_isRunning = true;
+ Q_EMIT runningChanged(true);
+ m_emitRunningChange = false;
+ }
+
+ // Don't call onFrameUpdate until after onInitialize has been called
+ if (m_isRunning) {
+ // Give QML an opportunity to change Qt3DS values every frame
+ Q_EMIT frameUpdate();
+ }
+}
+
+/*!
+ \internal
+ Copies the list of commands previously queued up. Called by Q3DSRenderer::synchronize().
+ */
+void Q3DSStudio3D::getCommands(bool emitInitialize, CommandQueue &renderQueue)
+{
+ if (emitInitialize)
+ m_emitRunningChange = true;
+
+ renderQueue.copyCommands(m_pendingCommands);
+ m_pendingCommands.clear(false);
+}
+
+/*!
+ \internal
+ */
+void Q3DSStudio3D::mousePressEvent(QMouseEvent *event)
+{
+ if (m_eventIgnoreFlags.testFlag(IgnoreMouseEvents))
+ return;
+
+ if (m_pixelRatio != 1.0) {
+ QMouseEvent scaledEvent(event->type(), event->pos() * m_pixelRatio,
+ event->button(), event->buttons(), event->modifiers());
+ m_presentation->mousePressEvent(&scaledEvent);
+ } else {
+ m_presentation->mousePressEvent(event);
+ }
+}
+
+/*!
+ \internal
+ */
+void Q3DSStudio3D::mouseReleaseEvent(QMouseEvent *event)
+{
+ if (m_eventIgnoreFlags.testFlag(IgnoreMouseEvents))
+ return;
+
+ if (m_pixelRatio != 1.0) {
+ QMouseEvent scaledEvent(event->type(), event->pos() * m_pixelRatio,
+ event->button(), event->buttons(), event->modifiers());
+ m_presentation->mouseReleaseEvent(&scaledEvent);
+ } else {
+ m_presentation->mouseReleaseEvent(event);
+ }
+}
+
+/*!
+ \internal
+ */
+void Q3DSStudio3D::mouseMoveEvent(QMouseEvent *event)
+{
+ if (m_eventIgnoreFlags.testFlag(IgnoreMouseEvents))
+ return;
+
+ if (m_pixelRatio != 1.0) {
+ QMouseEvent scaledEvent(event->type(), event->pos() * m_pixelRatio,
+ event->button(), event->buttons(), event->modifiers());
+ m_presentation->mouseMoveEvent(&scaledEvent);
+ } else {
+ m_presentation->mouseMoveEvent(event);
+ }
+}
+
+/*!
+ \internal
+ */
+void Q3DSStudio3D::wheelEvent(QWheelEvent *event)
+{
+ if (m_eventIgnoreFlags.testFlag(IgnoreWheelEvents))
+ return;
+
+ m_presentation->wheelEvent(event);
+}
+
+/*!
+ \internal
+ */
+void Q3DSStudio3D::keyPressEvent(QKeyEvent *event)
+{
+ if (m_eventIgnoreFlags.testFlag(IgnoreKeyboardEvents))
+ return;
+
+ m_presentation->keyPressEvent(event);
+}
+
+/*!
+ \internal
+ */
+void Q3DSStudio3D::keyReleaseEvent(QKeyEvent *event)
+{
+ if (m_eventIgnoreFlags.testFlag(IgnoreKeyboardEvents))
+ return;
+
+ if (!event->isAutoRepeat())
+ m_presentation->keyReleaseEvent(event);
+}
+
+QT_END_NAMESPACE
diff --git a/src/Runtime/ogl-runtime/src/api/studio3dqml/q3dsstudio3d_p.h b/src/Runtime/ogl-runtime/src/api/studio3dqml/q3dsstudio3d_p.h
new file mode 100644
index 00000000..eed8459a
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3dqml/q3dsstudio3d_p.h
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (c) 2016 NVIDIA CORPORATION.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3DS_STUDIO3D_H
+#define Q3DS_STUDIO3D_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtStudio3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtStudio3D/private/q3dscommandqueue_p.h>
+#include <QtGui/qopenglframebufferobject.h>
+#include <QtQuick/qquickframebufferobject.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q3DSRenderer;
+class Q3DSViewerSettings;
+class Q3DSPresentationItem;
+
+class Q3DSStudio3D : public QQuickFramebufferObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool running READ isRunning NOTIFY runningChanged)
+ Q_PROPERTY(Q3DSPresentationItem *presentation READ presentation CONSTANT)
+ Q_PROPERTY(Q3DSViewerSettings *viewerSettings READ viewerSettings CONSTANT)
+ Q_PROPERTY(QString error READ error NOTIFY errorChanged)
+ Q_PROPERTY(EventIgnoreFlags ignoredEvents READ ignoredEvents WRITE setIgnoredEvents NOTIFY ignoredEventsChanged)
+
+public:
+ enum EventIgnoreFlag {
+ EnableAllEvents = 0,
+ IgnoreMouseEvents = 0x01,
+ IgnoreWheelEvents = 0x02,
+ IgnoreKeyboardEvents = 0x04,
+ IgnoreAllInputEvents = IgnoreMouseEvents | IgnoreWheelEvents | IgnoreKeyboardEvents
+ };
+ Q_DECLARE_FLAGS(EventIgnoreFlags, EventIgnoreFlag)
+ Q_FLAG(EventIgnoreFlags)
+
+ Q3DSStudio3D();
+ ~Q3DSStudio3D() override;
+
+ QQuickFramebufferObject::Renderer *createRenderer() const override;
+
+ bool isRunning() const;
+ Q3DSPresentationItem *presentation() const;
+ Q3DSViewerSettings *viewerSettings() const;
+ QString error() const;
+ void setError(const QString &error);
+
+ void getCommands(bool emitInitialize, CommandQueue &renderQueue);
+
+ void mousePressEvent(QMouseEvent *event) override;
+ void mouseReleaseEvent(QMouseEvent *event) override;
+ void mouseMoveEvent(QMouseEvent *event) override;
+ void wheelEvent(QWheelEvent *event) override;
+ void keyPressEvent(QKeyEvent *event) override;
+ void keyReleaseEvent(QKeyEvent *event) override;
+
+ EventIgnoreFlags ignoredEvents() const;
+ void setIgnoredEvents(EventIgnoreFlags flags);
+
+ void componentComplete() override;
+
+Q_SIGNALS:
+ void frameUpdate();
+ void runningChanged(bool initialized);
+ void errorChanged(const QString &error);
+ void ignoredEventsChanged();
+ void presentationReady();
+ void presentationLoaded();
+
+public Q_SLOTS:
+ void reset();
+
+protected Q_SLOTS:
+ void handleWindowChanged(QQuickWindow *window);
+ void handleVisibleChanged();
+ void tick();
+ void requestResponseHandler(const QString &elementPath, CommandType commandType,
+ void *requestData);
+private:
+ void updateEventMasks();
+
+protected:
+ Q3DSViewerSettings *m_viewerSettings;
+ Q3DSPresentationItem *m_presentation;
+
+ bool m_emitRunningChange;
+ bool m_isRunning;
+ EventIgnoreFlags m_eventIgnoreFlags;
+
+ CommandQueue m_pendingCommands;
+ qreal m_pixelRatio;
+ QString m_error;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(Q3DSStudio3D::EventIgnoreFlags)
+
+QT_END_NAMESPACE
+
+#endif // Q3DS_STUDIO3D_H
diff --git a/src/Runtime/ogl-runtime/src/api/studio3dqml/qmldir b/src/Runtime/ogl-runtime/src/api/studio3dqml/qmldir
new file mode 100644
index 00000000..1eaa8f2b
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3dqml/qmldir
@@ -0,0 +1,3 @@
+module QtStudio3D.OpenGL
+plugin declarative_qtstudio3dopengl
+classname Q3DSPlugin
diff --git a/src/Runtime/ogl-runtime/src/api/studio3dqml/studio3dqml.pro b/src/Runtime/ogl-runtime/src/api/studio3dqml/studio3dqml.pro
new file mode 100644
index 00000000..b62a3424
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/api/studio3dqml/studio3dqml.pro
@@ -0,0 +1,34 @@
+include($$PWD/../../commoninclude.pri)
+
+QT += qml quick opengl studio3d-private
+CONFIG += plugin
+
+qtHaveModule(multimedia) {
+DEFINES += PLATFORM_HAS_QT_MULTIMEDIA_LIB
+QT += multimedia
+}
+
+TARGET = qtstudio3dopengl
+TARGETPATH = QtStudio3D/OpenGL
+IMPORT_VERSION = 2.4
+
+SOURCES += \
+ q3dsplugin.cpp \
+ q3dsstudio3d.cpp \
+ q3dsrenderer.cpp \
+ q3dspresentationitem.cpp
+
+HEADERS += \
+ q3dsplugin.h \
+ q3dsrenderer_p.h \
+ q3dsstudio3d_p.h \
+ q3dspresentationitem_p.h
+
+LIBS += \
+ -lqt3dsopengl$$qtPlatformTargetSuffix() \
+ -lqt3dsqmlstreamer$$qtPlatformTargetSuffix()
+
+OTHER_FILES += \
+ qmldir
+
+load(qml_plugin)