diff options
Diffstat (limited to 'src/Runtime/ogl-runtime/src/api')
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 ¤tSlideName) +{ + 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 ¤tSlideName); + void goToSlide(bool next, bool wrap); + void goToTime(float time); + +Q_SIGNALS: + void currentSlideIndexChanged(int currentSlideIndex); + void previousSlideIndexChanged(int previousSlideIndex); + void currentSlideNameChanged(const QString ¤tSlideName); + 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) |