diff options
Diffstat (limited to 'src/Runtime')
46 files changed, 6383 insertions, 2 deletions
diff --git a/src/Runtime/Qt3DSRuntime/Qt3DSRuntime.pro b/src/Runtime/Qt3DSRuntime/Qt3DSRuntime.pro index ac5a3936..54aa0442 100644 --- a/src/Runtime/Qt3DSRuntime/Qt3DSRuntime.pro +++ b/src/Runtime/Qt3DSRuntime/Qt3DSRuntime.pro @@ -67,7 +67,6 @@ macos { QMAKE_LFLAGS_SONAME = -Wl,-install_name,@rpath/ } - PREDEPS_LIBS = qt3dsruntimestatic include(../../utils.pri) diff --git a/src/Runtime/Runtime.pro b/src/Runtime/Runtime.pro index abc3fe7b..aedfb1ee 100644 --- a/src/Runtime/Runtime.pro +++ b/src/Runtime/Runtime.pro @@ -2,7 +2,8 @@ TEMPLATE = subdirs CONFIG += ordered SUBDIRS += \ Qt3DSRuntimeStatic \ - Qt3DSRuntime + Qt3DSRuntime \ + api win32 { SUBDIRS += \ diff --git a/src/Runtime/api/api.pro b/src/Runtime/api/api.pro new file mode 100644 index 00000000..7d5b27d0 --- /dev/null +++ b/src/Runtime/api/api.pro @@ -0,0 +1,5 @@ +TEMPLATE = subdirs +CONFIG += ordered +SUBDIRS += \ + studio3d \ + studio3dqml diff --git a/src/Runtime/api/studio3d/q3dscommandqueue.cpp b/src/Runtime/api/studio3d/q3dscommandqueue.cpp new file mode 100644 index 00000000..ed0ad8b5 --- /dev/null +++ b/src/Runtime/api/studio3d/q3dscommandqueue.cpp @@ -0,0 +1,303 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "q3dscommandqueue_p.h" +#include "q3dspresentation.h" + +ElementCommand::ElementCommand() + : m_commandType(CommandType_Invalid) +{ +} + +QString ElementCommand::toString() const +{ + QString ret = QStringLiteral("ElementCommand - Type: %1 Path: '%2' StrVal: '%3' VarVal: '%4'"); + return ret.arg(m_commandType).arg(m_elementPath) + .arg(m_stringValue).arg(m_variantValue.toString()); +} + +CommandQueue::CommandQueue() + : m_visibleChanged(false) + , m_scaleModeChanged(false) + , m_shadeModeChanged(false) + , m_showRenderStatsChanged(false) + , m_matteColorChanged(false) + , m_sourceChanged(false) + , m_variantListChanged(false) + , m_globalAnimationTimeChanged(false) + , m_delayedLoadingChanged(false) + , m_visible(false) + , m_scaleMode(Q3DSViewerSettings::ScaleModeCenter) + , m_shadeMode(Q3DSViewerSettings::ShadeModeShaded) + , m_showRenderStats(false) + , m_matteColor(Qt::black) + , m_delayedLoading(false) + , m_size(0) +{ + qRegisterMetaType<CommandType>(); +} + +ElementCommand &CommandQueue::queueCommand(const QString &elementPath, + CommandType commandType, + const QString &attributeName, + const QVariant &value) +{ + ElementCommand &cmd = nextFreeCommand(); + + cmd.m_commandType = commandType; + cmd.m_elementPath = elementPath; + cmd.m_stringValue = attributeName; + cmd.m_variantValue = value; + + return cmd; +} + +ElementCommand &CommandQueue::queueCommand(const QString &elementPath, + CommandType commandType, + const QString &attributeName, + const QVariant &value, + int intValue) +{ + ElementCommand &cmd = nextFreeCommand(); + + cmd.m_commandType = commandType; + cmd.m_elementPath = elementPath; + cmd.m_stringValue = attributeName; + cmd.m_variantValue = value; + cmd.m_intValues[0] = intValue; + + return cmd; +} + +ElementCommand &CommandQueue::queueCommand(const QString &elementPath, CommandType commandType, + const QString &value) +{ + ElementCommand &cmd = nextFreeCommand(); + + cmd.m_commandType = commandType; + cmd.m_elementPath = elementPath; + cmd.m_stringValue = value; + + return cmd; +} + +ElementCommand &CommandQueue::queueCommand(const QString &elementPath, + CommandType commandType, bool value) +{ + ElementCommand &cmd = nextFreeCommand(); + + cmd.m_commandType = commandType; + cmd.m_elementPath = elementPath; + cmd.m_boolValue = value; + + return cmd; +} + +ElementCommand &CommandQueue::queueCommand(const QString &elementPath, + CommandType commandType, float value) +{ + ElementCommand &cmd = nextFreeCommand(); + + cmd.m_commandType = commandType; + cmd.m_elementPath = elementPath; + cmd.m_floatValue = value; + + return cmd; +} + +ElementCommand &CommandQueue::queueCommand(const QString &elementPath, + CommandType commandType, int value0, int value1, + int value2, int value3) +{ + ElementCommand &cmd = nextFreeCommand(); + + cmd.m_commandType = commandType; + cmd.m_elementPath = elementPath; + cmd.m_intValues[0] = value0; + cmd.m_intValues[1] = value1; + cmd.m_intValues[2] = value2; + cmd.m_intValues[3] = value3; + + return cmd; +} + +ElementCommand &CommandQueue::queueCommand(const QString &elementPath, CommandType commandType, + const QString &stringValue, void *commandData) +{ + ElementCommand &cmd = nextFreeCommand(); + + cmd.m_commandType = commandType; + cmd.m_elementPath = elementPath; + cmd.m_stringValue = stringValue; + cmd.m_data = commandData; + + return cmd; +} + +ElementCommand &CommandQueue::queueCommand(const QString &elementPath, CommandType commandType) +{ + ElementCommand &cmd = nextFreeCommand(); + + cmd.m_commandType = commandType; + cmd.m_elementPath = elementPath; + + return cmd; +} + +void CommandQueue::copyCommands(CommandQueue &fromQueue) +{ + m_visibleChanged = m_visibleChanged || fromQueue.m_visibleChanged; + m_scaleModeChanged = m_scaleModeChanged || fromQueue.m_scaleModeChanged; + m_shadeModeChanged = m_shadeModeChanged || fromQueue.m_shadeModeChanged; + m_showRenderStatsChanged = m_showRenderStatsChanged || fromQueue.m_showRenderStatsChanged; + m_matteColorChanged = m_matteColorChanged || fromQueue.m_matteColorChanged; + m_sourceChanged = m_sourceChanged || fromQueue.m_sourceChanged; + m_variantListChanged = m_variantListChanged || fromQueue.m_variantListChanged; + m_globalAnimationTimeChanged + = m_globalAnimationTimeChanged || fromQueue.m_globalAnimationTimeChanged; + m_delayedLoadingChanged = m_delayedLoadingChanged || fromQueue.m_delayedLoadingChanged; + + if (fromQueue.m_visibleChanged) + m_visible = fromQueue.m_visible; + if (fromQueue.m_scaleModeChanged) + m_scaleMode = fromQueue.m_scaleMode; + if (fromQueue.m_shadeModeChanged) + m_shadeMode = fromQueue.m_shadeMode; + if (fromQueue.m_showRenderStatsChanged) + m_showRenderStats = fromQueue.m_showRenderStats; + if (fromQueue.m_matteColorChanged) + m_matteColor = fromQueue.m_matteColor; + if (fromQueue.m_sourceChanged) + m_source = fromQueue.m_source; + if (fromQueue.m_variantListChanged) + m_variantList = fromQueue.m_variantList; + if (fromQueue.m_globalAnimationTimeChanged) + m_globalAnimationTime = fromQueue.m_globalAnimationTime; + if (fromQueue.m_delayedLoadingChanged) + m_delayedLoading = fromQueue.m_delayedLoading; + + // Pending queue may be synchronized multiple times between queue processing, so let's append + // to the existing queue rather than clearing it. + for (int i = 0; i < fromQueue.m_size; i++) { + const ElementCommand &source = fromQueue.constCommandAt(i); + switch (source.m_commandType) { + case CommandType_SetDataInputValue: + queueCommand(source.m_elementPath, source.m_commandType, source.m_stringValue, + source.m_variantValue, source.m_intValues[0]); + break; + case CommandType_SetAttribute: + queueCommand(source.m_elementPath, source.m_commandType, source.m_stringValue, + source.m_variantValue); + break; + case CommandType_GoToSlideByName: + case CommandType_FireEvent: + case CommandType_CreateMaterial: + queueCommand(source.m_elementPath, source.m_commandType, source.m_stringValue); + break; + case CommandType_SetPresentationActive: + queueCommand(source.m_elementPath, source.m_commandType, + source.m_boolValue); + break; + case CommandType_GoToTime: + queueCommand(source.m_elementPath, source.m_commandType, + source.m_floatValue); + break; + case CommandType_GoToSlide: + case CommandType_GoToSlideRelative: + case CommandType_MousePress: + case CommandType_MouseRelease: + case CommandType_MouseMove: + case CommandType_MouseWheel: + case CommandType_KeyPress: + case CommandType_KeyRelease: + queueCommand(source.m_elementPath, source.m_commandType, + source.m_intValues[0], source.m_intValues[1], + source.m_intValues[2], source.m_intValues[3]); + break; + case CommandType_CreateElement: + queueCommand(source.m_elementPath, source.m_commandType, source.m_stringValue, + source.m_data); + fromQueue.commandAt(i).m_data = nullptr; // This queue takes ownership of data + break; + case CommandType_DeleteElement: + case CommandType_RequestSlideInfo: + case CommandType_UnloadSlide: + case CommandType_PreloadSlide: + case CommandType_RequestDataInputs: + queueCommand(source.m_elementPath, source.m_commandType); + break; + default: + queueCommand(QString(), CommandType_Invalid, false); + break; + } + } +} + +// Clears changed states and empties the queue +void CommandQueue::clear(bool deleteCommandData) +{ + m_visibleChanged = false; + m_scaleModeChanged = false; + m_shadeModeChanged = false; + m_showRenderStatsChanged = false; + m_matteColorChanged = false; + m_sourceChanged = false; + m_variantListChanged = false; + m_globalAnimationTimeChanged = false; + m_delayedLoadingChanged = false; + + if (deleteCommandData) { + for (int i = 0; i < m_size; ++i) { + ElementCommand &cmd = m_elementCommands[i]; + if (cmd.m_data) { + switch (cmd.m_commandType) { + case CommandType_CreateElement: + delete static_cast<QHash<QString, QVariant> *>(cmd.m_data); + break; + default: + Q_ASSERT(false); // Should never come here + break; + } + cmd.m_data = nullptr; + } + } + } + + // We do not clear the actual queued commands, those will be reused the next frame + // To avoid a lot of unnecessary reallocations. + m_size = 0; +} + +ElementCommand &CommandQueue::nextFreeCommand() +{ + m_size++; + if (m_size > m_elementCommands.size()) + m_elementCommands.append(ElementCommand()); + return m_elementCommands[m_size - 1]; +} diff --git a/src/Runtime/api/studio3d/q3dscommandqueue_p.h b/src/Runtime/api/studio3d/q3dscommandqueue_p.h new file mode 100644 index 00000000..ff30829f --- /dev/null +++ b/src/Runtime/api/studio3d/q3dscommandqueue_p.h @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef Q3DS_COMMAND_QUEUE_H +#define Q3DS_COMMAND_QUEUE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtStudio3D API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "q3dsviewersettings.h" + +#include <QtGui/qcolor.h> +#include <QtCore/qsize.h> +#include <QtCore/qvector.h> +#include <QtCore/qurl.h> +#include <QtCore/qvariant.h> + +QT_BEGIN_NAMESPACE + +enum CommandType { + CommandType_Invalid = 0, + CommandType_SetAttribute, + CommandType_SetPresentationActive, + CommandType_GoToSlideByName, + CommandType_GoToSlide, + CommandType_GoToSlideRelative, + CommandType_GoToTime, + CommandType_FireEvent, + CommandType_MousePress, + CommandType_MouseRelease, + CommandType_MouseMove, + CommandType_MouseWheel, + CommandType_KeyPress, + CommandType_KeyRelease, + CommandType_SetGlobalAnimationTime, + CommandType_SetDataInputValue, + CommandType_CreateElement, + CommandType_DeleteElement, + CommandType_CreateMaterial, + + // Requests + CommandType_RequestSlideInfo, + CommandType_RequestDataInputs, + CommandType_PreloadSlide, + CommandType_UnloadSlide +}; + +class Q_STUDIO3D_EXPORT ElementCommand +{ +public: + ElementCommand(); + + CommandType m_commandType; + QString m_elementPath; + QString m_stringValue; + QVariant m_variantValue; + void *m_data = nullptr; // Data is owned by the queue and is deleted once command is handled + union { + bool m_boolValue; + float m_floatValue; + int m_intValues[4]; + qint64 m_int64Value; + }; + + QString toString() const; +}; + +typedef QVector<ElementCommand> CommandList; + +class Q_STUDIO3D_EXPORT CommandQueue +{ +public: + CommandQueue(); + + ElementCommand &queueCommand(const QString &elementPath, CommandType commandType, + const QString &attributeName, const QVariant &value); + ElementCommand &queueCommand(const QString &elementPath, CommandType commandType, + const QString &attributeName, const QVariant &value, + int intValue); + ElementCommand &queueCommand(const QString &elementPath, CommandType commandType, + const QString &value); + ElementCommand &queueCommand(const QString &elementPath, CommandType commandType, + bool value); + ElementCommand &queueCommand(const QString &elementPath, CommandType commandType, + float value); + ElementCommand &queueCommand(const QString &elementPath, CommandType commandType, + int value0, int value1 = 0, + int value2 = 0, int value3 = 0); + ElementCommand &queueCommand(const QString &elementPath, CommandType commandType, + const QString &stringValue, void *commandData); + ElementCommand &queueCommand(const QString &elementPath, CommandType commandType); + + void copyCommands(CommandQueue &fromQueue); + + bool m_visibleChanged; + bool m_scaleModeChanged; + bool m_shadeModeChanged; + bool m_showRenderStatsChanged; + bool m_matteColorChanged; + bool m_sourceChanged; + bool m_variantListChanged; + bool m_globalAnimationTimeChanged; + bool m_delayedLoadingChanged; + + bool m_visible; + Q3DSViewerSettings::ScaleMode m_scaleMode; + Q3DSViewerSettings::ShadeMode m_shadeMode; + bool m_showRenderStats; + QColor m_matteColor; + QUrl m_source; + QStringList m_variantList; + qint64 m_globalAnimationTime; + bool m_delayedLoading; + + void clear(bool deleteCommandData); + int size() const { return m_size; } + const ElementCommand &constCommandAt(int index) const { return m_elementCommands.at(index); } + ElementCommand &commandAt(int index) { return m_elementCommands[index]; } + +private: + ElementCommand &nextFreeCommand(); + + CommandList m_elementCommands; + int m_size; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(CommandType) + +#endif // Q3DS_COMMAND_QUEUE_H diff --git a/src/Runtime/api/studio3d/q3dsdatainput.cpp b/src/Runtime/api/studio3d/q3dsdatainput.cpp new file mode 100644 index 00000000..3048613e --- /dev/null +++ b/src/Runtime/api/studio3d/q3dsdatainput.cpp @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "q3dsdatainput_p.h" +#include "q3dspresentation_p.h" +#include "q3dscommandqueue_p.h" + +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +Q3DSDataInput::Q3DSDataInput(QObject *parent) + : QObject(parent) + , d_ptr(new Q3DSDataInputPrivate(this)) +{ +} + +Q3DSDataInput::Q3DSDataInput(const QString &name, QObject *parent) + : QObject(parent) + , d_ptr(new Q3DSDataInputPrivate(this)) +{ + d_ptr->m_name = name; +} + +Q3DSDataInput::Q3DSDataInput(Q3DSPresentation *presentation, const QString &name, QObject *parent) + : QObject(parent) + , d_ptr(new Q3DSDataInputPrivate(this)) +{ + d_ptr->m_name = name; + d_ptr->m_presentation = presentation; + if (presentation) + presentation->registerDataInput(this); +} + +Q3DSDataInput::Q3DSDataInput(Q3DSDataInputPrivate *d, Q3DSPresentation *presentation, + const QString &name, QObject *parent) + : QObject(parent) + , d_ptr(d) +{ + d_ptr->m_name = name; + d_ptr->m_presentation = presentation; + if (presentation) + presentation->registerDataInput(this); +} + +Q3DSDataInput::~Q3DSDataInput() +{ + delete d_ptr; +} + +QString Q3DSDataInput::name() const +{ + return d_ptr->m_name; +} + +void Q3DSDataInput::setName(const QString &name) +{ + if (d_ptr->m_name != name) { + d_ptr->m_name = name; + if (d_ptr->m_presentation) + d_ptr->m_presentation->registerDataInput(this); + Q_EMIT nameChanged(); + } +} + +QVariant Q3DSDataInput::value() const +{ + return d_ptr->m_value; +} + +// TODO: Min and Max are not currently exposed to QML, as implementation requires +// cumbersome traversal over command queue from QML viewer to renderer. +float Q3DSDataInput::min() const +{ + if (d_ptr->m_presentation) + return 0.0f; + + return d_ptr->m_presentation->d_ptr->dataInputMin(d_ptr->m_name); +} + +float Q3DSDataInput::max() const +{ + if (d_ptr->m_presentation) + return 0.0f; + + return d_ptr->m_presentation->d_ptr->dataInputMax(d_ptr->m_name); +} + +bool Q3DSDataInput::isValid() const +{ + if (d_ptr->m_presentation) + return d_ptr->m_presentation->d_ptr->isValidDataInput(this); + else + return false; +} + +void Q3DSDataInput::setMin(float min) +{ + d_ptr->m_presentation->setDataInputValue(d_ptr->m_name, min, ValueRole::Min); + emit minChanged(); +} + +void Q3DSDataInput::setMax(float max) +{ + d_ptr->m_presentation->setDataInputValue(d_ptr->m_name, max, ValueRole::Max); + emit maxChanged(); +} + +void Q3DSDataInput::setValue(const QVariant &value) +{ + // Since properties controlled by data inputs can change without the current value being + // reflected on the value of the DataInput element, we allow setting the value to the + // same one it was previously and still consider it a change. + // For example, when controlling timeline, the value set to DataInput will only be + // the current value for one frame if presentation has a running animation. + d_ptr->setValue(value, ValueRole::Value); + Q_EMIT valueChanged(); +} + +void Q3DSDataInputPrivate::setPresentation(Q3DSPresentation *presentation) +{ + m_presentation = presentation; +} + +Q3DSDataInputPrivate::Q3DSDataInputPrivate(Q3DSDataInput *parent) + : q_ptr(parent) +{ +} + +Q3DSDataInputPrivate::~Q3DSDataInputPrivate() +{ + if (m_presentation) + m_presentation->unregisterDataInput(q_ptr); +} + +void Q3DSDataInputPrivate::setValue(const QVariant &value, Q3DSDataInput::ValueRole valueRole) +{ + m_value = value; + if (m_presentation) + m_presentation->setDataInputValue(m_name, m_value, valueRole); +} + +void Q3DSDataInputPrivate::setViewerApp(Q3DSViewer::Q3DSViewerApp *app) +{ + m_viewerApp = app; + + if (m_viewerApp && m_value.isValid()) + setValue(m_value); +} + +void Q3DSDataInputPrivate::setCommandQueue(CommandQueue *queue) +{ + m_commandQueue = queue; + + if (m_commandQueue && m_value.isValid()) + setValue(m_value); +} + +QT_END_NAMESPACE diff --git a/src/Runtime/api/studio3d/q3dsdatainput.h b/src/Runtime/api/studio3d/q3dsdatainput.h new file mode 100644 index 00000000..fc5933fa --- /dev/null +++ b/src/Runtime/api/studio3d/q3dsdatainput.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef Q3DSDATAINPUT_H +#define Q3DSDATAINPUT_H + +#include <QtStudio3D/qstudio3dglobal.h> +#include <QtCore/qobject.h> +#include <QtCore/qvariant.h> + +QT_BEGIN_NAMESPACE + +class Q3DSDataInputPrivate; +class Q3DSPresentation; + +class Q_STUDIO3D_EXPORT Q3DSDataInput : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(Q3DSDataInput) + + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged) + // TODO: QML-side getter/setter for min and max + // Q_PROPERTY(float max READ max WRITE setMax NOTIFY maxChanged) + // Q_PROPERTY(float min READ min WRITE setMin NOTIFY minChanged) +public: + explicit Q3DSDataInput(QObject *parent = nullptr); + explicit Q3DSDataInput(const QString &name, QObject *parent = nullptr); + explicit Q3DSDataInput(Q3DSPresentation *presentation, const QString &name, + QObject *parent = nullptr); + + virtual ~Q3DSDataInput(); + + enum class ValueRole { + Value = 0, + Min = 1, + Max = 2 + }; + + QString name() const; + QVariant value() const; + float min() const; + float max() const; + bool isValid() const; + +public Q_SLOTS: + void setName(const QString &name); + void setValue(const QVariant &value); + void setMin(float min); + void setMax(float max); + +Q_SIGNALS: + void nameChanged(); + void valueChanged(); + void minChanged(); + void maxChanged(); + +protected: + explicit Q3DSDataInput(Q3DSDataInputPrivate *d, Q3DSPresentation *presentation, + const QString &name, QObject *parent = nullptr); + Q3DSDataInputPrivate *d_ptr; + +private: + Q_DISABLE_COPY(Q3DSDataInput) + friend class Q3DSPresentationPrivate; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(Q3DSDataInput*) + +#endif // Q3DSDATAINPUT_H diff --git a/src/Runtime/api/studio3d/q3dsdatainput_p.h b/src/Runtime/api/studio3d/q3dsdatainput_p.h new file mode 100644 index 00000000..855406cd --- /dev/null +++ b/src/Runtime/api/studio3d/q3dsdatainput_p.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef Q3DSDATAINPUT_P_P_H +#define Q3DSDATAINPUT_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtStudio3D API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "q3dsdatainput.h" +#include "q3dscommandqueue_p.h" +#include "Qt3DSViewerApp.h" + +QT_BEGIN_NAMESPACE + +class Q3DSPresentationPrivate; + +class Q_STUDIO3D_EXPORT Q3DSDataInputPrivate +{ + Q_DECLARE_PUBLIC(Q3DSDataInput) +public: + explicit Q3DSDataInputPrivate(Q3DSDataInput *parent); + virtual ~Q3DSDataInputPrivate(); + + void setValue(const QVariant &value, + Q3DSDataInput::ValueRole valueRole = Q3DSDataInput::ValueRole::Value); + void setViewerApp(Q3DSViewer::Q3DSViewerApp *app); + void setCommandQueue(CommandQueue *queue); + void setPresentation(Q3DSPresentation *presentation); + +protected: + Q3DSDataInput *q_ptr; + Q3DSViewer::Q3DSViewerApp *m_viewerApp = nullptr; // Not owned + CommandQueue *m_commandQueue = nullptr; // Not owned + Q3DSPresentation *m_presentation = nullptr; // Not owned + QString m_name; + QVariant m_value; +}; + +QT_END_NAMESPACE + +#endif // Q3DSDATAINPUT_P_P_H diff --git a/src/Runtime/api/studio3d/q3dselement.cpp b/src/Runtime/api/studio3d/q3dselement.cpp new file mode 100644 index 00000000..ac3221dd --- /dev/null +++ b/src/Runtime/api/studio3d/q3dselement.cpp @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "q3dselement_p.h" +#include "q3dspresentation_p.h" +#include "q3dscommandqueue_p.h" + +#include <QtCore/qdebug.h> +#include <QtCore/qsettings.h> +#include <QtCore/qcoreapplication.h> + +QT_BEGIN_NAMESPACE + +Q3DSElement::Q3DSElement(QObject *parent) + : QObject(parent) + , d_ptr(new Q3DSElementPrivate(this)) +{ +} + +Q3DSElement::Q3DSElement(const QString &elementPath, QObject *parent) + : QObject(parent) + , d_ptr(new Q3DSElementPrivate(this)) +{ + d_ptr->m_elementPath = elementPath; +} + +Q3DSElement::Q3DSElement(Q3DSPresentation *presentation, const QString &elementPath, + QObject *parent) + : QObject(parent) + , d_ptr(new Q3DSElementPrivate(this)) +{ + d_ptr->m_elementPath = elementPath; + if (presentation) + presentation->registerElement(this); +} + +Q3DSElement::Q3DSElement(Q3DSElementPrivate *d, Q3DSPresentation *presentation, + const QString &elementPath, QObject *parent) + : QObject(parent) + , d_ptr(d) +{ + d_ptr->m_elementPath = elementPath; + if (presentation) + presentation->registerElement(this); +} + +Q3DSElement::~Q3DSElement() +{ + // Private class isn't QObject, so we need to delete it explicitly + delete d_ptr; +} + +QString Q3DSElement::elementPath() const +{ + return d_ptr->m_elementPath; +} + +void Q3DSElement::setElementPath(const QString &elementPath) +{ + if (d_ptr->m_elementPath != elementPath) { + d_ptr->setElementPath(elementPath); + Q_EMIT elementPathChanged(d_ptr->m_elementPath); + } +} + +void Q3DSElement::setAttribute(const QString &attributeName, const QVariant &value) +{ + if (d_ptr->m_presentation) + d_ptr->m_presentation->q_ptr->setAttribute(d_ptr->m_elementPath, attributeName, value); + else + qWarning() << __FUNCTION__ << "Element is not registered to any presentation!"; +} + +void Q3DSElement::fireEvent(const QString &eventName) +{ + if (d_ptr->m_presentation) + d_ptr->m_presentation->q_ptr->fireEvent(d_ptr->m_elementPath, eventName); + else + qWarning() << __FUNCTION__ << "Element is not registered to any presentation!"; +} + +Q3DSElementPrivate::Q3DSElementPrivate(Q3DSElement *parent) + : q_ptr(parent) + , m_viewerApp(nullptr) + , m_commandQueue(nullptr) + , m_presentation(nullptr) +{ +} + +Q3DSElementPrivate::~Q3DSElementPrivate() +{ + if (m_presentation) + m_presentation->unregisterElement(q_ptr); +} + +void Q3DSElementPrivate::setElementPath(const QString &elementPath) +{ + m_elementPath = elementPath; + + if (m_presentation) + m_presentation->registerElement(q_ptr); +} + +void Q3DSElementPrivate::setViewerApp(Q3DSViewer::Q3DSViewerApp *app) +{ + m_viewerApp = app; +} + +void Q3DSElementPrivate::setCommandQueue(CommandQueue *queue) +{ + m_commandQueue = queue; +} + +void Q3DSElementPrivate::setPresentation(Q3DSPresentationPrivate *presentation) +{ + m_presentation = presentation; +} + +void Q3DSElementPrivate::requestResponseHandler(CommandType commandType, void *requestData) +{ + Q_UNUSED(commandType) + Q_UNUSED(requestData) + + // Base element doesn't handle any request command types yet + qWarning() << __FUNCTION__ << "Unknown command type."; +} + +QT_END_NAMESPACE diff --git a/src/Runtime/api/studio3d/q3dselement.h b/src/Runtime/api/studio3d/q3dselement.h new file mode 100644 index 00000000..04c43f52 --- /dev/null +++ b/src/Runtime/api/studio3d/q3dselement.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef Q3DSELEMENT_H +#define Q3DSELEMENT_H + +#include <QtStudio3D/qstudio3dglobal.h> +#include <QtCore/qobject.h> + +QT_BEGIN_NAMESPACE + +class Q3DSElementPrivate; +class Q3DSPresentation; + +class Q_STUDIO3D_EXPORT Q3DSElement : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(Q3DSElement) + + Q_PROPERTY(QString elementPath READ elementPath WRITE setElementPath NOTIFY elementPathChanged) + +public: + explicit Q3DSElement(QObject *parent = nullptr); + explicit Q3DSElement(const QString &elementPath, QObject *parent = nullptr); + explicit Q3DSElement(Q3DSPresentation *presentation, const QString &elementPath, + QObject *parent = nullptr); + virtual ~Q3DSElement(); + + QString elementPath() const; + +public Q_SLOTS: + void setElementPath(const QString &elementPath); + void setAttribute(const QString &attributeName, const QVariant &value); + void fireEvent(const QString &eventName); + +Q_SIGNALS: + void elementPathChanged(const QString &elementPath); + +protected: + explicit Q3DSElement(Q3DSElementPrivate *d, Q3DSPresentation *presentation, + const QString &elementPath, QObject *parent = nullptr); + Q3DSElementPrivate *d_ptr; + +private: + Q_DISABLE_COPY(Q3DSElement) + + friend class Q3DSPresentationPrivate; + friend class Q3DSStudio3D; +}; + +QT_END_NAMESPACE + +#endif // Q3DSELEMENT_H diff --git a/src/Runtime/api/studio3d/q3dselement_p.h b/src/Runtime/api/studio3d/q3dselement_p.h new file mode 100644 index 00000000..d4e77b1c --- /dev/null +++ b/src/Runtime/api/studio3d/q3dselement_p.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef Q3DSSCENE_P_H +#define Q3DSSCENE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtStudio3D API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "q3dselement.h" +#include "q3dscommandqueue_p.h" +#include "Qt3DSViewerApp.h" + +QT_BEGIN_NAMESPACE + +class Q3DSPresentationPrivate; + +class Q_STUDIO3D_EXPORT Q3DSElementPrivate +{ + Q_DECLARE_PUBLIC(Q3DSElement) +public: + explicit Q3DSElementPrivate(Q3DSElement *parent); + virtual ~Q3DSElementPrivate(); + + void setElementPath(const QString &elementPath); + + virtual void setViewerApp(Q3DSViewer::Q3DSViewerApp *app); + virtual void setCommandQueue(CommandQueue *queue); + virtual void setPresentation(Q3DSPresentationPrivate *presentation); + + virtual void requestResponseHandler(CommandType commandType, void *requestData); + +protected: + Q3DSElement *q_ptr; + Q3DSViewer::Q3DSViewerApp *m_viewerApp; // Not owned + CommandQueue *m_commandQueue; // Not owned + Q3DSPresentationPrivate *m_presentation; // Not owned + QString m_elementPath; +}; + +QT_END_NAMESPACE + +#endif // Q3DSSCENE_P_H diff --git a/src/Runtime/api/studio3d/q3dsimagesequencegenerator.cpp b/src/Runtime/api/studio3d/q3dsimagesequencegenerator.cpp new file mode 100644 index 00000000..d0b8251b --- /dev/null +++ b/src/Runtime/api/studio3d/q3dsimagesequencegenerator.cpp @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "q3dsimagesequencegenerator_p.h" +#include "q3dsimagesequencegeneratorthread_p.h" + +#ifndef Q_OS_ANDROID +bool Q3DSImageSequenceGenerator::generateImageSequence( + const QString &presentation, qreal start, qreal end, qreal fps, qreal frameInterval, + int width, int height, const QString &outPath, const QString &outFile) +{ + Q3DSImageSequenceGeneratorThread *thread = new Q3DSImageSequenceGeneratorThread; + + connect(thread, &Q3DSImageSequenceGeneratorThread::generationFinished, + this, &Q3DSImageSequenceGenerator::finished); + + bool success = thread->initialize(presentation, start, end, fps, frameInterval, width, height, + outPath, outFile); + + if (success) { + connect(thread, &Q3DSImageSequenceGeneratorThread::progress, + this, &Q3DSImageSequenceGenerator::progress); + thread->start(); + } else { + delete thread; + } + + return success; +} +#endif diff --git a/src/Runtime/api/studio3d/q3dsimagesequencegenerator_p.h b/src/Runtime/api/studio3d/q3dsimagesequencegenerator_p.h new file mode 100644 index 00000000..bc56fb1e --- /dev/null +++ b/src/Runtime/api/studio3d/q3dsimagesequencegenerator_p.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef Q3DSIMAGE_SEQUENCE_GENERATOR_H +#define Q3DSIMAGE_SEQUENCE_GENERATOR_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtStudio3D API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtStudio3D/qstudio3dglobal.h> +#include <QtCore/qobject.h> +#ifndef Q_OS_ANDROID +QT_BEGIN_NAMESPACE + +class Q_STUDIO3D_EXPORT Q3DSImageSequenceGenerator : public QObject +{ + Q_OBJECT +public: + Q3DSImageSequenceGenerator() {} + virtual ~Q3DSImageSequenceGenerator() {} + + bool generateImageSequence(const QString &presentation, qreal start, qreal end, + qreal fps, qreal frameInterval, int width, int height, + const QString &outPath, const QString &outFile); +Q_SIGNALS: + void progress(int totalFrames, int frameNumber); + void finished(bool success, const QString &details); +}; + +QT_END_NAMESPACE + +#endif // Q3DSIMAGE_SEQUENCE_GENERATOR_H +#endif diff --git a/src/Runtime/api/studio3d/q3dsimagesequencegeneratorthread.cpp b/src/Runtime/api/studio3d/q3dsimagesequencegeneratorthread.cpp new file mode 100644 index 00000000..40bb95b9 --- /dev/null +++ b/src/Runtime/api/studio3d/q3dsimagesequencegeneratorthread.cpp @@ -0,0 +1,190 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "q3dsimagesequencegeneratorthread_p.h" +#include "q3dssurfaceviewer.h" +#include "q3dspresentation.h" +#include "q3dsviewersettings.h" + +#include <QtGui/qopenglcontext.h> +#include <QtGui/qopenglfunctions.h> +#include <QtGui/qoffscreensurface.h> +#include <QtGui/qopenglframebufferobject.h> +#include <QtCore/qfileinfo.h> +#include <QtCore/qdir.h> +#include <QtCore/qdebug.h> +#include <QtCore/qmath.h> + +bool Q3DSImageSequenceGeneratorThread::initialize( + const QString &presentation, qreal start, qreal end, qreal fps, qreal frameInterval, + int width, int height, const QString &outPath, const QString &outFile) +{ + QFileInfo fileInfo(presentation); + if (!fileInfo.exists()) { + QString error = QObject::tr("File not found: '%1'").arg(presentation); + qWarning() << "Generating image sequence failed -" << error; + Q_EMIT generationFinished(false, error); + return false; + } + + m_outputFileName = QStringLiteral("%2/%1_%3.png"); + if (outFile.isEmpty()) { + m_outputFileName = m_outputFileName.arg(fileInfo.baseName()) + .arg(outPath).arg(QStringLiteral("%1")); + } else { + m_outputFileName = m_outputFileName.arg(outFile).arg(outPath).arg(QStringLiteral("%1")); + } + + m_sourceUrl = QUrl::fromLocalFile(fileInfo.absoluteFilePath()); + + QSurfaceFormat format; + format.setDepthBufferSize(24); + format.setStencilBufferSize(8); + + m_context = new QOpenGLContext; + m_context->setFormat(format); + if (!m_context->create()) { + QString error = QObject::tr("Failed to create context"); + qWarning() << "Generating image sequence failed -" << error; + Q_EMIT generationFinished(false, error); + return false; + } + + m_surface = new QOffscreenSurface; + m_surface->setFormat(m_context->format()); + m_surface->create(); + + m_mainThread = QThread::currentThread(); + m_surface->moveToThread(this); + m_context->moveToThread(this); + + m_start = start; + m_end = end; + m_fps = fps; + m_frameInterval = frameInterval; + m_width = width; + m_height = height; + + return true; +} + +Q3DSImageSequenceGeneratorThread::Q3DSImageSequenceGeneratorThread() + : m_start(0) + , m_end(10000) + , m_fps(60) + , m_frameInterval(16.666667) + , m_width(1920) + , m_height(1080) + , m_surface(nullptr) + , m_context(nullptr) +{ +} + +Q3DSImageSequenceGeneratorThread::~Q3DSImageSequenceGeneratorThread() { + delete m_context; + delete m_surface; +} + +void Q3DSImageSequenceGeneratorThread::run() { + if (!m_context->makeCurrent(m_surface)) { + QString error = QObject::tr("Couldn't make context current."); + qWarning() << "Generating image sequence failed -" << error; + Q_EMIT generationFinished(false, error); + cleanup(); + return; + } + + const QSize size(m_width, m_height); + QOpenGLFramebufferObject fbo(size, QOpenGLFramebufferObject::CombinedDepthStencil); + + Q3DSSurfaceViewer viewer; + viewer.presentation()->setSource(m_sourceUrl); + viewer.settings()->setScaleMode(Q3DSViewerSettings::ScaleModeFill); + + viewer.setUpdateInterval(-1); + viewer.setAutoSize(false); + viewer.setSize(size); + + if (!viewer.initialize(m_surface, m_context, fbo.handle())) { + QString error = QObject::tr("Viewer initialization failed."); + qWarning() << "Generating image sequence failed -" << error; + Q_EMIT generationFinished(false, error); + cleanup(); + return; + } + + if (m_frameInterval <= 0) + m_frameInterval = 1000.0 / m_fps; + + // Presentations always assume you want to start animating at time zero and set a local + // offset to global time when they render the first frame. This means we need to always + // render a frame at global time zero first. + if (qRound(m_start) != 0) { + viewer.presentation()->setGlobalAnimationTime(0); + viewer.update(); + } + + // Add a bit of time to the end time to ensure we don't lose the last frame to rounding errors + m_end += m_frameInterval / 10000.0; + + // Ensure directory exists + QFileInfo fi(m_outputFileName); + QDir dir = fi.absoluteDir(); + dir.mkpath("."); + + int frameCount = 0; + int totalFrames = qCeil((m_end - m_start) / m_frameInterval); + for (qreal t = m_start; t <= m_end; t += m_frameInterval) { + ++frameCount; + viewer.presentation()->setGlobalAnimationTime(qRound64(t)); + viewer.update(); + if (!fbo.toImage().save(m_outputFileName.arg(frameCount))) { + QString error = QObject::tr("Failed to write output file: '%1'") + .arg(m_outputFileName.arg(frameCount)); + qWarning() << "Generating image sequence failed -" << error; + Q_EMIT generationFinished(false, error); + cleanup(); + return; + } + Q_EMIT progress(totalFrames, frameCount); + } + + Q_EMIT generationFinished(true, m_outputFileName.arg("*")); + cleanup(); +} + +void Q3DSImageSequenceGeneratorThread::cleanup() +{ + m_context->doneCurrent(); + delete m_context; + m_context = nullptr; + // Surface needs to be deleted in the thread it was created in + m_surface->moveToThread(m_mainThread); + deleteLater(); +} diff --git a/src/Runtime/api/studio3d/q3dsimagesequencegeneratorthread_p.h b/src/Runtime/api/studio3d/q3dsimagesequencegeneratorthread_p.h new file mode 100644 index 00000000..45869a69 --- /dev/null +++ b/src/Runtime/api/studio3d/q3dsimagesequencegeneratorthread_p.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef Q3DSIMAGE_SEQUENCE_GENERATOR_THREAD_H +#define Q3DSIMAGE_SEQUENCE_GENERATOR_THREAD_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtStudio3D API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtStudio3D/qstudio3dglobal.h> +#include <QtCore/qthread.h> +#include <QtCore/qurl.h> + +QT_BEGIN_NAMESPACE + +class QOffscreenSurface; +class QOpenGLContext; + +class Q3DSImageSequenceGeneratorThread : public QThread +{ + Q_OBJECT +public: + Q3DSImageSequenceGeneratorThread(); + virtual ~Q3DSImageSequenceGeneratorThread(); + + bool initialize(const QString &presentation, qreal start, qreal end, + qreal fps, qreal frameInterval, int width, int height, + const QString &outPath, const QString &outFile); + +Q_SIGNALS: + void progress(int totalFrames, int frameNumber); + void generationFinished(bool success, const QString &details); + +protected: + void run() override; + +private: + void cleanup(); + + QUrl m_sourceUrl; + qreal m_start; + qreal m_end; + qreal m_fps; + qreal m_frameInterval; + int m_width; + int m_height; + QString m_outputFileName; + + QOffscreenSurface *m_surface; + QOpenGLContext *m_context; + QThread *m_mainThread; +}; + +QT_END_NAMESPACE + +#endif // Q3DSIMAGE_SEQUENCE_GENERATOR_THREAD_H diff --git a/src/Runtime/api/studio3d/q3dspresentation.cpp b/src/Runtime/api/studio3d/q3dspresentation.cpp new file mode 100644 index 00000000..0887d702 --- /dev/null +++ b/src/Runtime/api/studio3d/q3dspresentation.cpp @@ -0,0 +1,974 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "q3dspresentation_p.h" +#include "q3dssceneelement_p.h" +#include "q3dscommandqueue_p.h" +#include "viewerqmlstreamproxy_p.h" +#include "q3dsdatainput_p.h" + +#include <QtCore/qdebug.h> +#include <QtCore/qsettings.h> +#include <QtCore/qcoreapplication.h> +#include <QtGui/qevent.h> + +QT_BEGIN_NAMESPACE + +Q3DSPresentation::Q3DSPresentation(QObject *parent) + : QObject(parent) + , d_ptr(new Q3DSPresentationPrivate(this)) +{ +} + +Q3DSPresentation::~Q3DSPresentation() +{ +} + +QUrl Q3DSPresentation::source() const +{ + return d_ptr->m_source; +} + +QStringList Q3DSPresentation::variantList() const +{ + return d_ptr->m_variantList; +} + +void Q3DSPresentation::registerElement(Q3DSElement *element) +{ + d_ptr->registerElement(element); +} + +void Q3DSPresentation::unregisterElement(Q3DSElement *element) +{ + d_ptr->unregisterElement(element); +} + +Q3DSElement *Q3DSPresentation::registeredElement(const QString &elementPath) const +{ + return d_ptr->m_elements.value(elementPath, nullptr); +} + +void Q3DSPresentation::registerDataInput(Q3DSDataInput *dataInput) +{ + d_ptr->registerDataInput(dataInput); +} + +void Q3DSPresentation::unregisterDataInput(Q3DSDataInput *dataInput) +{ + d_ptr->unregisterDataInput(dataInput); +} + +Q3DSDataInput *Q3DSPresentation::registeredDataInput(const QString &name) const +{ + return d_ptr->m_dataInputs.value(name, nullptr); +} + +QVector<Q3DSDataInput *> Q3DSPresentation::dataInputs() const +{ + QVector<Q3DSDataInput *> ret; + const auto datainputs = d_ptr->m_dataInputs; + for (const auto &it : datainputs) + ret.append(it); + + return ret; +} + +QVariantList Q3DSPresentation::getDataInputs() const +{ + QVariantList ret; + const auto datainputs = dataInputs(); + + for (const auto &it : datainputs) + ret.append(QVariant::fromValue(it)); + + return ret; +} + +void Q3DSPresentation::setSource(const QUrl &source) +{ + if (d_ptr->m_source != source) { + d_ptr->setSource(source); + Q_EMIT sourceChanged(source); + } +} + +void Q3DSPresentation::setVariantList(const QStringList &variantList) +{ + if (d_ptr->m_variantList != variantList) { + d_ptr->setVariantList(variantList); + Q_EMIT variantListChanged(variantList); + } +} + +bool Q3DSPresentation::delayedLoading() const +{ + return d_ptr->m_delayedLoading; +} + +void Q3DSPresentation::setDelayedLoading(bool enable) +{ + if (d_ptr->m_delayedLoading != enable) { + d_ptr->setDelayedLoading(enable); + Q_EMIT delayedLoadingChanged(enable); + } +} + +void Q3DSPresentation::preloadSlide(const QString &elementPath) +{ + if (d_ptr->m_viewerApp) + d_ptr->m_viewerApp->preloadSlide(elementPath); + else if (d_ptr->m_commandQueue) + d_ptr->m_commandQueue->queueCommand(elementPath, CommandType_PreloadSlide); +} + +void Q3DSPresentation::unloadSlide(const QString &elementPath) +{ + if (d_ptr->m_viewerApp) + d_ptr->m_viewerApp->unloadSlide(elementPath); + else if (d_ptr->m_commandQueue) + d_ptr->m_commandQueue->queueCommand(elementPath, CommandType_UnloadSlide); +} + +void Q3DSPresentation::goToSlide(const QString &elementPath, unsigned int index) +{ + if (d_ptr->m_viewerApp) { + const QByteArray path(elementPath.toUtf8()); + d_ptr->m_viewerApp->GoToSlideByIndex(path, index); + } else if (d_ptr->m_commandQueue) { + d_ptr->m_commandQueue->queueCommand(elementPath, CommandType_GoToSlide, int(index)); + } +} + +void Q3DSPresentation::goToSlide(const QString &elementPath, const QString &name) +{ + if (d_ptr->m_viewerApp) { + const QByteArray path(elementPath.toUtf8()); + const QByteArray byteName(name.toUtf8()); + d_ptr->m_viewerApp->GoToSlideByName(path, byteName); + } else if (d_ptr->m_commandQueue) { + d_ptr->m_commandQueue->queueCommand(elementPath, CommandType_GoToSlideByName, name); + } +} + +void Q3DSPresentation::goToSlide(const QString &elementPath, bool next, bool wrap) +{ + if (d_ptr->m_viewerApp) { + const QByteArray path(elementPath.toUtf8()); + d_ptr->m_viewerApp->GoToSlideRelative(path, next, wrap); + } else if (d_ptr->m_commandQueue) { + d_ptr->m_commandQueue->queueCommand(elementPath, CommandType_GoToSlideRelative, + int(next), int(wrap)); + } +} + +void Q3DSPresentation::goToTime(const QString &elementPath, float time) +{ + if (d_ptr->m_viewerApp) { + const QByteArray path(elementPath.toUtf8()); + d_ptr->m_viewerApp->GoToTime(path, time); + } else if (d_ptr->m_commandQueue) { + d_ptr->m_commandQueue->queueCommand(elementPath, CommandType_GoToTime, time); + } +} + +void Q3DSPresentation::setAttribute(const QString &elementPath, const QString &attributeName, + const QVariant &value) +{ + if (d_ptr->m_viewerApp) { + const QByteArray path(elementPath.toUtf8()); + const QByteArray name(attributeName.toUtf8()); + + QByteArray valueStr; + float valueFloat; + + const void *theValue = nullptr; + switch (static_cast<QMetaType::Type>(value.type())) { + case QMetaType::Bool: + case QMetaType::Int: + case QMetaType::Double: + case QMetaType::Float: + valueFloat = value.toFloat(); + theValue = &valueFloat; + break; + case QMetaType::QString: + default: // Try string for other types + valueStr = value.toString().toUtf8(); + theValue = valueStr.constData(); + break; + } + d_ptr->m_viewerApp->SetAttribute(path, name, (char *)theValue); + } else if (d_ptr->m_commandQueue) { + d_ptr->m_commandQueue->queueCommand(elementPath, CommandType_SetAttribute, + attributeName, value); + } +} + +void Q3DSPresentation::setPresentationActive(const QString &id, bool active) +{ + if (d_ptr->m_viewerApp) { + const QByteArray presId(id.toUtf8()); + d_ptr->m_viewerApp->SetPresentationActive(presId, active); + } else if (d_ptr->m_commandQueue) { + d_ptr->m_commandQueue->queueCommand(id, CommandType_SetPresentationActive, active); + } +} + +void Q3DSPresentation::fireEvent(const QString &elementPath, const QString &eventName) +{ + if (d_ptr->m_viewerApp) { + const QByteArray path(elementPath.toUtf8()); + const QByteArray name(eventName.toUtf8()); + d_ptr->m_viewerApp->FireEvent(path, name); + } else if (d_ptr->m_commandQueue) { + d_ptr->m_commandQueue->queueCommand(elementPath, CommandType_FireEvent, eventName); + } +} + +void Q3DSPresentation::setGlobalAnimationTime(qint64 milliseconds) +{ + if (d_ptr->m_viewerApp) { + d_ptr->m_viewerApp->SetGlobalAnimationTime(milliseconds); + } else { + d_ptr->m_commandQueue->m_globalAnimationTimeChanged = true; + d_ptr->m_commandQueue->m_globalAnimationTime = milliseconds; + } +} + +void Q3DSPresentation::setDataInputValue(const QString &name, const QVariant &value, + Q3DSDataInput::ValueRole valueRole) +{ + if (d_ptr->m_viewerApp) { + d_ptr->m_viewerApp->SetDataInputValue(name, value, + (qt3ds::runtime::DataInputValueRole)valueRole); + } else if (d_ptr->m_commandQueue) { + d_ptr->m_commandQueue->queueCommand(QString(), CommandType_SetDataInputValue, + name, value, static_cast<int>(valueRole)); + } +} + +/** + Adds a new child element for the element specified by parentElementPath to the slide specified + with slideName. Only model element creation is currently supported. + A referenced material element is also created for the new model element. The source material + name can be specified with custom "material" property in the properties hash. + The source material must exist in the material container of the presentation. +*/ +void Q3DSPresentation::createElement(const QString &parentElementPath, const QString &slideName, + const QHash<QString, QVariant> &properties) +{ + if (d_ptr->m_viewerApp) { + d_ptr->m_viewerApp->createElement(parentElementPath, slideName, properties); + } else if (d_ptr->m_commandQueue) { + // We need to copy the properties map as queue takes ownership of it + QHash<QString, QVariant> *theProperties = new QHash<QString, QVariant>(properties); + d_ptr->m_commandQueue->queueCommand(parentElementPath, CommandType_CreateElement, + slideName, theProperties); + } +} + +/** + Removes an element added by createElement and all its child elements. +*/ +void Q3DSPresentation::deleteElement(const QString &elementPath) +{ + if (d_ptr->m_viewerApp) + d_ptr->m_viewerApp->deleteElement(elementPath); + else if (d_ptr->m_commandQueue) + d_ptr->m_commandQueue->queueCommand(elementPath, CommandType_DeleteElement); +} + +/** + Creates a material specified by the materialDefinition parameter into the material + container of the presentation that owns the element specified by the elementPath parameter. + After creation, the material can be used for new elements created via createElement. + The materialDefinition parameter can contain either the file path to a material definition + file or a material definition in the Qt 3D Studion material data format. +*/ +void Q3DSPresentation::createMaterial(const QString &elementPath, + const QString &materialDefinition) +{ + if (d_ptr->m_viewerApp) { + d_ptr->m_viewerApp->createMaterial(elementPath, materialDefinition); + } else if (d_ptr->m_commandQueue) { + d_ptr->m_commandQueue->queueCommand(elementPath, CommandType_CreateMaterial, + materialDefinition); + } +} + +void Q3DSPresentation::mousePressEvent(QMouseEvent *e) +{ + if (d_ptr->m_viewerApp) { + d_ptr->m_viewerApp->HandleMousePress(e->x(), e->y(), e->button(), true); + } else if (d_ptr->m_commandQueue) { + d_ptr->m_commandQueue->queueCommand(QString(), CommandType_MousePress, + e->x(), e->y(), int(e->button())); + } +} + +void Q3DSPresentation::mouseReleaseEvent(QMouseEvent *e) +{ + if (d_ptr->m_viewerApp) { + d_ptr->m_viewerApp->HandleMousePress(e->x(), e->y(), e->button(), false); + } else if (d_ptr->m_commandQueue) { + d_ptr->m_commandQueue->queueCommand(QString(), CommandType_MouseRelease, + e->x(), e->y(), int(e->button())); + } +} + +void Q3DSPresentation::mouseMoveEvent(QMouseEvent *e) +{ + if (d_ptr->m_viewerApp) { + d_ptr->m_viewerApp->HandleMouseMove(e->x(), e->y(), true); + } else if (d_ptr->m_commandQueue) { + d_ptr->m_commandQueue->queueCommand(QString(), CommandType_MouseMove, + e->x(), e->y()); + } +} + +void Q3DSPresentation::wheelEvent(QWheelEvent *e) +{ + QPoint pixelData = e->pixelDelta(); + int numSteps = 0; + if (pixelData.isNull()) { + if (e->orientation() == Qt::Vertical) + numSteps = e->angleDelta().y() / 8; + else + numSteps = e->angleDelta().x() / 8; + } else { + // trackpad, pixel = one step in scroll wheel. + if (e->orientation() == Qt::Vertical) + numSteps = pixelData.y(); + else + numSteps = pixelData.x(); + } + if (numSteps != 0) { + if (d_ptr->m_viewerApp) { + d_ptr->m_viewerApp->HandleMouseWheel(e->x(), e->y(), + e->orientation() == Qt::Vertical ? 0 : 1, + numSteps); + } else if (d_ptr->m_commandQueue) { + d_ptr->m_commandQueue->queueCommand(QString(), CommandType_MouseWheel, + e->x(), e->y(), + int(e->orientation() == Qt::Vertical), numSteps); + } + } +} + +void Q3DSPresentation::keyPressEvent(QKeyEvent *e) +{ + if (d_ptr->m_viewerApp) { + d_ptr->m_viewerApp->HandleKeyInput(d_ptr->getScanCode(e), true); + } else if (d_ptr->m_commandQueue) { + d_ptr->m_commandQueue->queueCommand(QString(), CommandType_KeyPress, + d_ptr->getScanCode(e)); + } +} + +void Q3DSPresentation::keyReleaseEvent(QKeyEvent *e) +{ + if (d_ptr->m_viewerApp) { + d_ptr->m_viewerApp->HandleKeyInput(d_ptr->getScanCode(e), false); + } else if (d_ptr->m_commandQueue) { + d_ptr->m_commandQueue->queueCommand(QString(), CommandType_KeyRelease, + d_ptr->getScanCode(e)); + } +} + +Q3DSPresentationPrivate::Q3DSPresentationPrivate(Q3DSPresentation *q) + : QObject(q) + , q_ptr(q) + , m_viewerApp(nullptr) + , m_commandQueue(nullptr) + , m_streamProxy(nullptr) + , m_delayedLoading(false) +{ +} + +Q3DSPresentationPrivate::~Q3DSPresentationPrivate() +{ + unregisterAllElements(); + unregisterAllDataInputs(); + delete m_streamProxy; +} + +void Q3DSPresentationPrivate::setSource(const QUrl &source) +{ + m_source = source; + if (m_commandQueue) { + m_commandQueue->m_sourceChanged = true; + m_commandQueue->m_source = source; + } +} + +void Q3DSPresentationPrivate::setVariantList(const QStringList &variantList) +{ + m_variantList = variantList; + if (m_commandQueue) { + m_commandQueue->m_variantListChanged = true; + m_commandQueue->m_variantList = variantList; + } +} + +void Q3DSPresentationPrivate::setViewerApp(Q3DSViewer::Q3DSViewerApp *app, bool connectApp) +{ + Q3DSViewer::Q3DSViewerApp *oldApp = m_viewerApp; + m_viewerApp = app; + + const auto elements = m_elements.values(); + for (Q3DSElement *element : elements) + element->d_ptr->setViewerApp(app); + + if (m_viewerApp) { + const auto dataInputs = m_viewerApp->dataInputs(); + for (const auto &name : dataInputs) { + if (!m_dataInputs.contains(name)) { + auto *di = new Q3DSDataInput(name, nullptr); + registerDataInput(di); + } + } + Q_EMIT q_ptr->dataInputsReady(); + } + + if (connectApp) { + if (app) { + connect(app, &Q3DSViewer::Q3DSViewerApp::SigSlideEntered, + this, &Q3DSPresentationPrivate::handleSlideEntered); + connect(app, &Q3DSViewer::Q3DSViewerApp::SigSlideExited, + q_ptr, &Q3DSPresentation::slideExited); + connect(app, &Q3DSViewer::Q3DSViewerApp::SigCustomSignal, + q_ptr, &Q3DSPresentation::customSignalEmitted); + connect(app, &Q3DSViewer::Q3DSViewerApp::SigElementCreated, + q_ptr, &Q3DSPresentation::elementCreated); + connect(app, &Q3DSViewer::Q3DSViewerApp::SigMaterialCreated, + q_ptr, &Q3DSPresentation::materialCreated); + } + if (oldApp) { + disconnect(oldApp, &Q3DSViewer::Q3DSViewerApp::SigSlideEntered, + this, &Q3DSPresentationPrivate::handleSlideEntered); + disconnect(oldApp, &Q3DSViewer::Q3DSViewerApp::SigSlideExited, + q_ptr, &Q3DSPresentation::slideExited); + disconnect(oldApp, &Q3DSViewer::Q3DSViewerApp::SigCustomSignal, + q_ptr, &Q3DSPresentation::customSignalEmitted); + disconnect(oldApp, &Q3DSViewer::Q3DSViewerApp::SigElementCreated, + q_ptr, &Q3DSPresentation::elementCreated); + disconnect(oldApp, &Q3DSViewer::Q3DSViewerApp::SigMaterialCreated, + q_ptr, &Q3DSPresentation::materialCreated); + } + } +} + +void Q3DSPresentationPrivate::setCommandQueue(CommandQueue *queue) +{ + m_commandQueue = queue; + + const auto elements = m_elements.values(); + const auto dataInputs = m_dataInputs.values(); + for (Q3DSElement *element : elements) + element->d_ptr->setCommandQueue(queue); + for (Q3DSDataInput *di : dataInputs) + di->d_ptr->setCommandQueue(queue); + + if (m_commandQueue) { + setDelayedLoading(m_delayedLoading); + setVariantList(m_variantList); + // Queue a request ASAP for datainputs defined in UIA file so that + // getDataInputs has up-to-date info at the earliest. + m_commandQueue->queueCommand({}, CommandType_RequestDataInputs); + setSource(m_source); + } +} + +void Q3DSPresentationPrivate::setDelayedLoading(bool enable) +{ + m_delayedLoading = enable; + if (m_commandQueue) { + m_commandQueue->m_delayedLoading = enable; + m_commandQueue->m_delayedLoadingChanged = true; + } +} + +void Q3DSPresentationPrivate::requestResponseHandler(CommandType commandType, void *requestData) +{ + switch (commandType) { + case CommandType_RequestDataInputs: { + QVariantList *response = reinterpret_cast<QVariantList *>(requestData); + + for (int i = 0; i < response->size(); ++i) { + // Check and append to QML-side list if the (UIA) presentation has additional datainputs + // that are not explicitly defined in QML code. + if (!m_dataInputs.contains(response->at(i).value<QString>())) + registerDataInput(new Q3DSDataInput(response->at(i).value<QString>(), nullptr)); + } + delete response; + Q_EMIT q_ptr->dataInputsReady(); + break; + } + default: + Q_ASSERT(false); + break; + } +} +// Doc note: The ownership of the registered scenes remains with the caller, who needs to +// ensure that registered scenes are alive as long as the presentation is alive. +void Q3DSPresentationPrivate::registerElement(Q3DSElement *element) +{ + Q_ASSERT(!element->elementPath().isEmpty()); + + // Allow only single registration for each element path and scene object + QMutableHashIterator<QString, Q3DSElement *> i(m_elements); + while (i.hasNext()) { + i.next(); + if (i.value() == element) { + // If the same scene object is already registered with different path, + // remove it from the map to avoid duplication. + if (i.key() != element->elementPath()) + i.remove(); + } else if (i.key() == element->elementPath()) { + // If the same element path is registered by another scene object, the old + // scene object is unregistered. + i.value()->d_ptr->setViewerApp(nullptr); + i.value()->d_ptr->setPresentation(nullptr); + i.remove(); + } + } + + element->d_ptr->setViewerApp(m_viewerApp); + element->d_ptr->setCommandQueue(m_commandQueue); + element->d_ptr->setPresentation(this); + + m_elements.insert(element->elementPath(), element); +} + +void Q3DSPresentationPrivate::unregisterElement(Q3DSElement *element) +{ + Q3DSElement *oldScene = m_elements.value(element->elementPath()); + if (oldScene == element) { + element->d_ptr->setViewerApp(nullptr); + element->d_ptr->setCommandQueue(nullptr); + element->d_ptr->setPresentation(nullptr); + m_elements.remove(element->elementPath()); + } +} + +void Q3DSPresentationPrivate::unregisterAllElements() +{ + for (Q3DSElement *element : m_elements.values()) { + element->d_ptr->setViewerApp(nullptr); + element->d_ptr->setCommandQueue(nullptr); + element->d_ptr->setPresentation(nullptr); + } + m_elements.clear(); +} + +void Q3DSPresentationPrivate::registerDataInput(Q3DSDataInput *dataInput) +{ + Q_ASSERT(!dataInput->name().isEmpty()); + + // Allow only single registration for each DataInput + QMutableHashIterator<QString, Q3DSDataInput *> i(m_dataInputs); + while (i.hasNext()) { + i.next(); + if (i.value() == dataInput) { + // If the same DataInput object is already registered with different name, + // remove it from the map to avoid duplication. + if (i.key() != dataInput->name()) + i.remove(); + } else if (i.key() == dataInput->name()) { + // If the same name is registered by another DataInput object, the old + // DataInput object is unregistered. + i.value()->d_ptr->setViewerApp(nullptr); + i.value()->d_ptr->setPresentation(nullptr); + i.remove(); + } + } + + dataInput->d_ptr->setPresentation(q_ptr); + dataInput->d_ptr->setViewerApp(m_viewerApp); + dataInput->d_ptr->setCommandQueue(m_commandQueue); + + m_dataInputs.insert(dataInput->name(), dataInput); +} + +void Q3DSPresentationPrivate::unregisterDataInput(Q3DSDataInput *dataInput) +{ + Q3DSDataInput *oldDi = m_dataInputs.value(dataInput->name()); + if (oldDi == dataInput) { + dataInput->d_ptr->setCommandQueue(nullptr); + dataInput->d_ptr->setViewerApp(nullptr); + dataInput->d_ptr->setPresentation(nullptr); + m_dataInputs.remove(dataInput->name()); + } +} + +void Q3DSPresentationPrivate::unregisterAllDataInputs() +{ + for (Q3DSDataInput *di : m_dataInputs.values()) { + di->d_ptr->setViewerApp(nullptr); + di->d_ptr->setCommandQueue(nullptr); + di->d_ptr->setPresentation(nullptr); + } + m_dataInputs.clear(); +} +bool Q3DSPresentationPrivate::isValidDataInput(const Q3DSDataInput *dataInput) const +{ + if (!m_viewerApp) + return false; + + return m_viewerApp->dataInputs().contains(dataInput->name()); +} + +float Q3DSPresentationPrivate::dataInputMin(const QString &name) const +{ + if (!m_viewerApp) + return 0.0f; + + return m_viewerApp->dataInputMin(name); +} + +float Q3DSPresentationPrivate::dataInputMax(const QString &name) const +{ + if (!m_viewerApp) + return 0.0f; + + return m_viewerApp->dataInputMax(name); +} + +Q3DStudio::EKeyCode Q3DSPresentationPrivate::getScanCode(QKeyEvent *e) +{ + enum { + RIGHT_SHIFT = 0x036, + RIGHT_CTRL = 0x11d, + RIGHT_ALT = 0x138, + }; + + Qt::Key keyScanCode = static_cast<Qt::Key>(e->key()); + + Q3DStudio::EKeyCode newScanCode = Q3DStudio::KEY_NOKEY; + switch (keyScanCode) { + case Qt::Key_Down: + newScanCode = Q3DStudio::KEY_DOWN; + break; + case Qt::Key_Up: + newScanCode = Q3DStudio::KEY_UP; + break; + case Qt::Key_Left: + newScanCode = Q3DStudio::KEY_LEFT; + break; + case Qt::Key_Right: + newScanCode = Q3DStudio::KEY_RIGHT; + break; + case Qt::Key_Return: + case Qt::Key_Enter: + newScanCode = e->modifiers() == Qt::KeypadModifier ? Q3DStudio::KEY_NUMPADENTER + : Q3DStudio::KEY_RETURN; + break; + case Qt::Key_Backspace: + newScanCode = Q3DStudio::KEY_BACK; + break; + case Qt::Key_Tab: + newScanCode = Q3DStudio::KEY_TAB; + break; + case Qt::Key_Escape: + newScanCode = Q3DStudio::KEY_ESCAPE; + break; + case Qt::Key_A: + newScanCode = Q3DStudio::KEY_A; + break; + case Qt::Key_B: + newScanCode = Q3DStudio::KEY_B; + break; + case Qt::Key_C: + newScanCode = Q3DStudio::KEY_C; + break; + case Qt::Key_D: + newScanCode = Q3DStudio::KEY_D; + break; + case Qt::Key_E: + newScanCode = Q3DStudio::KEY_E; + break; + case Qt::Key_F: + newScanCode = Q3DStudio::KEY_F; + break; + case Qt::Key_G: + newScanCode = Q3DStudio::KEY_G; + break; + case Qt::Key_H: + newScanCode = Q3DStudio::KEY_H; + break; + case Qt::Key_I: + newScanCode = Q3DStudio::KEY_I; + break; + case Qt::Key_J: + newScanCode = Q3DStudio::KEY_J; + break; + case Qt::Key_K: + newScanCode = Q3DStudio::KEY_K; + break; + case Qt::Key_L: + newScanCode = Q3DStudio::KEY_L; + break; + case Qt::Key_M: + newScanCode = Q3DStudio::KEY_M; + break; + case Qt::Key_N: + newScanCode = Q3DStudio::KEY_N; + break; + case Qt::Key_O: + newScanCode = Q3DStudio::KEY_O; + break; + case Qt::Key_P: + newScanCode = Q3DStudio::KEY_P; + break; + case Qt::Key_Q: + newScanCode = Q3DStudio::KEY_Q; + break; + case Qt::Key_R: + newScanCode = Q3DStudio::KEY_R; + break; + case Qt::Key_S: + newScanCode = Q3DStudio::KEY_S; + break; + case Qt::Key_T: + newScanCode = Q3DStudio::KEY_T; + break; + case Qt::Key_U: + newScanCode = Q3DStudio::KEY_U; + break; + case Qt::Key_V: + newScanCode = Q3DStudio::KEY_V; + break; + case Qt::Key_W: + newScanCode = Q3DStudio::KEY_W; + break; + case Qt::Key_X: + newScanCode = Q3DStudio::KEY_X; + break; + case Qt::Key_Y: + newScanCode = Q3DStudio::KEY_Y; + break; + case Qt::Key_Z: + newScanCode = Q3DStudio::KEY_Z; + break; + case Qt::Key_0: + newScanCode = + e->modifiers() == Qt::KeypadModifier ? Q3DStudio::KEY_NUMPAD0 : Q3DStudio::KEY_0; + break; + case Qt::Key_1: + newScanCode = + e->modifiers() == Qt::KeypadModifier ? Q3DStudio::KEY_NUMPAD1 : Q3DStudio::KEY_1; + break; + case Qt::Key_2: + newScanCode = + e->modifiers() == Qt::KeypadModifier ? Q3DStudio::KEY_NUMPAD2 : Q3DStudio::KEY_2; + break; + case Qt::Key_3: + newScanCode = + e->modifiers() == Qt::KeypadModifier ? Q3DStudio::KEY_NUMPAD3 : Q3DStudio::KEY_3; + break; + case Qt::Key_4: + newScanCode = + e->modifiers() == Qt::KeypadModifier ? Q3DStudio::KEY_NUMPAD4 : Q3DStudio::KEY_4; + break; + case Qt::Key_5: + newScanCode = + e->modifiers() == Qt::KeypadModifier ? Q3DStudio::KEY_NUMPAD5 : Q3DStudio::KEY_5; + break; + case Qt::Key_6: + newScanCode = + e->modifiers() == Qt::KeypadModifier ? Q3DStudio::KEY_NUMPAD6 : Q3DStudio::KEY_6; + break; + case Qt::Key_7: + newScanCode = + e->modifiers() == Qt::KeypadModifier ? Q3DStudio::KEY_NUMPAD7 : Q3DStudio::KEY_7; + break; + case Qt::Key_8: + newScanCode = + e->modifiers() == Qt::KeypadModifier ? Q3DStudio::KEY_NUMPAD8 : Q3DStudio::KEY_8; + break; + case Qt::Key_9: + newScanCode = + e->modifiers() == Qt::KeypadModifier ? Q3DStudio::KEY_NUMPAD9 : Q3DStudio::KEY_9; + break; + case Qt::Key_Minus: + newScanCode = e->modifiers() == Qt::KeypadModifier ? Q3DStudio::KEY_NUMPADSUBTRACT + : Q3DStudio::KEY_SUBTRACT; + break; + case Qt::Key_Plus: + newScanCode = e->modifiers() == Qt::KeypadModifier ? Q3DStudio::KEY_NUMPADADD + : Q3DStudio::KEY_EQUALS; + break; + case Qt::Key_NumLock: + newScanCode = Q3DStudio::KEY_NUMLOCK; + break; + case Qt::Key_ScrollLock: + newScanCode = Q3DStudio::KEY_SCROLL; + break; + case Qt::Key_CapsLock: + newScanCode = Q3DStudio::KEY_CAPITAL; + break; + case Qt::Key_Pause: + newScanCode = Q3DStudio::KEY_PAUSE; + break; + case Qt::Key_Print: + newScanCode = Q3DStudio::KEY_PRINTSCREEN; + break; + case Qt::Key_Insert: + newScanCode = Q3DStudio::KEY_INSERT; + break; + case Qt::Key_Delete: + newScanCode = Q3DStudio::KEY_DELETE; + break; + case Qt::Key_Home: + newScanCode = Q3DStudio::KEY_HOME; + break; + case Qt::Key_End: + newScanCode = Q3DStudio::KEY_END; + break; + case Qt::Key_PageUp: + newScanCode = Q3DStudio::KEY_PGUP; + break; + case Qt::Key_PageDown: + newScanCode = Q3DStudio::KEY_PGDN; + break; + case Qt::Key_F1: + newScanCode = Q3DStudio::KEY_F1; + break; + case Qt::Key_F2: + newScanCode = Q3DStudio::KEY_F2; + break; + case Qt::Key_F3: + newScanCode = Q3DStudio::KEY_F3; + break; + case Qt::Key_F4: + newScanCode = Q3DStudio::KEY_F4; + break; + case Qt::Key_F5: + newScanCode = Q3DStudio::KEY_F5; + break; + case Qt::Key_F6: + newScanCode = Q3DStudio::KEY_F6; + break; + case Qt::Key_F7: + newScanCode = Q3DStudio::KEY_F7; + break; + case Qt::Key_F8: + newScanCode = Q3DStudio::KEY_F8; + break; + case Qt::Key_F9: + newScanCode = Q3DStudio::KEY_F9; + break; + case Qt::Key_F10: + newScanCode = Q3DStudio::KEY_F10; + break; + case Qt::Key_F11: + newScanCode = Q3DStudio::KEY_F11; + break; + case Qt::Key_F12: + newScanCode = Q3DStudio::KEY_F12; + break; + case Qt::Key_F13: + newScanCode = Q3DStudio::KEY_F13; + break; + case Qt::Key_F14: + newScanCode = Q3DStudio::KEY_F14; + break; + case Qt::Key_QuoteLeft: + newScanCode = Q3DStudio::KEY_GRAVE; + break; + case Qt::Key_Asterisk: + newScanCode = Q3DStudio::KEY_MULTIPLY; + break; + case Qt::Key_BracketRight: + newScanCode = Q3DStudio::KEY_RBRACKET; + break; + case Qt::Key_BracketLeft: + newScanCode = Q3DStudio::KEY_LBRACKET; + break; + case Qt::Key_Semicolon: + newScanCode = Q3DStudio::KEY_SEMICOLON; + break; + case Qt::Key_Comma: + newScanCode = Q3DStudio::KEY_COMMA; + break; + case Qt::Key_Period: + newScanCode = e->modifiers() == Qt::KeypadModifier ? Q3DStudio::KEY_NUMPADDECIMAL + : Q3DStudio::KEY_PERIOD; + break; + case Qt::Key_Apostrophe: + newScanCode = Q3DStudio::KEY_APOSTROPHE; + break; + case Qt::Key_Slash: + newScanCode = Q3DStudio::KEY_SLASH; + break; + case Qt::Key_Backslash: + newScanCode = Q3DStudio::KEY_BACKSLASH; + break; + case Qt::Key_Equal: + newScanCode = Q3DStudio::KEY_EQUALS; + break; + case Qt::Key_Space: + newScanCode = Q3DStudio::KEY_SPACE; + break; + case Qt::Key_Shift: + newScanCode = + e->nativeScanCode() == RIGHT_SHIFT ? Q3DStudio::KEY_RSHIFT : Q3DStudio::KEY_LSHIFT; + break; + case Qt::Key_Control: + newScanCode = e->nativeScanCode() == RIGHT_CTRL ? Q3DStudio::KEY_RCONTROL + : Q3DStudio::KEY_LCONTROL; + break; + case Qt::Key_Alt: + newScanCode = + e->nativeScanCode() == RIGHT_ALT ? Q3DStudio::KEY_RALT : Q3DStudio::KEY_LALT; + break; + default: + break; + } + + return newScanCode; +} + +ViewerQmlStreamProxy *Q3DSPresentationPrivate::streamProxy() +{ + if (!m_streamProxy) + m_streamProxy = new ViewerQmlStreamProxy(); + return m_streamProxy; +} + +void Q3DSPresentationPrivate::handleSlideEntered(const QString &elementPath, unsigned int index, + const QString &name) +{ + Q3DSSceneElement *scene = qobject_cast<Q3DSSceneElement *>(m_elements.value(elementPath)); + if (scene) + scene->d_func()->handleSlideEntered(index, name); + Q_EMIT q_ptr->slideEntered(elementPath, index, name); +} + +QT_END_NAMESPACE diff --git a/src/Runtime/api/studio3d/q3dspresentation.h b/src/Runtime/api/studio3d/q3dspresentation.h new file mode 100644 index 00000000..d7f02e49 --- /dev/null +++ b/src/Runtime/api/studio3d/q3dspresentation.h @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef Q3DSPRESENTATION_H +#define Q3DSPRESENTATION_H + +#include <QtStudio3D/qstudio3dglobal.h> +#include <QtCore/qobject.h> +#include <QtCore/qurl.h> +#include <QtStudio3D/q3dsdatainput.h> + +QT_BEGIN_NAMESPACE + +class Q3DSPresentationPrivate; +class Q3DSElement; +class QMouseEvent; +class QWheelEvent; +class QKeyEvent; + +class Q_STUDIO3D_EXPORT Q3DSPresentation : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(Q3DSPresentation) + Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(QStringList variantList READ variantList WRITE setVariantList NOTIFY variantListChanged) + Q_PROPERTY(bool delayedLoading READ delayedLoading WRITE setDelayedLoading NOTIFY delayedLoadingChanged) + +public: + explicit Q3DSPresentation(QObject *parent = nullptr); + ~Q3DSPresentation(); + + QUrl source() const; + QStringList variantList() const; + + void registerElement(Q3DSElement *scene); + void unregisterElement(Q3DSElement *scene); + Q3DSElement *registeredElement(const QString &elementPath) const; + + void registerDataInput(Q3DSDataInput *dataInput); + void unregisterDataInput(Q3DSDataInput *dataInput); + Q3DSDataInput *registeredDataInput(const QString &name) const; + + Q_INVOKABLE QVariantList getDataInputs() const; + QVector<Q3DSDataInput *> dataInputs() const; + + bool delayedLoading() const; + void setDelayedLoading(bool enable); + + Q_INVOKABLE void preloadSlide(const QString &elementPath); + Q_INVOKABLE void unloadSlide(const QString &elementPath); + + // Input event handlers + void mousePressEvent(QMouseEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void wheelEvent(QWheelEvent *e); + void keyPressEvent(QKeyEvent *e); + void keyReleaseEvent(QKeyEvent *e); + + void createElement(const QString &parentElementPath, const QString &slideName, + const QHash<QString, QVariant> &properties); + void deleteElement(const QString &elementPath); + void createMaterial(const QString &elementPath, const QString &materialDefinition); + +public Q_SLOTS: + void setSource(const QUrl &source); + void setVariantList(const QStringList &variantList); + void goToSlide(const QString &elementPath, unsigned int index); + void goToSlide(const QString &elementPath, const QString &name); + void goToSlide(const QString &elementPath, bool next, bool wrap); + void goToTime(const QString &elementPath, float time); + void setAttribute(const QString &elementPath, const QString &attributeName, + const QVariant &value); + void setPresentationActive(const QString &id, bool active); + void fireEvent(const QString &elementPath, const QString &eventName); + void setGlobalAnimationTime(qint64 milliseconds); + void setDataInputValue(const QString &name, const QVariant &value, + Q3DSDataInput::ValueRole valueRole = Q3DSDataInput::ValueRole::Value); + +Q_SIGNALS: + void variantListChanged(const QStringList &variantList); + void sourceChanged(const QUrl &source); + void slideEntered(const QString &elementPath, unsigned int index, const QString &name); + void slideExited(const QString &elementPath, unsigned int index, const QString &name); + // Indicates that data input definitions in the Studio project have been parsed + // and datainputs are available through dataInputs() / getDataInputs(). + void dataInputsReady(); + void customSignalEmitted(const QString &elementPath, const QString &name); + void delayedLoadingChanged(bool enable); + void elementCreated(const QString &elementPath, const QString &error); + void materialCreated(const QString &name, const QString &error); + +private: + Q_DISABLE_COPY(Q3DSPresentation) + Q3DSPresentationPrivate *d_ptr; + + friend class Q3DSPresentationItem; + friend class Q3DSSurfaceViewerPrivate; + friend class Q3DSWidgetPrivate; + friend class Q3DSRenderer; + friend class Q3DSStudio3D; + friend class Q3DSDataInput; +}; + +QT_END_NAMESPACE + +#endif // Q3DSPRESENTATION_H diff --git a/src/Runtime/api/studio3d/q3dspresentation_p.h b/src/Runtime/api/studio3d/q3dspresentation_p.h new file mode 100644 index 00000000..6172aa33 --- /dev/null +++ b/src/Runtime/api/studio3d/q3dspresentation_p.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef Q3DSPRESENTATION_P_H +#define Q3DSPRESENTATION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtStudio3D API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "q3dspresentation.h" +#include "q3dscommandqueue_p.h" +#include "Qt3DSViewerApp.h" +#include <QtCore/QHash> +#include <QtCore/QUrl> + +QT_BEGIN_NAMESPACE + +class CommandQueue; +class ViewerQmlStreamProxy; +class QKeyEvent; + +class Q_STUDIO3D_EXPORT Q3DSPresentationPrivate : public QObject +{ + Q_OBJECT + Q_DECLARE_PUBLIC(Q3DSPresentation) + +public: + typedef QHash<QString, Q3DSElement *> ElementMap; + typedef QHash<QString, Q3DSDataInput *> DataInputMap; + + explicit Q3DSPresentationPrivate(Q3DSPresentation *parent); + ~Q3DSPresentationPrivate(); + + void setSource(const QUrl &source); + void setVariantList(const QStringList &variantList); + void setViewerApp(Q3DSViewer::Q3DSViewerApp *app, bool connectApp = true); + void setCommandQueue(CommandQueue *queue); + void setDelayedLoading(bool enable); + + void registerElement(Q3DSElement *element); + void unregisterElement(Q3DSElement *element); + void unregisterAllElements(); + + void registerDataInput(Q3DSDataInput *dataInput); + void unregisterDataInput(Q3DSDataInput *dataInput); + void unregisterAllDataInputs(); + + bool isValidDataInput(const Q3DSDataInput *dataInput) const; + float dataInputMin(const QString &name) const; + float dataInputMax(const QString &name) const; + + ViewerQmlStreamProxy *streamProxy(); + Q3DStudio::EKeyCode getScanCode(QKeyEvent *e); + + void requestResponseHandler(CommandType commandType, void *requestData); + +public Q_SLOTS: + void handleSlideEntered(const QString &elementPath, unsigned int index, const QString &name); + +public: + Q3DSPresentation *q_ptr; + +private: + Q3DSViewer::Q3DSViewerApp *m_viewerApp; // Not owned + CommandQueue *m_commandQueue; // Not owned + ElementMap m_elements; + DataInputMap m_dataInputs; + QUrl m_source; + QStringList m_variantList; + ViewerQmlStreamProxy *m_streamProxy; + bool m_delayedLoading; + + friend class Q3DSStudio3D; +}; + +QT_END_NAMESPACE + +#endif // Q3DSPRESENTATION_P_H diff --git a/src/Runtime/api/studio3d/q3dssceneelement.cpp b/src/Runtime/api/studio3d/q3dssceneelement.cpp new file mode 100644 index 00000000..2eef5d00 --- /dev/null +++ b/src/Runtime/api/studio3d/q3dssceneelement.cpp @@ -0,0 +1,273 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "q3dssceneelement_p.h" +#include "q3dspresentation_p.h" +#include "q3dscommandqueue_p.h" + +#include <QtCore/qdebug.h> +#include <QtCore/qsettings.h> +#include <QtCore/qcoreapplication.h> + +QT_BEGIN_NAMESPACE + +Q3DSSceneElement::Q3DSSceneElement(QObject *parent) + : Q3DSElement(new Q3DSSceneElementPrivate(this), nullptr, QString(), parent) +{ +} + +Q3DSSceneElement::Q3DSSceneElement(const QString &elementPath, QObject *parent) + : Q3DSElement(new Q3DSSceneElementPrivate(this), nullptr, elementPath, parent) +{ +} + +Q3DSSceneElement::Q3DSSceneElement(Q3DSPresentation *presentation, const QString &elementPath, + QObject *parent) + : Q3DSElement(new Q3DSSceneElementPrivate(this), presentation, elementPath, parent) +{ + +} + +Q3DSSceneElement::~Q3DSSceneElement() +{ +} + +int Q3DSSceneElement::currentSlideIndex() const +{ + Q_D(const Q3DSSceneElement); + return d->m_currentSlideIndex; +} + +int Q3DSSceneElement::previousSlideIndex() const +{ + Q_D(const Q3DSSceneElement); + return d->m_previousSlideIndex; +} + +QString Q3DSSceneElement::currentSlideName() const +{ + Q_D(const Q3DSSceneElement); + return d->m_currentSlideName; +} + +QString Q3DSSceneElement::previousSlideName() const +{ + Q_D(const Q3DSSceneElement); + return d->m_previousSlideName; +} + +void Q3DSSceneElement::setCurrentSlideIndex(int currentSlideIndex) +{ + Q_D(Q3DSSceneElement); + if (d->m_viewerApp) { + const QByteArray path(d->m_elementPath.toUtf8()); + d->m_viewerApp->GoToSlideByIndex(path, currentSlideIndex + 1); + } else if (d->m_commandQueue) { + d->m_commandQueue->queueCommand(d->m_elementPath, CommandType_GoToSlide, + int(currentSlideIndex + 1)); + } else { + // Store desired slide until we have either app or queue. Only name or index can be set. + d->m_initialSlideIndex = currentSlideIndex + 1; + d->m_initialSlideName.clear(); + } +} + +void Q3DSSceneElement::setCurrentSlideName(const QString ¤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; + } +} + +void Q3DSSceneElement::goToSlide(bool next, bool wrap) +{ + Q_D(Q3DSSceneElement); + d->goToSlide(next, wrap); +} + +void Q3DSSceneElement::goToTime(float time) +{ + Q_D(Q3DSSceneElement); + d->goToTime(time); +} + +Q3DSSceneElementPrivate::Q3DSSceneElementPrivate(Q3DSSceneElement *parent) + : Q3DSElementPrivate(parent) + , m_currentSlideIndex(0) + , m_previousSlideIndex(0) + , m_initialSlideIndex(0) + , m_slideInfoRequestPending(false) +{ +} + +Q3DSSceneElementPrivate::~Q3DSSceneElementPrivate() +{ +} + +void Q3DSSceneElementPrivate::handleSlideEntered(int index, const QString &name) +{ + Q_Q(Q3DSSceneElement); + + // Initializing presentation will report slide entered for the scenes on the default slide + // of the presentation even if user has specified different initial slides. + // Since we don't have robust error reporting mechanism from the viewerapp, + // we cannot simply ignore these initial enters, as there is no guarantee the slide + // user wants even exists. + + // We ignore the slide exited signals and rely on stored previous slide data + // to avoid excessive signaling on slide changes. + bool notifyCurrent = m_currentSlideIndex != index; + bool notifyPrevious = m_previousSlideIndex != m_currentSlideIndex; + + // Since child (i.e. component) slides always get enter event when parent slide is entered, + // it is possible that current and previous slides are the same. This feels bit odd, but is + // technically correct, as the last time we got enter, the same slide was made current. + // It also matches the internal m_viewerApp logic for previous slides. + m_previousSlideIndex = m_currentSlideIndex; + m_previousSlideName = m_currentSlideName; + m_currentSlideIndex = index; + m_currentSlideName = name; + + if (notifyPrevious) { + Q_EMIT q->previousSlideIndexChanged(m_previousSlideIndex); + Q_EMIT q->previousSlideNameChanged(m_previousSlideName); + } + + if (notifyCurrent) { + Q_EMIT q->currentSlideIndexChanged(m_currentSlideIndex); + Q_EMIT q->currentSlideNameChanged(m_currentSlideName); + } +} + +void Q3DSSceneElementPrivate::goToSlide(bool next, bool wrap) +{ + if (m_presentation) + m_presentation->q_ptr->goToSlide(m_elementPath, next, wrap); + else + qWarning() << __FUNCTION__ << "Element is not registered to any presentation!"; +} + +void Q3DSSceneElementPrivate::goToTime(float time) +{ + if (m_presentation) + m_presentation->q_ptr->goToTime(m_elementPath, time); + else + qWarning() << __FUNCTION__ << "Element is not registered to any presentation!"; +} + +void Q3DSSceneElementPrivate::setViewerApp(Q3DSViewer::Q3DSViewerApp *app) +{ + Q_Q(Q3DSSceneElement); + + if (app || m_viewerApp) { + m_currentSlideIndex = 0; + m_currentSlideName.clear(); + m_previousSlideIndex = 0; + m_previousSlideName.clear(); + } + + Q3DSElementPrivate::setViewerApp(app); + + if (m_viewerApp) { + const QByteArray path(m_elementPath.toUtf8()); + m_viewerApp->GetSlideInfo(path, m_currentSlideIndex, m_previousSlideIndex, + m_currentSlideName, m_previousSlideName); + + // If user has set current slide before viewer app has been set for the first time, + // we will switch to the desired slide after we initialize. + if (m_initialSlideIndex != 0) + q->setCurrentSlideIndex(m_initialSlideIndex - 1); + else if (!m_initialSlideName.isEmpty()) + q->setCurrentSlideName(m_initialSlideName); + + m_initialSlideIndex = 0; + m_initialSlideName.clear(); + } +} + +void Q3DSSceneElementPrivate::setCommandQueue(CommandQueue *queue) +{ + Q_Q(Q3DSSceneElement); + + if (queue || m_commandQueue) { + m_currentSlideIndex = 0; + m_currentSlideName.clear(); + m_previousSlideIndex = 0; + m_previousSlideName.clear(); + } + Q3DSElementPrivate::setCommandQueue(queue); + + if (m_commandQueue) { + m_commandQueue->queueCommand(m_elementPath, CommandType_RequestSlideInfo); + m_slideInfoRequestPending = true; + // If user has set current slide before the queue has been set for the first time, + // we will switch to the desired slide after we initialize. + if (m_initialSlideIndex != 0) + q->setCurrentSlideIndex(m_initialSlideIndex - 1); + else if (!m_initialSlideName.isEmpty()) + q->setCurrentSlideName(m_initialSlideName); + + m_initialSlideIndex = 0; + m_initialSlideName.clear(); + } +} + +void Q3DSSceneElementPrivate::requestResponseHandler(CommandType commandType, void *requestData) +{ + switch (commandType) { + case CommandType_RequestSlideInfo: { + QVariantList *response = reinterpret_cast<QVariantList *>(requestData); + if (m_slideInfoRequestPending) { + m_slideInfoRequestPending = false; + + m_previousSlideIndex = response->at(1).toInt(); + m_previousSlideName = response->at(3).toString(); + + handleSlideEntered(response->at(0).toInt(), response->at(2).toString()); + } + delete response; + break; + } + default: + Q3DSElementPrivate::requestResponseHandler(commandType, requestData); + break; + } +} + +QT_END_NAMESPACE diff --git a/src/Runtime/api/studio3d/q3dssceneelement.h b/src/Runtime/api/studio3d/q3dssceneelement.h new file mode 100644 index 00000000..2d96255c --- /dev/null +++ b/src/Runtime/api/studio3d/q3dssceneelement.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef Q3DSSCENEELEMENT_H +#define Q3DSSCENEELEMENT_H + +#include <QtStudio3D/q3dselement.h> +#include <QtCore/qobject.h> + +QT_BEGIN_NAMESPACE + +class Q3DSSceneElementPrivate; + +class Q_STUDIO3D_EXPORT Q3DSSceneElement : public Q3DSElement +{ + Q_OBJECT + Q_DECLARE_PRIVATE(Q3DSSceneElement) + + Q_PROPERTY(int currentSlideIndex READ currentSlideIndex WRITE setCurrentSlideIndex NOTIFY currentSlideIndexChanged) + Q_PROPERTY(int previousSlideIndex READ previousSlideIndex NOTIFY previousSlideIndexChanged) + Q_PROPERTY(QString currentSlideName READ currentSlideName WRITE setCurrentSlideName NOTIFY currentSlideNameChanged) + Q_PROPERTY(QString previousSlideName READ previousSlideName NOTIFY previousSlideNameChanged) + +public: + explicit Q3DSSceneElement(QObject *parent = nullptr); + explicit Q3DSSceneElement(const QString &elementPath, QObject *parent = nullptr); + explicit Q3DSSceneElement(Q3DSPresentation *presentation, const QString &elementPath, + QObject *parent = nullptr); + ~Q3DSSceneElement(); + + int currentSlideIndex() const; + int previousSlideIndex() const; + QString currentSlideName() const; + QString previousSlideName() const; + +public Q_SLOTS: + void setCurrentSlideIndex(int currentSlideIndex); + void setCurrentSlideName(const QString ¤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/api/studio3d/q3dssceneelement_p.h b/src/Runtime/api/studio3d/q3dssceneelement_p.h new file mode 100644 index 00000000..02d2bdff --- /dev/null +++ b/src/Runtime/api/studio3d/q3dssceneelement_p.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef Q3DSSCENEELEMENT_P_H +#define Q3DSSCENEELEMENT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtStudio3D API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "q3dssceneelement.h" +#include "q3dselement_p.h" +#include "q3dscommandqueue_p.h" +#include "Qt3DSViewerApp.h" + +QT_BEGIN_NAMESPACE + +class Q3DSPresentationPrivate; + +class Q_STUDIO3D_EXPORT Q3DSSceneElementPrivate : public Q3DSElementPrivate +{ + Q_DECLARE_PUBLIC(Q3DSSceneElement) +public: + explicit Q3DSSceneElementPrivate(Q3DSSceneElement *parent); + ~Q3DSSceneElementPrivate(); + + void handleSlideEntered(int index, const QString &name); + void goToSlide(bool next, bool wrap); + void goToTime(float time); + + void setViewerApp(Q3DSViewer::Q3DSViewerApp *app) override; + void setCommandQueue(CommandQueue *queue) override; + + void requestResponseHandler(CommandType commandType, void *requestData) override; + +private: + int m_currentSlideIndex; + int m_previousSlideIndex; + int m_initialSlideIndex; + QString m_currentSlideName; + QString m_previousSlideName; + QString m_initialSlideName; + bool m_slideInfoRequestPending; +}; + +QT_END_NAMESPACE + +#endif // Q3DSSCENEELEMENT_P_H diff --git a/src/Runtime/api/studio3d/q3dssurfaceviewer.cpp b/src/Runtime/api/studio3d/q3dssurfaceviewer.cpp new file mode 100644 index 00000000..fc90e341 --- /dev/null +++ b/src/Runtime/api/studio3d/q3dssurfaceviewer.cpp @@ -0,0 +1,435 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "q3dssurfaceviewer_p.h" +#include "Qt3DSAudioPlayerImpl.h" +#include "viewerqmlstreamproxy_p.h" +#include "q3dsviewersettings_p.h" +#include "q3dspresentation_p.h" +#include "studioutils_p.h" + +#include <QtCore/qdebug.h> +#include <QtGui/qopenglcontext.h> +#include <QtGui/qopenglfunctions.h> +#include <QtGui/qoffscreensurface.h> +#include <QtGui/qwindow.h> +#include <QtGui/QPlatformSurfaceEvent> + +#include <QtCore/QFileInfo> + +using namespace Q3DSViewer; + +QT_BEGIN_NAMESPACE + +Q3DSSurfaceViewer::Q3DSSurfaceViewer(QObject *parent) + : QObject(parent) + , d_ptr(new Q3DSSurfaceViewerPrivate(this)) +{ +} + +Q3DSSurfaceViewer::~Q3DSSurfaceViewer() +{ + delete d_ptr; +} + +bool Q3DSSurfaceViewer::initialize(QSurface *surface, QOpenGLContext *context, GLuint fboId) +{ + return d_ptr->initialize(surface, context, fboId); +} + +void Q3DSSurfaceViewer::shutdown() +{ + d_ptr->shutdown(); +} + +void Q3DSSurfaceViewer::reset() +{ + d_ptr->reset(); +} + +void Q3DSSurfaceViewer::update() +{ + d_ptr->update(); +} + +QImage Q3DSSurfaceViewer::grab(const QRect &rect) +{ + return d_ptr->grab(rect); +} + +QSize Q3DSSurfaceViewer::size() const +{ + return d_ptr->m_size; +} + +void Q3DSSurfaceViewer::setSize(const QSize &size) +{ + d_ptr->setSize(size); +} + +bool Q3DSSurfaceViewer::autoSize() const +{ + return d_ptr->m_autoSize; +} + +void Q3DSSurfaceViewer::setAutoSize(bool autoSize) +{ + if (d_ptr->m_autoSize != autoSize) { + d_ptr->m_autoSize = autoSize; + Q_EMIT autoSizeChanged(autoSize); + } +} + +int Q3DSSurfaceViewer::updateInterval() const +{ + return d_ptr->m_updateInterval; +} + +void Q3DSSurfaceViewer::setUpdateInterval(int interval) +{ + d_ptr->setUpdateInterval(interval); +} + +bool Q3DSSurfaceViewer::isRunning() const +{ + return d_ptr->m_viewerApp != nullptr; +} + +QString Q3DSSurfaceViewer::presentationId() const +{ + return d_ptr->m_id; +} + +int Q3DSSurfaceViewer::fboId() const +{ + return d_ptr->m_fboId; +} + +QSurface *Q3DSSurfaceViewer::surface() const +{ + return d_ptr->m_surface; +} + +QOpenGLContext *Q3DSSurfaceViewer::context() const +{ + return d_ptr->m_context; +} + +Q3DSViewerSettings *Q3DSSurfaceViewer::settings() const +{ + return d_ptr->m_settings; +} + +Q3DSPresentation *Q3DSSurfaceViewer::presentation() const +{ + return d_ptr->m_presentation; +} + +void Q3DSSurfaceViewer::setPresentationId(const QString &id) +{ + if (d_ptr->m_id != id) { + d_ptr->m_id = id; + Q_EMIT presentationIdChanged(id); + if (d_ptr->m_viewerApp) + d_ptr->m_viewerApp->setPresentationId(id); + } +} + +Q3DSSurfaceViewerPrivate::Q3DSSurfaceViewerPrivate(Q3DSSurfaceViewer *q) + : QObject(q) + , q_ptr(q) + , m_viewerApp(nullptr) + , m_timer(nullptr) + , m_updateInterval(-1) + , m_pixelRatio(1.0) + , m_fboId(0) + , m_surface(nullptr) + , m_context(nullptr) + , m_autoSize(true) + , m_settings(new Q3DSViewerSettings(this)) + , m_presentation(new Q3DSPresentation(this)) +{ + m_startupTimer.start(); + connect(m_presentation, &Q3DSPresentation::sourceChanged, + this, &Q3DSSurfaceViewerPrivate::reset); +} + +Q3DSSurfaceViewerPrivate::~Q3DSSurfaceViewerPrivate() +{ + releaseRuntime(); + + delete m_timer; +} + +void Q3DSSurfaceViewerPrivate::reset() +{ + if (m_viewerApp) { + releaseRuntime(); + initializeRuntime(); + } +} + +void Q3DSSurfaceViewerPrivate::setSize(const QSize &size) +{ + if (m_size != size) { + m_size = size; + + if (m_viewerApp) { + m_context->makeCurrent(m_surface); + m_viewerApp->Resize(int(m_size.width() * m_pixelRatio), + int(m_size.height() * m_pixelRatio)); + } + + Q_EMIT q_ptr->sizeChanged(m_size); + } +} + +void Q3DSSurfaceViewerPrivate::setUpdateInterval(int interval) +{ + if (m_updateInterval != interval) { + m_updateInterval = interval; + resetUpdateTimer(); + Q_EMIT q_ptr->updateIntervalChanged(m_updateInterval); + } +} + +bool Q3DSSurfaceViewerPrivate::initialize(QSurface *surface, QOpenGLContext *context, GLuint fboId) +{ + Q_ASSERT(context); + Q_ASSERT(surface); + + if (m_presentation->source().isEmpty()) { + qWarning("Failed to initialize Q3DSSurfaceViewer," + " presentation source must be set before calling initialize()"); + return false; + } + + QFileInfo info(Q3DSUtils::urlToLocalFileOrQrc(m_presentation->source())); + if (!info.exists()) { + qWarning() << "Failed to initialize Q3DSSurfaceViewer, the presentation doesn't exist:" + << m_presentation->source().toString(); + return false; + } + + shutdown(); + + m_surface = surface; + m_context = context; + m_fboId = fboId; + if (m_surface->surfaceClass() == QSurface::Window && fboId == 0) + m_pixelRatio = static_cast<QWindow *>(m_surface)->devicePixelRatio(); + + surfaceObject()->installEventFilter(this); + + connect(context, &QOpenGLContext::aboutToBeDestroyed, this, &Q3DSSurfaceViewerPrivate::shutdown); + + bool success = initializeRuntime(); + + if (success) + Q_EMIT q_ptr->runningChanged(true); + + return success; +} + + +void Q3DSSurfaceViewerPrivate::shutdown() +{ + bool oldInitialized = (m_viewerApp != nullptr); + + if (m_context) { + disconnect(m_context, &QOpenGLContext::aboutToBeDestroyed, + this, &Q3DSSurfaceViewerPrivate::shutdown); + } + + if (m_surface) + surfaceObject()->removeEventFilter(this); + + releaseRuntime(); + + m_surface = nullptr; + m_context = nullptr; + m_fboId = 0; + + if (oldInitialized) + Q_EMIT q_ptr->runningChanged(false); +} + + +void Q3DSSurfaceViewerPrivate::update() +{ + if (m_viewerApp && m_viewerApp->IsInitialised()) { + if (m_surface->surfaceClass() != QSurface::Window + || static_cast<QWindow *>(m_surface)->isExposed()) { + m_context->makeCurrent(m_surface); + if (m_autoSize) + setSize(m_surface->size()); + m_viewerApp->Render(); + + if (m_fboId == 0) + m_context->swapBuffers(m_surface); + + Q_EMIT q_ptr->frameUpdated(); + } + } +} + +extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, + bool include_alpha); + +QImage Q3DSSurfaceViewerPrivate::grab(const QRect &rect) +{ + QRect captureRect; + QSize fullSize = m_size * m_pixelRatio; + if (rect.isValid()) { + captureRect = QRect(rect.x() * m_pixelRatio, rect.y() * m_pixelRatio, + rect.width() * m_pixelRatio, rect.height() * m_pixelRatio); + } else { + captureRect = QRect(0, 0, fullSize.width(), fullSize.height()); + } + QImage image(captureRect.size(), QImage::Format_ARGB32); + + if (m_surface && m_context && m_viewerApp && m_viewerApp->IsInitialised() + && (m_surface->surfaceClass() != QSurface::Window + || static_cast<QWindow *>(m_surface)->isExposed())) { + m_context->makeCurrent(m_surface); + + // Render now to ensure the image is up to date and will actually exist in case + // the surface has a non-preserved swap buffer + if (m_autoSize) + setSize(m_surface->size()); + m_viewerApp->Render(); + + m_context->functions()->glBindFramebuffer(GL_FRAMEBUFFER, m_fboId); + QImage fullGrab = qt_gl_read_framebuffer(fullSize, false, false); + + // Also update the screen to match the grab, since we just rendered + if (m_fboId == 0) + m_context->swapBuffers(m_surface); + + if (captureRect.size() == fullSize) + image = fullGrab; + else + image = fullGrab.copy(captureRect); + } + + return image; +} + +bool Q3DSSurfaceViewerPrivate::eventFilter(QObject *obj, QEvent *e) +{ + if (m_surface && e->type() == QEvent::PlatformSurface) { + if (surfaceObject() == obj) { + QPlatformSurfaceEvent *ev = static_cast<QPlatformSurfaceEvent *>(e); + if (ev->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) + shutdown(); + } + } + return QObject::eventFilter(obj, e); +} + +bool Q3DSSurfaceViewerPrivate::initializeRuntime() +{ + Q_ASSERT(!m_viewerApp); + + m_context->makeCurrent(m_surface); + + m_viewerApp = &Q3DSViewerApp::Create(m_context, new Qt3DSAudioPlayerImpl(), &m_startupTimer); + connect(m_viewerApp, &Q3DSViewerApp::SigPresentationReady, + this->q_ptr, &Q3DSSurfaceViewer::presentationReady); + connect(m_viewerApp, &Q3DSViewerApp::SigPresentationLoaded, + this->q_ptr, &Q3DSSurfaceViewer::presentationLoaded); + Q_ASSERT(m_viewerApp); + + const QString localSource = Q3DSUtils::urlToLocalFileOrQrc(m_presentation->source()); + + if (m_autoSize) + m_size = m_surface->size(); + + if (!m_viewerApp->InitializeApp(int(m_size.width() * m_pixelRatio), + int(m_size.height() * m_pixelRatio), + m_context->format(), m_fboId, localSource, + m_presentation->variantList(), + m_presentation->delayedLoading(), + m_presentation->d_ptr->streamProxy())) { + releaseRuntime(); + qWarning("Failed to initialize runtime"); + return false; + } + + if (!m_id.isEmpty()) + m_viewerApp->setPresentationId(m_id); + m_settings->d_ptr->setViewerApp(m_viewerApp); + m_presentation->d_ptr->setViewerApp(m_viewerApp); + + resetUpdateTimer(); + + return true; +} + +void Q3DSSurfaceViewerPrivate::releaseRuntime() +{ + m_settings->d_ptr->setViewerApp(nullptr); + m_presentation->d_ptr->setViewerApp(nullptr); + + if (m_context && m_surface) + m_context->makeCurrent(m_surface); + + if (m_viewerApp) { + m_viewerApp->Release(); + m_viewerApp = nullptr; + } + + resetUpdateTimer(); +} + +void Q3DSSurfaceViewerPrivate::resetUpdateTimer() +{ + if (m_viewerApp && m_updateInterval >= 0) { + if (!m_timer) { + m_timer = new QTimer(); + connect(m_timer, &QTimer::timeout, this, &Q3DSSurfaceViewerPrivate::update); + } + m_timer->start(m_updateInterval); + } else if (m_timer) { + m_timer->stop(); + } +} + +QObject *Q3DSSurfaceViewerPrivate::surfaceObject() +{ + if (m_surface) { + if (m_surface->surfaceClass() == QSurface::Window) + return static_cast<QWindow *>(m_surface); + else + return static_cast<QOffscreenSurface *>(m_surface); + } + return nullptr; +} + +QT_END_NAMESPACE diff --git a/src/Runtime/api/studio3d/q3dssurfaceviewer.h b/src/Runtime/api/studio3d/q3dssurfaceviewer.h new file mode 100644 index 00000000..90d25aa1 --- /dev/null +++ b/src/Runtime/api/studio3d/q3dssurfaceviewer.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef Q3DSSURFACEVIEWER_H +#define Q3DSSURFACEVIEWER_H + +#include <QtStudio3D/qstudio3dglobal.h> +#include <QtCore/qobject.h> +#include <QtCore/qsize.h> +#include <QtCore/qurl.h> +#include <QtGui/qimage.h> +#include <QtGui/qopengl.h> + +QT_BEGIN_NAMESPACE + +class Q3DSSurfaceViewerPrivate; +class QSurface; +class QOpenGLContext; +class Q3DSViewerSettings; +class Q3DSPresentation; + +class Q_STUDIO3D_EXPORT Q3DSSurfaceViewer : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(Q3DSSurfaceViewer) + Q_PROPERTY(QSize size READ size WRITE setSize NOTIFY sizeChanged) + Q_PROPERTY(bool autoSize READ autoSize WRITE setAutoSize NOTIFY autoSizeChanged) + Q_PROPERTY(int updateInterval READ updateInterval WRITE setUpdateInterval NOTIFY updateIntervalChanged) + Q_PROPERTY(bool running READ isRunning NOTIFY runningChanged) + Q_PROPERTY(QString presentationId READ presentationId WRITE setPresentationId NOTIFY presentationIdChanged) + +public: + explicit Q3DSSurfaceViewer(QObject *parent = nullptr); + ~Q3DSSurfaceViewer(); + + bool initialize(QSurface *surface, QOpenGLContext *context, GLuint fboId = 0); + + QImage grab(const QRect &rect = QRect()); + + // Property accessors + QSize size() const; + bool autoSize() const; + int updateInterval() const; + bool isRunning() const; + QString presentationId() const; + + int fboId() const; + QSurface *surface() const; + QOpenGLContext *context() const; + + Q3DSViewerSettings *settings() const; + Q3DSPresentation *presentation() const; + +public Q_SLOTS: + void setSize(const QSize &size); + void setAutoSize(bool autoSize); + void setUpdateInterval(int interval); + void update(); + void shutdown(); + void reset(); + void setPresentationId(const QString &id); + +Q_SIGNALS: + void presentationLoaded(); + void presentationReady(); + void sizeChanged(const QSize &size); + void autoSizeChanged(bool autoSize); + void updateIntervalChanged(bool autoUpdate); + void runningChanged(bool initialized); + void frameUpdated(); + void presentationIdChanged(const QString &id); + +private: + Q_DISABLE_COPY(Q3DSSurfaceViewer) + Q3DSSurfaceViewerPrivate *d_ptr; +}; + +QT_END_NAMESPACE + +#endif // Q3DSSURFACEVIEWER_H diff --git a/src/Runtime/api/studio3d/q3dssurfaceviewer_p.h b/src/Runtime/api/studio3d/q3dssurfaceviewer_p.h new file mode 100644 index 00000000..9c56c1b5 --- /dev/null +++ b/src/Runtime/api/studio3d/q3dssurfaceviewer_p.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef Q3DSSURFACEVIEWER_P_H +#define Q3DSSURFACEVIEWER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtStudio3D API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "q3dssurfaceviewer.h" +#include "Qt3DSViewerApp.h" + +#include <QtCore/qtimer.h> + +QT_BEGIN_NAMESPACE + +class QSurface; +class QOpenGLContext; +class Q3DSViewerSettings; +class Q3DSPresentation; + +class Q_STUDIO3D_EXPORT Q3DSSurfaceViewerPrivate : public QObject +{ + Q_OBJECT + Q_DECLARE_PUBLIC(Q3DSSurfaceViewer) +public: + explicit Q3DSSurfaceViewerPrivate(Q3DSSurfaceViewer *parent = nullptr); + ~Q3DSSurfaceViewerPrivate(); + + void reset(); + void setSize(const QSize &size); + void setUpdateInterval(int interval); + bool initialize(QSurface *surface, QOpenGLContext *context, GLuint fboId); + void update(); + + QImage grab(const QRect &rect); + +private Q_SLOTS: + void shutdown(); + +protected: + bool eventFilter(QObject *obj, QEvent *e) override; + +private: + bool initializeRuntime(); + void releaseRuntime(); + void resetUpdateTimer(); + QObject *surfaceObject(); + + Q3DSSurfaceViewer *q_ptr; + + Q3DSViewer::Q3DSViewerApp *m_viewerApp; + QSize m_size; + QTimer *m_timer; + int m_updateInterval; + qreal m_pixelRatio; + GLuint m_fboId; + QSurface *m_surface; // Not owned + QOpenGLContext *m_context; // Not owned + bool m_autoSize; + Q3DSViewerSettings *m_settings; + Q3DSPresentation *m_presentation; + QString m_id; + QElapsedTimer m_startupTimer; +}; + +QT_END_NAMESPACE + +#endif // Q3DSSURFACEVIEWER_P_H diff --git a/src/Runtime/api/studio3d/q3dsviewersettings.cpp b/src/Runtime/api/studio3d/q3dsviewersettings.cpp new file mode 100644 index 00000000..b6660c84 --- /dev/null +++ b/src/Runtime/api/studio3d/q3dsviewersettings.cpp @@ -0,0 +1,244 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "q3dsviewersettings_p.h" +#include "Qt3DSViewerApp.h" +#include "q3dscommandqueue_p.h" + +#include <QtCore/qdebug.h> +#include <QtCore/qsettings.h> +#include <QtCore/qcoreapplication.h> + +QT_BEGIN_NAMESPACE + +Q3DSViewerSettings::Q3DSViewerSettings(QObject *parent) + : QObject(parent) + , d_ptr(new Q3DSViewerSettingsPrivate(this)) +{ +} + +Q3DSViewerSettings::~Q3DSViewerSettings() +{ +} + +QColor Q3DSViewerSettings::matteColor() const +{ + return d_ptr->m_matteColor; +} + +bool Q3DSViewerSettings::isShowRenderStats() const +{ + return d_ptr->m_showRenderStats; +} + +Q3DSViewerSettings::ShadeMode Q3DSViewerSettings::shadeMode() const +{ + return d_ptr->m_shadeMode; +} + +Q3DSViewerSettings::ScaleMode Q3DSViewerSettings::scaleMode() const +{ + return d_ptr->m_scaleMode; +} + +void Q3DSViewerSettings::save(const QString &group, const QString &organization, + const QString &application) +{ + d_ptr->save(group, organization, application); +} + +void Q3DSViewerSettings::load(const QString &group, const QString &organization, + const QString &application) +{ + d_ptr->load(group, organization, application); +} + +void Q3DSViewerSettings::setMatteColor(const QColor &color) +{ + if (d_ptr->m_matteColor != color) { + d_ptr->setMatteColor(color); + Q_EMIT matteColorChanged(color); + } +} + +void Q3DSViewerSettings::setShowRenderStats(bool show) +{ + if (d_ptr->m_showRenderStats != show) { + d_ptr->setShowRenderStats(show); + Q_EMIT showRenderStatsChanged(show); + } +} + +void Q3DSViewerSettings::setShadeMode(Q3DSViewerSettings::ShadeMode mode) +{ + if (d_ptr->m_shadeMode != mode) { + d_ptr->setShadeMode(mode); + Q_EMIT shadeModeChanged(mode); + } + +} + +void Q3DSViewerSettings::setScaleMode(Q3DSViewerSettings::ScaleMode mode) +{ + if (d_ptr->m_scaleMode != mode) { + d_ptr->setScaleMode(mode); + Q_EMIT scaleModeChanged(mode); + } +} + +Q3DSViewerSettingsPrivate::Q3DSViewerSettingsPrivate(Q3DSViewerSettings *q) + : QObject(q) + , q_ptr(q) + , m_viewerApp(nullptr) + , m_commandQueue(nullptr) + , m_matteColor(Qt::black) + , m_showRenderStats(false) + , m_shadeMode(Q3DSViewerSettings::ShadeModeShaded) + , m_scaleMode(Q3DSViewerSettings::ScaleModeCenter) + , m_savedSettings(nullptr) +{ +} + +Q3DSViewerSettingsPrivate::~Q3DSViewerSettingsPrivate() +{ +} + +void Q3DSViewerSettingsPrivate::setViewerApp(Q3DSViewer::Q3DSViewerApp *app) +{ + m_viewerApp = app; + if (m_viewerApp) { + setMatteColor(m_matteColor); + setShowRenderStats(m_showRenderStats); + setShadeMode(m_shadeMode); + setScaleMode(m_scaleMode); + } +} + +void Q3DSViewerSettingsPrivate::setCommandQueue(CommandQueue *queue) +{ + m_commandQueue = queue; + if (m_commandQueue) { + setMatteColor(m_matteColor); + setShowRenderStats(m_showRenderStats); + setShadeMode(m_shadeMode); + setScaleMode(m_scaleMode); + } +} + +void Q3DSViewerSettingsPrivate::save(const QString &group, const QString &organization, + const QString &application) +{ + initSettingsStore(group, organization, application); + + m_savedSettings->setValue(QStringLiteral("matteColor"), m_matteColor); + m_savedSettings->setValue(QStringLiteral("showRenderStats"), m_showRenderStats); + m_savedSettings->setValue(QStringLiteral("shadeMode"), m_shadeMode); + m_savedSettings->setValue(QStringLiteral("scaleMode"), m_scaleMode); +} + +void Q3DSViewerSettingsPrivate::load(const QString &group, const QString &organization, + const QString &application) +{ + initSettingsStore(group, organization, application); + + q_ptr->setMatteColor(m_savedSettings->value(QStringLiteral("matteColor")).value<QColor>()); + q_ptr->setShowRenderStats(m_savedSettings->value(QStringLiteral("showRenderStats")).toBool()); + q_ptr->setShadeMode(Q3DSViewerSettings::ShadeMode( + m_savedSettings->value(QStringLiteral("shadeMode")).toInt())); + q_ptr->setScaleMode(Q3DSViewerSettings::ScaleMode( + m_savedSettings->value(QStringLiteral("scaleMode")).toInt())); +} + +void Q3DSViewerSettingsPrivate::setMatteColor(const QColor &color) +{ + m_matteColor = color; + if (m_viewerApp) { + m_viewerApp->setMatteColor(color); + } else if (m_commandQueue) { + m_commandQueue->m_matteColor = color; + m_commandQueue->m_matteColorChanged = true; + } +} + +void Q3DSViewerSettingsPrivate::setShowRenderStats(bool show) +{ + m_showRenderStats = show; + if (m_viewerApp) { + m_viewerApp->setShowOnScreenStats(show); + } else if (m_commandQueue) { + m_commandQueue->m_showRenderStats = show; + m_commandQueue->m_showRenderStatsChanged = true; + } +} + +void Q3DSViewerSettingsPrivate::setShadeMode(Q3DSViewerSettings::ShadeMode mode) +{ + m_shadeMode = mode; + if (m_viewerApp) { + if (mode == Q3DSViewerSettings::ShadeModeShaded) + m_viewerApp->SetShadeMode(Q3DSViewer::ViewerShadeModes::Shaded); + else + m_viewerApp->SetShadeMode(Q3DSViewer::ViewerShadeModes::ShadedWireframe); + } else if (m_commandQueue) { + m_commandQueue->m_shadeMode = mode; + m_commandQueue->m_shadeModeChanged = true; + } +} + +void Q3DSViewerSettingsPrivate::setScaleMode(Q3DSViewerSettings::ScaleMode mode) +{ + m_scaleMode = mode; + if (m_viewerApp) { + if (mode == Q3DSViewerSettings::ScaleModeFit) + m_viewerApp->SetScaleMode(Q3DSViewer::ViewerScaleModes::ScaleToFit); + else if (mode == Q3DSViewerSettings::ScaleModeFill) + m_viewerApp->SetScaleMode(Q3DSViewer::ViewerScaleModes::ScaleToFill); + else + m_viewerApp->SetScaleMode(Q3DSViewer::ViewerScaleModes::ExactSize); + } else if (m_commandQueue) { + m_commandQueue->m_scaleMode = mode; + m_commandQueue->m_scaleModeChanged = true; + } +} + +void Q3DSViewerSettingsPrivate::initSettingsStore(const QString &group, const QString &organization, + const QString &application) +{ + if (!m_savedSettings) { + QString org = organization.isEmpty() ? QCoreApplication::instance()->organizationName() + : organization; + QString app = application.isEmpty() ? QCoreApplication::instance()->applicationName() + : application; + + m_savedSettings = new QSettings(org, app, this); + m_savedSettings->beginGroup(group); + } +} + +QT_END_NAMESPACE diff --git a/src/Runtime/api/studio3d/q3dsviewersettings.h b/src/Runtime/api/studio3d/q3dsviewersettings.h new file mode 100644 index 00000000..82d7d62e --- /dev/null +++ b/src/Runtime/api/studio3d/q3dsviewersettings.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef Q3DSVIEWERSETTINGS_H +#define Q3DSVIEWERSETTINGS_H + +#include <QtStudio3D/qstudio3dglobal.h> +#include <QtCore/qobject.h> +#include <QtGui/qcolor.h> + +QT_BEGIN_NAMESPACE + +class Q3DSViewerSettingsPrivate; + +class Q_STUDIO3D_EXPORT Q3DSViewerSettings : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(Q3DSViewerSettings) + Q_ENUMS(ShadeMode) + Q_ENUMS(ScaleMode) + Q_PROPERTY(QColor matteColor READ matteColor WRITE setMatteColor NOTIFY matteColorChanged) + Q_PROPERTY(bool showRenderStats READ isShowRenderStats WRITE setShowRenderStats NOTIFY showRenderStatsChanged) + Q_PROPERTY(ShadeMode shadeMode READ shadeMode WRITE setShadeMode NOTIFY shadeModeChanged) + Q_PROPERTY(ScaleMode scaleMode READ scaleMode WRITE setScaleMode NOTIFY scaleModeChanged) + +public: + enum ShadeMode { + ShadeModeShaded, + ShadeModeShadedWireframe + }; + + enum ScaleMode { + ScaleModeFit, + ScaleModeFill, + ScaleModeCenter + }; + + explicit Q3DSViewerSettings(QObject *parent = nullptr); + ~Q3DSViewerSettings(); + + QColor matteColor() const; + bool isShowRenderStats() const; + ShadeMode shadeMode() const; + ScaleMode scaleMode() const; + + Q_INVOKABLE void save(const QString &group, const QString &organization = QString(), + const QString &application = QString()); + Q_INVOKABLE void load(const QString &group, const QString &organization = QString(), + const QString &application = QString()); + +public Q_SLOTS: + void setMatteColor(const QColor &color); + void setShowRenderStats(bool show); + void setShadeMode(ShadeMode mode); + void setScaleMode(ScaleMode mode); + +Q_SIGNALS: + void matteColorChanged(const QColor &color); + void showRenderStatsChanged(bool show); + void shadeModeChanged(ShadeMode mode); + void scaleModeChanged(ScaleMode mode); + +private: + Q_DISABLE_COPY(Q3DSViewerSettings) + Q3DSViewerSettingsPrivate *d_ptr; + + friend class Q3DSSurfaceViewerPrivate; + friend class Q3DSWidgetPrivate; + friend class Q3DSRenderer; + friend class Q3DSStudio3D; +}; + +QT_END_NAMESPACE + +#endif // Q3DSVIEWERSETTINGS_H diff --git a/src/Runtime/api/studio3d/q3dsviewersettings_p.h b/src/Runtime/api/studio3d/q3dsviewersettings_p.h new file mode 100644 index 00000000..48fbae3a --- /dev/null +++ b/src/Runtime/api/studio3d/q3dsviewersettings_p.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef Q3DSVIEWERSETTINGS_P_H +#define Q3DSVIEWERSETTINGS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtStudio3D API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "q3dsviewersettings.h" +#include "Qt3DSViewerApp.h" + +QT_BEGIN_NAMESPACE + +class QSettings; +class CommandQueue; + +class Q_STUDIO3D_EXPORT Q3DSViewerSettingsPrivate : public QObject +{ + Q_OBJECT + Q_DECLARE_PUBLIC(Q3DSViewerSettings) +public: + explicit Q3DSViewerSettingsPrivate(Q3DSViewerSettings *parent); + ~Q3DSViewerSettingsPrivate(); + + void setViewerApp(Q3DSViewer::Q3DSViewerApp *app); + void setCommandQueue(CommandQueue *queue); + void save(const QString &group, const QString &organization, const QString &application); + void load(const QString &group, const QString &organization, const QString &application); + + void setMatteColor(const QColor &color); + void setShowRenderStats(bool show); + void setShadeMode(Q3DSViewerSettings::ShadeMode mode); + void setScaleMode(Q3DSViewerSettings::ScaleMode mode); + +public: + Q3DSViewerSettings *q_ptr; + +private: + void initSettingsStore(const QString &group, const QString &organization, + const QString &application); + + Q3DSViewer::Q3DSViewerApp *m_viewerApp; // Not owned + CommandQueue *m_commandQueue; // Not owned + QColor m_matteColor; + bool m_showRenderStats; + Q3DSViewerSettings::ShadeMode m_shadeMode; + Q3DSViewerSettings::ScaleMode m_scaleMode; + QSettings *m_savedSettings; +}; + +QT_END_NAMESPACE + +#endif // Q3DSVIEWERSETTINGS_P_H diff --git a/src/Runtime/api/studio3d/q3dswidget.cpp b/src/Runtime/api/studio3d/q3dswidget.cpp new file mode 100644 index 00000000..23334b5b --- /dev/null +++ b/src/Runtime/api/studio3d/q3dswidget.cpp @@ -0,0 +1,332 @@ +/**************************************************************************** +** +** Copyright (C) 2013 - 2016 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "q3dswidget_p.h" +#include "Qt3DSAudioPlayerImpl.h" +#include "viewerqmlstreamproxy_p.h" +#include "q3dsviewersettings_p.h" +#include "q3dspresentation_p.h" +#include "studioutils_p.h" +#include "q3dsvariantconfig_p.h" + +#include <QtGui/qevent.h> +#include <QtGui/qopenglcontext.h> +#include <QtGui/QWindow> +#include <QtCore/qfileinfo.h> +#include <QtCore/qdebug.h> + +using namespace Q3DSViewer; + +QT_BEGIN_NAMESPACE + +typedef void (QWidget::*QWidgetVoidSlot)(); + +Q3DSWidget::Q3DSWidget(QWidget *parent) + : QOpenGLWidget(parent) + , d_ptr(new Q3DSWidgetPrivate(this)) +{ + // Get keyboard handling + setFocusPolicy(Qt::StrongFocus); + setMouseTracking(true); +} + +Q3DSWidget::~Q3DSWidget() +{ + delete d_ptr; +} + +bool Q3DSWidget::initialize() +{ + return d_ptr->initialize(); +} + +int Q3DSWidget::updateInterval() const +{ + return d_ptr->m_updateInterval; +} + +bool Q3DSWidget::isRunning() const +{ + return d_ptr->m_viewerApp != nullptr; +} + +Q3DSViewerSettings *Q3DSWidget::settings() const +{ + return d_ptr->settings(); +} + +Q3DSPresentation *Q3DSWidget::presentation() const +{ + return d_ptr->presentation(); +} + +void Q3DSWidget::initializeGL() +{ + // Find the native window to determine pixel ratio + QWidget *widget = this; + QWindow *window = windowHandle(); + while (widget && window == nullptr) { + widget = qobject_cast<QWidget *>(widget->parent()); + window = widget->windowHandle(); + } + if (window) + d_ptr->m_pixelRatio = window->devicePixelRatio(); +} + +void Q3DSWidget::resizeGL(int w, int h) +{ + if (d_ptr->m_viewerApp) + d_ptr->m_viewerApp->Resize(int(w * d_ptr->m_pixelRatio), int(h * d_ptr->m_pixelRatio)); +} + +void Q3DSWidget::paintGL() +{ + if (d_ptr->m_viewerApp && d_ptr->m_viewerApp->IsInitialised()) + d_ptr->m_viewerApp->Render(); +} + +void Q3DSWidget::setUpdateInterval(int interval) +{ + d_ptr->setUpdateInterval(interval); +} + +void Q3DSWidget::shutdown() +{ + d_ptr->shutdown(); +} + +void Q3DSWidget::reset() +{ + d_ptr->reset(); +} + +void Q3DSWidget::mousePressEvent(QMouseEvent *event) +{ + if (d_ptr->m_pixelRatio != 1.0) { + QMouseEvent scaledEvent(event->type(), event->pos() * d_ptr->m_pixelRatio, + event->button(), event->buttons(), event->modifiers()); + d_ptr->m_presentation->mousePressEvent(&scaledEvent); + } else { + d_ptr->m_presentation->mousePressEvent(event); + } +} + +void Q3DSWidget::mouseReleaseEvent(QMouseEvent *event) +{ + if (d_ptr->m_pixelRatio != 1.0) { + QMouseEvent scaledEvent(event->type(), event->pos() * d_ptr->m_pixelRatio, + event->button(), event->buttons(), event->modifiers()); + d_ptr->m_presentation->mouseReleaseEvent(&scaledEvent); + } else { + d_ptr->m_presentation->mouseReleaseEvent(event); + } +} + +void Q3DSWidget::mouseMoveEvent(QMouseEvent *event) +{ + if (d_ptr->m_pixelRatio != 1.0) { + QMouseEvent scaledEvent(event->type(), event->pos() * d_ptr->m_pixelRatio, + event->button(), event->buttons(), event->modifiers()); + d_ptr->m_presentation->mouseMoveEvent(&scaledEvent); + } else { + d_ptr->m_presentation->mouseMoveEvent(event); + } +} + +void Q3DSWidget::wheelEvent(QWheelEvent *event) +{ + d_ptr->m_presentation->wheelEvent(event); +} + +void Q3DSWidget::keyPressEvent(QKeyEvent *event) +{ + d_ptr->m_presentation->keyPressEvent(event); +} + +void Q3DSWidget::keyReleaseEvent(QKeyEvent *event) +{ + d_ptr->m_presentation->keyReleaseEvent(event); +} + +Q3DSWidgetPrivate::Q3DSWidgetPrivate(Q3DSWidget *q) + : QObject(q) + , q_ptr(q) + , m_viewerApp(nullptr) + , m_timer(nullptr) + , m_updateInterval(-1) + , m_pixelRatio(1.0) + , m_settings(new Q3DSViewerSettings(this)) + , m_presentation(new Q3DSPresentation(this)) +{ + m_startupTimer.start(); + connect(m_presentation, &Q3DSPresentation::sourceChanged, this, &Q3DSWidgetPrivate::reset); +} + +Q3DSWidgetPrivate::~Q3DSWidgetPrivate() +{ + releaseRuntime(); + + delete m_timer; +} + +void Q3DSWidgetPrivate::reset() +{ + if (m_viewerApp) { + releaseRuntime(); + initializeRuntime(); + } +} + +void Q3DSWidgetPrivate::setUpdateInterval(int interval) +{ + if (m_updateInterval != interval) { + m_updateInterval = interval; + resetUpdateTimer(); + Q_EMIT q_ptr->updateIntervalChanged(m_updateInterval); + } +} + +bool Q3DSWidgetPrivate::initialize() +{ + Q_ASSERT(q_ptr->context()); + + if (m_presentation->source().isEmpty()) { + qWarning("Failed to initialize Q3DSWidget," + " presentation source must be set before calling initialize()"); + return false; + } + + QFileInfo info(Q3DSUtils::urlToLocalFileOrQrc(m_presentation->source())); + if (!info.exists()) { + qWarning() << "Failed to initialize Q3DSWidget, the presentation doesn't exist:" + << m_presentation->source().toString(); + return false; + } + + shutdown(); + + connect(q_ptr->context(), &QOpenGLContext::aboutToBeDestroyed, + this, &Q3DSWidgetPrivate::shutdown); + + bool success = initializeRuntime(); + + if (success) + Q_EMIT q_ptr->runningChanged(true); + + return success; +} + +Q3DSViewerSettings *Q3DSWidgetPrivate::settings() +{ + return m_settings; +} + +Q3DSPresentation *Q3DSWidgetPrivate::presentation() +{ + return m_presentation; +} + +void Q3DSWidgetPrivate::shutdown() +{ + bool oldInitialized = (m_viewerApp != nullptr); + + if (q_ptr->context()) { + disconnect(q_ptr->context(), &QOpenGLContext::aboutToBeDestroyed, + this, &Q3DSWidgetPrivate::shutdown); + } + + releaseRuntime(); + + if (oldInitialized) + Q_EMIT q_ptr->runningChanged(false); +} + +bool Q3DSWidgetPrivate::initializeRuntime() +{ + Q_ASSERT(!m_viewerApp); + + q_ptr->makeCurrent(); + + m_viewerApp = &Q3DSViewerApp::Create(q_ptr->context(), new Qt3DSAudioPlayerImpl(), + &m_startupTimer); + + Q_ASSERT(m_viewerApp); + + const QString localSource = Q3DSUtils::urlToLocalFileOrQrc(m_presentation->source()); + + if (!m_viewerApp->InitializeApp(int(q_ptr->width() * m_pixelRatio), + int(q_ptr->height() * m_pixelRatio), + q_ptr->context()->format(), + q_ptr->defaultFramebufferObject(), localSource, + m_presentation->variantList(), + m_presentation->delayedLoading(), + m_presentation->d_ptr->streamProxy())) { + releaseRuntime(); + qWarning("Failed to initialize runtime"); + return false; + } + + m_settings->d_ptr->setViewerApp(m_viewerApp); + m_presentation->d_ptr->setViewerApp(m_viewerApp); + + resetUpdateTimer(); + + return true; +} + +void Q3DSWidgetPrivate::releaseRuntime() +{ + m_settings->d_ptr->setViewerApp(nullptr); + m_presentation->d_ptr->setViewerApp(nullptr); + + if (m_viewerApp) { + q_ptr->makeCurrent(); + m_viewerApp->Release(); + m_viewerApp = nullptr; + } + + resetUpdateTimer(); +} + +void Q3DSWidgetPrivate::resetUpdateTimer() +{ + if (m_viewerApp && m_updateInterval >= 0) { + if (!m_timer) { + m_timer = new QTimer(); + connect(m_timer, &QTimer::timeout, + q_ptr, static_cast<QWidgetVoidSlot>(&QWidget::update)); + } + m_timer->start(m_updateInterval); + } else if (m_timer) { + m_timer->stop(); + } +} + +QT_END_NAMESPACE diff --git a/src/Runtime/api/studio3d/q3dswidget.h b/src/Runtime/api/studio3d/q3dswidget.h new file mode 100644 index 00000000..ad5d823d --- /dev/null +++ b/src/Runtime/api/studio3d/q3dswidget.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2013 - 2016 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef Q3DSWIDGET_H +#define Q3DSWIDGET_H + +#include <QtStudio3D/qstudio3dglobal.h> +#include <QtWidgets/QOpenGLWidget> +#include <QtCore/QUrl> + +QT_BEGIN_NAMESPACE + +class Q3DSWidgetPrivate; +class Q3DSViewerSettings; +class Q3DSPresentation; + +class Q_STUDIO3D_EXPORT Q3DSWidget : public QOpenGLWidget +{ + Q_OBJECT + Q_DECLARE_PRIVATE(Q3DSWidget) + Q_PROPERTY(int updateInterval READ updateInterval WRITE setUpdateInterval NOTIFY updateIntervalChanged) + Q_PROPERTY(bool running READ isRunning NOTIFY runningChanged) + +public: + explicit Q3DSWidget(QWidget *parent = nullptr); + virtual ~Q3DSWidget(); + + bool initialize(); + + // Property accessors + int updateInterval() const; + bool isRunning() const; + + Q3DSViewerSettings *settings() const; + Q3DSPresentation *presentation() const; + +public Q_SLOTS: + void setUpdateInterval(int interval); + void shutdown(); + void reset(); + +Q_SIGNALS: + void updateIntervalChanged(bool autoUpdate); + void runningChanged(bool initialized); + +protected: + // Qt event handling + void mousePressEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void wheelEvent(QWheelEvent *event) override; + void keyPressEvent(QKeyEvent *event) override; + void keyReleaseEvent(QKeyEvent *e) override; + + // Qt overrides + void initializeGL() override; + void resizeGL(int w, int h) override; + void paintGL() override; + +private: + Q_DISABLE_COPY(Q3DSWidget) + Q3DSWidgetPrivate *d_ptr; +}; +QT_END_NAMESPACE +#endif // Q3DSWIDGET_H diff --git a/src/Runtime/api/studio3d/q3dswidget_p.h b/src/Runtime/api/studio3d/q3dswidget_p.h new file mode 100644 index 00000000..03ca6aac --- /dev/null +++ b/src/Runtime/api/studio3d/q3dswidget_p.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2013 - 2016 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtStudio3D API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Q3DSWIDGET_P_H +#define Q3DSWIDGET_P_H + +#include "q3dswidget.h" +#include "Qt3DSViewerApp.h" + +#include <QtCore/qtimer.h> + +QT_BEGIN_NAMESPACE + +class Q3DSViewerSettings; +class Q3DSPresentation; + +class Q_STUDIO3D_EXPORT Q3DSWidgetPrivate : public QObject +{ +public: + Q_OBJECT + Q_DECLARE_PUBLIC(Q3DSWidget) + +public: + explicit Q3DSWidgetPrivate(Q3DSWidget *q); + virtual ~Q3DSWidgetPrivate(); + + void reset(); + void setUpdateInterval(int interval); + bool initialize(); + + Q3DSViewerSettings *settings(); + Q3DSPresentation *presentation(); + +private Q_SLOTS: + void shutdown(); + +private: + bool initializeRuntime(); + void releaseRuntime(); + void resetUpdateTimer(); + + Q3DSWidget *q_ptr; + + Q3DSViewer::Q3DSViewerApp *m_viewerApp; + QTimer *m_timer; + int m_updateInterval; + qreal m_pixelRatio; + QElapsedTimer m_startupTimer; + + Q3DSViewerSettings *m_settings; + Q3DSPresentation *m_presentation; +}; + +QT_END_NAMESPACE + +#endif // Q3DSWIDGET_P_H diff --git a/src/Runtime/api/studio3d/qstudio3dglobal.h b/src/Runtime/api/studio3d/qstudio3dglobal.h new file mode 100644 index 00000000..d1960634 --- /dev/null +++ b/src/Runtime/api/studio3d/qstudio3dglobal.h @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSTUDIO3D_GLOBAL_H +#define QSTUDIO3D_GLOBAL_H + +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +#ifndef QT_STATIC +# if defined(QT_BUILD_STUDIO3D_LIB) +# define Q_STUDIO3D_EXPORT Q_DECL_EXPORT +# else +# define Q_STUDIO3D_EXPORT Q_DECL_IMPORT +# endif +#else +# define Q_STUDIO3D_EXPORT +#endif + +QT_END_NAMESPACE + +#endif // QSTUDIO3D_GLOBAL_H diff --git a/src/Runtime/api/studio3d/studio3d.pro b/src/Runtime/api/studio3d/studio3d.pro new file mode 100644 index 00000000..6c5e0585 --- /dev/null +++ b/src/Runtime/api/studio3d/studio3d.pro @@ -0,0 +1,53 @@ +TARGET = QtStudio3D + +include($$PWD/../../commoninclude.pri) +QT += opengl widgets qml + +qtHaveModule(multimedia) { +DEFINES += PLATFORM_HAS_QT_MULTIMEDIA_LIB +QT += multimedia +} +CONFIG += console + +LIBS += \ + -lqt3dsopengl$$qtPlatformTargetSuffix() \ + -lqt3dsqmlstreamer$$qtPlatformTargetSuffix() + +HEADERS += \ + q3dswidget.h \ + q3dswidget_p.h \ + q3dssurfaceviewer.h \ + q3dssurfaceviewer_p.h \ + qstudio3dglobal.h \ + viewerqmlstreamproxy_p.h \ + q3dsviewersettings.h \ + q3dsviewersettings_p.h \ + q3dspresentation.h \ + q3dspresentation_p.h \ + q3dssceneelement.h \ + q3dssceneelement_p.h \ + q3dselement.h \ + q3dselement_p.h \ + studioutils_p.h \ + q3dscommandqueue_p.h \ + q3dsimagesequencegenerator_p.h \ + q3dsimagesequencegeneratorthread_p.h \ + q3dsdatainput.h \ + q3dsdatainput_p.h + +SOURCES += q3dswidget.cpp \ + q3dssurfaceviewer.cpp \ + viewerqmlstreamproxy.cpp \ + q3dsviewersettings.cpp \ + q3dspresentation.cpp \ + q3dssceneelement.cpp \ + q3dselement.cpp \ + studioutils.cpp \ + q3dscommandqueue.cpp \ + q3dsimagesequencegenerator.cpp \ + q3dsimagesequencegeneratorthread.cpp \ + q3dsdatainput.cpp + +load(qt_module) + +OTHER_FILES += $$PWD/../../../doc/src/12-cpp-reference/* diff --git a/src/Runtime/api/studio3d/studioutils.cpp b/src/Runtime/api/studio3d/studioutils.cpp new file mode 100644 index 00000000..9156be7f --- /dev/null +++ b/src/Runtime/api/studio3d/studioutils.cpp @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "studioutils_p.h" + +#include <QtCore/QString> + +QT_BEGIN_NAMESPACE + +QString Q3DSUtils::urlToLocalFileOrQrc(const QUrl &url) +{ + const QString scheme(url.scheme().toLower()); + if (scheme == QLatin1String("qrc")) { + if (url.authority().isEmpty()) + return QLatin1Char(':') + url.path(); + return QString(); + } + +#if defined(Q_OS_ANDROID) + if (scheme == QLatin1String("assets")) { + if (url.authority().isEmpty()) + return url.toString(); + return QString(); + } +#endif + + return url.toLocalFile(); +} + +QT_END_NAMESPACE diff --git a/src/Runtime/api/studio3d/studioutils_p.h b/src/Runtime/api/studio3d/studioutils_p.h new file mode 100644 index 00000000..afec688c --- /dev/null +++ b/src/Runtime/api/studio3d/studioutils_p.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtStudio3D API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#include "qstudio3dglobal.h" + +#include <QtCore/QUrl> + +QT_BEGIN_NAMESPACE + +class Q_STUDIO3D_EXPORT Q3DSUtils +{ +public: + static QString urlToLocalFileOrQrc(const QUrl &url); +}; + +QT_END_NAMESPACE diff --git a/src/Runtime/api/studio3d/viewerqmlstreamproxy.cpp b/src/Runtime/api/studio3d/viewerqmlstreamproxy.cpp new file mode 100644 index 00000000..520dc8c6 --- /dev/null +++ b/src/Runtime/api/studio3d/viewerqmlstreamproxy.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "viewerqmlstreamproxy_p.h" + +QT_BEGIN_NAMESPACE + +ViewerQmlStreamProxy::ViewerQmlStreamProxy(QObject *parent) + : Q3DSQmlStreamProxy(parent) +{ +} + +ViewerQmlStreamProxy::~ViewerQmlStreamProxy() +{ +} + +void ViewerQmlStreamProxy::visit(const char *path) +{ + setPath(QLatin1String(path)); +} + +void ViewerQmlStreamProxy::visit(const char *type, const char *id, const char *src, + const char *args) +{ + Q_UNUSED(src); + QString assetType = QLatin1String(type); + QString presentationId = QLatin1String(id); + QString presentationArgs = QLatin1String(args); + if (assetType == QLatin1String("presentation-qml")) + registerPresentation(presentationId, presentationArgs); +} + +QT_END_NAMESPACE diff --git a/src/Runtime/api/studio3d/viewerqmlstreamproxy_p.h b/src/Runtime/api/studio3d/viewerqmlstreamproxy_p.h new file mode 100644 index 00000000..16569c1c --- /dev/null +++ b/src/Runtime/api/studio3d/viewerqmlstreamproxy_p.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtStudio3D API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#include "qstudio3dglobal.h" +#include "q3dsqmlstreamproxy.h" +#include "Qt3DSViewerApp.h" + +QT_BEGIN_NAMESPACE + +class Q_STUDIO3D_EXPORT ViewerQmlStreamProxy : public Q3DSQmlStreamProxy, + public qt3ds::Qt3DSAssetVisitor +{ +public: + ViewerQmlStreamProxy(QObject *parent = nullptr); + ~ViewerQmlStreamProxy(); + + void visit(const char *path) override; + void visit(const char *type, const char *id, const char *src, const char *args) override; +}; + +QT_END_NAMESPACE diff --git a/src/Runtime/api/studio3dqml/q3dsplugin.cpp b/src/Runtime/api/studio3dqml/q3dsplugin.cpp new file mode 100644 index 00000000..aa558775 --- /dev/null +++ b/src/Runtime/api/studio3dqml/q3dsplugin.cpp @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (c) 2016 NVIDIA CORPORATION. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "q3dsplugin.h" + +#include <QtQml/qqml.h> + +#include <QtStudio3D/private/q3dsviewersettings_p.h> + +#include "q3dsstudio3d.h" +#include "q3dspresentationitem.h" +#include "q3dsqmlstream.h" +#include "q3dsqmlsubpresentationsettings.h" +#include "q3dssceneelement.h" +#include "q3dsdatainput.h" + +QT_BEGIN_NAMESPACE + +void Q3DSPlugin::registerTypes(const char *uri) +{ + Q_ASSERT(uri == QLatin1String("QtStudio3D.OpenGL")); + + // @uri QtStudio3D.OpenGL + qmlRegisterType<Q3DSStudio3D>(uri, 2, 4, "Studio3D"); + qmlRegisterType<Q3DSViewerSettings>(uri, 2, 4, "ViewerSettings"); + qmlRegisterType<Q3DSPresentationItem>(uri, 2, 4, "Presentation"); + qmlRegisterType<Q3DSSceneElement>(uri, 2, 4, "SceneElement"); + qmlRegisterType<Q3DSElement>(uri, 2, 4, "Element"); + qmlRegisterType<Q3DSQmlStream>(uri, 2, 4, "QmlStream"); + qmlRegisterType<Q3DSSubPresentationSettings>(uri, 2, 4, "SubPresentationSettings"); + qmlRegisterType<Q3DSDataInput>(uri, 2, 4, "DataInput"); +} + +QT_END_NAMESPACE diff --git a/src/Runtime/api/studio3dqml/q3dsplugin.h b/src/Runtime/api/studio3dqml/q3dsplugin.h new file mode 100644 index 00000000..999a0659 --- /dev/null +++ b/src/Runtime/api/studio3dqml/q3dsplugin.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (c) 2016 NVIDIA CORPORATION. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef Q3DS_PLUGIN_H +#define Q3DS_PLUGIN_H + +#include <QtQml/qqmlextensionplugin.h> + +static void initResources() +{ +#ifdef QT_STATIC + Q_INIT_RESOURCE(qmake_QtStudio3D); +#endif +} + +QT_BEGIN_NAMESPACE + +class Q3DSPlugin : public QQmlExtensionPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + +public: + Q3DSPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) + { + initResources(); + } + void registerTypes(const char *uri) override; +}; + +QT_END_NAMESPACE + +#endif // Q3DS_PLUGIN_H diff --git a/src/Runtime/api/studio3dqml/q3dspresentationitem.cpp b/src/Runtime/api/studio3dqml/q3dspresentationitem.cpp new file mode 100644 index 00000000..6c4c8e36 --- /dev/null +++ b/src/Runtime/api/studio3dqml/q3dspresentationitem.cpp @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "q3dspresentationitem.h" + +#include <QtStudio3D/q3dssceneelement.h> +#include <QtStudio3D/q3dsdatainput.h> +#include <QtStudio3D/private/q3dspresentation_p.h> +#include <QtStudio3D/private/viewerqmlstreamproxy_p.h> +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +Q3DSPresentationItem::Q3DSPresentationItem(QObject *parent) + : Q3DSPresentation(parent) + , m_subPresentationSettings(nullptr) +{ +} + +Q3DSPresentationItem::~Q3DSPresentationItem() +{ +} + +Q3DSSubPresentationSettings *Q3DSPresentationItem::subPresentationSettings() const +{ + return m_subPresentationSettings; +} + +QQmlListProperty<QObject> Q3DSPresentationItem::qmlChildren() +{ + return QQmlListProperty<QObject>(this, nullptr, &appendQmlChildren, nullptr, nullptr, nullptr); +} + +void Q3DSPresentationItem::appendQmlChildren(QQmlListProperty<QObject> *list, QObject *obj) +{ + auto item = qobject_cast<Q3DSPresentationItem *>(list->object); + if (item) { + auto scene = qobject_cast<Q3DSSceneElement *>(obj); + if (scene) { + if (item->registeredElement(scene->elementPath())) + qWarning() << __FUNCTION__ << "A duplicate SceneElement defined for Presentation."; + else + item->registerElement(scene); + } else { + auto studioElement = qobject_cast<Q3DSElement *>(obj); + if (studioElement) { + if (item->registeredElement(studioElement->elementPath())) + qWarning() << __FUNCTION__ << "A duplicate Element defined for Presentation."; + else + item->registerElement(studioElement); + } else { + auto subPresSettings = qobject_cast<Q3DSSubPresentationSettings *>(obj); + if (subPresSettings) { + if (item->m_subPresentationSettings) { + qWarning() << __FUNCTION__ + << "Duplicate SubPresentationSettings defined for Presentation."; + } else { + item->m_subPresentationSettings = subPresSettings; + item->d_ptr->streamProxy()->setSettings(subPresSettings); + } + } else { + auto dataInput = qobject_cast<Q3DSDataInput *>(obj); + if (item->registeredDataInput(dataInput->name())) { + qWarning() << __FUNCTION__ + << "Duplicate DataInput defined for Presentation."; + } else { + item->registerDataInput(dataInput); + } + } + } + } + } +} + + +QT_END_NAMESPACE diff --git a/src/Runtime/api/studio3dqml/q3dspresentationitem.h b/src/Runtime/api/studio3dqml/q3dspresentationitem.h new file mode 100644 index 00000000..3ee2964f --- /dev/null +++ b/src/Runtime/api/studio3dqml/q3dspresentationitem.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef Q3DSPRESENTATIONITEM_H +#define Q3DSPRESENTATIONITEM_H + +#include "q3dsqmlsubpresentationsettings.h" + +#include <QtStudio3D/q3dspresentation.h> +#include <QtQml/qqmllist.h> + +QT_BEGIN_NAMESPACE + +class Q3DSPresentationItem : public Q3DSPresentation +{ + Q_OBJECT + Q_PROPERTY(QQmlListProperty<QObject> qmlChildren READ qmlChildren DESIGNABLE false) + Q_PROPERTY(Q3DSSubPresentationSettings *subPresentationSettings READ subPresentationSettings CONSTANT) + Q_CLASSINFO("DefaultProperty", "qmlChildren") + +public: + explicit Q3DSPresentationItem(QObject *parent = nullptr); + ~Q3DSPresentationItem(); + + Q3DSSubPresentationSettings *subPresentationSettings() const; + + QQmlListProperty<QObject> qmlChildren(); + +public Q_SLOTS: + static void appendQmlChildren(QQmlListProperty<QObject> *list, QObject *obj); + +private: + Q3DSSubPresentationSettings *m_subPresentationSettings; + + friend class Q3DSStudio3D; +}; + +QT_END_NAMESPACE + +#endif // Q3DSPRESENTATIONITEM_H diff --git a/src/Runtime/api/studio3dqml/q3dsrenderer.cpp b/src/Runtime/api/studio3dqml/q3dsrenderer.cpp new file mode 100644 index 00000000..7e063ab4 --- /dev/null +++ b/src/Runtime/api/studio3dqml/q3dsrenderer.cpp @@ -0,0 +1,400 @@ +/**************************************************************************** +** +** Copyright (c) 2016 NVIDIA CORPORATION. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "q3dsrenderer.h" +#include "Qt3DSViewerApp.h" +#include "Qt3DSAudioPlayerImpl.h" +#include "q3dspresentationitem.h" + +#include <QtStudio3D/private/q3dscommandqueue_p.h> +#include <QtStudio3D/private/q3dsviewersettings_p.h> +#include <QtStudio3D/private/q3dspresentation_p.h> +#include <QtStudio3D/private/studioutils_p.h> + +#include <QtCore/qdebug.h> +#include <QtGui/qwindow.h> +#include <QtGui/qopenglcontext.h> +#include <QtQuick/qquickwindow.h> + +using namespace Q3DSViewer; + +QT_BEGIN_NAMESPACE + +Q3DSRenderer::Q3DSRenderer(bool visibleFlag, qt3ds::Qt3DSAssetVisitor *assetVisitor) + : m_visibleFlag(visibleFlag) + , m_initElements(false) + , m_runtime(0) + , m_window(nullptr) + , m_initialized(false) + , m_initializationFailure(false) + , m_visitor(assetVisitor) + , m_settings(new Q3DSViewerSettings(this)) + , m_presentation(new Q3DSPresentation(this)) +{ + m_startupTimer.start(); +} + +Q3DSRenderer::~Q3DSRenderer() +{ + releaseRuntime(); +} + +QOpenGLFramebufferObject *Q3DSRenderer::createFramebufferObject(const QSize &size) +{ + QOpenGLFramebufferObjectFormat theFormat; + theFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); + QOpenGLFramebufferObject *frameBuffer = + new QOpenGLFramebufferObject(size, theFormat); + if (m_runtime && m_runtime->IsInitialised()) + m_runtime->setOffscreenId(frameBuffer->handle()); + return frameBuffer; +} + +/** Pull pending commands from the plugin. + * Invoked automatically by the QML scene graph. + * + * This is the only place where it is valid for the Q3DSStudio3D plugin and render to communicate. + */ +void Q3DSRenderer::synchronize(QQuickFramebufferObject *inView) +{ + // Passing m_InitElements here is a bit of a hack to easily set the flag on the plugin. + static_cast<Q3DSStudio3D *>(inView)->getCommands(m_initElements, m_commands); + + if (m_initializationFailure) + static_cast<Q3DSStudio3D *>(inView)->setError(m_error); + + if (m_commands.m_sourceChanged || m_commands.m_variantListChanged) { + releaseRuntime(); + // Need to update source and variant list here rather than + // processCommands, as both are needed for init + m_presentation->setVariantList(m_commands.m_variantList); + m_presentation->setSource(m_commands.m_source); + m_presentation->setDelayedLoading(m_commands.m_delayedLoading); + m_initialized = false; + m_initializationFailure = false; + m_error.clear(); + static_cast<Q3DSStudio3D *>(inView)->setError(QString()); + } + + m_initElements = false; + + // We need a handle to the window to be able to reset the GL state inside of Draw(). + // See https://bugreports.qt.io/browse/QTBUG-47213 + if (!m_window) + m_window = inView->window(); +} + +void Q3DSRenderer::releaseRuntime() +{ + m_settings->d_ptr->setViewerApp(nullptr); + m_presentation->d_ptr->setViewerApp(nullptr); + + if (m_runtime) { + m_runtime->Release(); + m_runtime = nullptr; + } +} + +/** Invoked by the QML scene graph indicating that it's time to render. + * Calls `draw()` if the plugin is visible, or `processCommands()` otherwise. + * + * Note that this will still render if the plugin is opacity:0. To avoid this, + * add a line to your QML to hide the object when opacity is zero, like: + * + * visible: opacity != 0 + */ +void Q3DSRenderer::render() +{ + // We may start in a non visible state but we still need + // to init the runtime otherwise the commands are never processed + if (!m_initialized && !m_initializationFailure) { + m_initialized = initializeRuntime(this->framebufferObject()); + m_initializationFailure = !m_initialized; + if (m_initializationFailure) + m_commands.clear(true); + } + + // Don't render if the plugin is hidden; however, if hidden, but sure + // to process pending commands so we can be shown again. + if (m_initialized) { + if (m_visibleFlag) + draw(); + else + processCommands(); + update(); // mark as dirty to ensure update again + } +} + +/** Cause Qt3DS runtime to render content. + * Initializes GL and the runtime when called the first time. + */ +void Q3DSRenderer::draw() +{ + if (m_runtime && m_runtime->IsInitialised() && m_window) { + if (m_initialized) + m_runtime->RestoreState(); + m_runtime->Render(); + m_runtime->SaveState(); + + m_window->resetOpenGLState(); + } +} + +bool Q3DSRenderer::initializeRuntime(QOpenGLFramebufferObject *inFbo) +{ + m_runtime = &Q3DSViewerApp::Create(nullptr, new Qt3DSAudioPlayerImpl(), &m_startupTimer); + Q_ASSERT(m_runtime); + + // Connect presentation ready signal before initializing the app + connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigPresentationReady, + this, &Q3DSRenderer::presentationReady); + connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigPresentationLoaded, + this, &Q3DSRenderer::presentationLoaded); + + int theWidth = inFbo->width(); + int theHeight = inFbo->height(); + + const QString localSource = Q3DSUtils::urlToLocalFileOrQrc(m_presentation->source()); + + if (!m_runtime->InitializeApp(theWidth, theHeight, + QOpenGLContext::currentContext()->format(), + inFbo->handle(), localSource, + m_presentation->variantList(), + m_presentation->delayedLoading(), + m_visitor)) { + m_error = m_runtime->error(); + releaseRuntime(); + return false; + } + + m_runtime->RegisterScriptCallback(Q3DSViewer::ViewerCallbackType::Enum::CALLBACK_ON_INIT, + reinterpret_cast<qml_Function>(Q3DSRenderer::onInitHandler), + this); + m_runtime->RegisterScriptCallback(Q3DSViewer::ViewerCallbackType::Enum::CALLBACK_ON_UPDATE, + reinterpret_cast<qml_Function>(Q3DSRenderer::onUpdateHandler), + this); + + m_settings->d_ptr->setViewerApp(m_runtime); + m_presentation->d_ptr->setViewerApp(m_runtime, false); + + // Connect signals + connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigSlideEntered, + this, &Q3DSRenderer::enterSlide); + connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigSlideExited, + this, &Q3DSRenderer::exitSlide); + connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigCustomSignal, + this, &Q3DSRenderer::customSignalEmitted); + connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigElementCreated, + this, &Q3DSRenderer::elementCreated); + connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigMaterialCreated, + this, &Q3DSRenderer::materialCreated); + + return true; +} + +/** Accept user commands (e.g. setAttribute) needed to initialize the code. + * + * If we attempt to run Qt3DS methods like setAttribute() before the runtime + * has been initialized, they will be lost. This method is the correct place + * to accept user commands. + * + * Currently this method just sets a flag needed to pass a flag to the + * plugin next time syncronize() is called, which eventually gets the plugin + * to emit an `runningChanged` signal the next time `tick()` is called. + * As a result, code specified in an `onRunningChanged` handler may be run + * after one or more frames have already rendered. + */ +void Q3DSRenderer::onInitHandler(void *userData) +{ + Q3DSRenderer *theRenderer = static_cast<Q3DSRenderer *>(userData); + theRenderer->setInitElements(true); +} + +/** Accept the latest pending user commands (e.g. setAttribute). + * + * This method just calls `ProcessCommands` to avoid unnecessary + * pointer dereferencing and accessor methods (or public member variables). + */ +void Q3DSRenderer::onUpdateHandler(void *userData) +{ + Q3DSRenderer *theRenderer = static_cast<Q3DSRenderer *>(userData); + theRenderer->processCommands(); +} + +/** Apply commands queued up by the user (e.g. setAttribute). + * + * Note that these commands are executed even if the plugin is not visible, + * in part to allow changes to the visible flag to be noticed, but also + * to allow specialty code to continue to be queued up even when not rendering. + */ +void Q3DSRenderer::processCommands() +{ + if (!m_runtime) { + m_commands.clear(true); + return; + } + + if (m_commands.m_visibleChanged) + m_visibleFlag = m_commands.m_visible; + + if (QOpenGLFramebufferObject *inFbo = this->framebufferObject()) { + if (inFbo->isValid() && (inFbo->width() != m_runtime->GetWindowWidth() + || inFbo->height() != m_runtime->GetWindowHeight())) { + m_runtime->Resize(inFbo->width(), inFbo->height()); + } + } + + if (m_commands.m_scaleModeChanged) + m_settings->setScaleMode(m_commands.m_scaleMode); + if (m_commands.m_shadeModeChanged) + m_settings->setShadeMode(m_commands.m_shadeMode); + if (m_commands.m_matteColorChanged) + m_settings->setMatteColor(m_commands.m_matteColor); + if (m_commands.m_showRenderStatsChanged) + m_settings->setShowRenderStats(m_commands.m_showRenderStats); + if (m_commands.m_delayedLoadingChanged) + this->m_runtime->setDelayedLoading(m_commands.m_delayedLoading); + + if (m_commands.m_globalAnimationTimeChanged) + m_presentation->setGlobalAnimationTime(m_commands.m_globalAnimationTime); + + // Send scene graph changes over to Q3DS + for (int i = 0; i < m_commands.size(); i++) { + const ElementCommand &cmd = m_commands.constCommandAt(i); + switch (cmd.m_commandType) { + case CommandType_SetAttribute: + m_presentation->setAttribute(cmd.m_elementPath, cmd.m_stringValue, cmd.m_variantValue); + break; + case CommandType_SetPresentationActive: + m_presentation->setPresentationActive(cmd.m_elementPath, cmd.m_boolValue); + break; + case CommandType_GoToTime: + m_presentation->goToTime(cmd.m_elementPath, cmd.m_floatValue); + break; + case CommandType_GoToSlide: + m_presentation->goToSlide(cmd.m_elementPath, cmd.m_intValues[0]); + break; + case CommandType_GoToSlideByName: + m_presentation->goToSlide(cmd.m_elementPath, cmd.m_stringValue); + break; + case CommandType_GoToSlideRelative: + m_presentation->goToSlide(cmd.m_elementPath, bool(cmd.m_intValues[0]), + bool(cmd.m_intValues[1])); + break; + case CommandType_FireEvent: + m_presentation->fireEvent(cmd.m_elementPath, cmd.m_stringValue); + break; + case CommandType_MousePress: + m_runtime->HandleMousePress(cmd.m_intValues[0], + cmd.m_intValues[1], cmd.m_intValues[2], true); + break; + case CommandType_MouseRelease: + m_runtime->HandleMousePress(cmd.m_intValues[0], + cmd.m_intValues[1], cmd.m_intValues[2], false); + break; + case CommandType_MouseMove: + m_runtime->HandleMouseMove(cmd.m_intValues[0], cmd.m_intValues[1], true); + break; + case CommandType_MouseWheel: + m_runtime->HandleMouseWheel(cmd.m_intValues[0], cmd.m_intValues[1], + bool(cmd.m_intValues[2]), cmd.m_intValues[3]); + break; + case CommandType_KeyPress: + m_runtime->HandleKeyInput(Q3DStudio::EKeyCode(cmd.m_intValues[0]), true); + break; + case CommandType_KeyRelease: + m_runtime->HandleKeyInput(Q3DStudio::EKeyCode(cmd.m_intValues[0]), false); + break; + case CommandType_SetDataInputValue: + m_runtime->SetDataInputValue( + cmd.m_stringValue, cmd.m_variantValue, + static_cast<qt3ds::runtime::DataInputValueRole>(cmd.m_intValues[0])); + break; + case CommandType_CreateElement: { + m_runtime->createElement(cmd.m_elementPath, cmd.m_stringValue, + *static_cast<QHash<QString, QVariant> *>(cmd.m_data)); + // Runtime makes copy of the data in its own format, so we can delete it now + auto &command = m_commands.commandAt(i); + delete reinterpret_cast<QHash<QString, QVariant> *>(command.m_data); + command.m_data = nullptr; + break; + } + case CommandType_DeleteElement: { + m_runtime->deleteElement(cmd.m_elementPath); + break; + } + case CommandType_CreateMaterial: { + m_runtime->createMaterial(cmd.m_elementPath, cmd.m_stringValue); + break; + } + case CommandType_RequestSlideInfo: { + int current = 0; + int previous = 0; + QString currentName; + QString previousName; + const QByteArray path(cmd.m_elementPath.toUtf8()); + m_runtime->GetSlideInfo(path, current, previous, currentName, previousName); + QVariantList *requestData = new QVariantList(); + requestData->append(QVariant(current)); + requestData->append(QVariant(previous)); + requestData->append(QVariant(currentName)); + requestData->append(QVariant(previousName)); + + Q_EMIT requestResponse(cmd.m_elementPath, cmd.m_commandType, requestData); + + break; + } + case CommandType_RequestDataInputs: { + QVariantList *requestData = new QVariantList(); + if (m_presentation) { + const auto diList = m_presentation->dataInputs(); + + for (const auto &it : diList) + requestData->append(QVariant::fromValue(it->name())); + } + + Q_EMIT requestResponse(cmd.m_elementPath, cmd.m_commandType, requestData); + break; + } + case CommandType_PreloadSlide: + m_runtime->preloadSlide(cmd.m_elementPath); + break; + case CommandType_UnloadSlide: + m_runtime->unloadSlide(cmd.m_elementPath); + break; + default: + qWarning() << __FUNCTION__ << "Unrecognized CommandType in command list!"; + } + } + + m_commands.clear(false); +} + +QT_END_NAMESPACE diff --git a/src/Runtime/api/studio3dqml/q3dsrenderer.h b/src/Runtime/api/studio3dqml/q3dsrenderer.h new file mode 100644 index 00000000..12f98aef --- /dev/null +++ b/src/Runtime/api/studio3dqml/q3dsrenderer.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (c) 2016 NVIDIA CORPORATION. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef Q3DS_RENDERER_H +#define Q3DS_RENDERER_H + +#include <QtGui/qopenglframebufferobject.h> +#include <QtQuick/qquickframebufferobject.h> + +#include "Qt3DSViewerApp.h" +#include "q3dsstudio3d.h" + +QT_BEGIN_NAMESPACE + +class Q3DSViewerSettings; +class Q3DSPresentation; + +class Q3DSRenderer : public QObject, + public QQuickFramebufferObject::Renderer +{ + Q_OBJECT + +public: + Q3DSRenderer(bool visibleFlag, qt3ds::Qt3DSAssetVisitor *assetVisitor); + ~Q3DSRenderer(); + + QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) override; + + void setInitElements(bool inFlag) { m_initElements = inFlag; } + void processCommands(); + +Q_SIGNALS: + void enterSlide(const QString &elementPath, unsigned int slide, const QString &slideName); + void exitSlide(const QString &elementPath, unsigned int slide, const QString &slideName); + void requestResponse(const QString &elementPath, CommandType commandType, void *requestData); + void presentationReady(); + void presentationLoaded(); + void customSignalEmitted(const QString &elNmentPath, const QString &name); + void elementCreated(const QString &elementName, const QString &error); + void materialCreated(const QString &name, const QString &error); + +protected: + static void onInitHandler(void *userData); + static void onUpdateHandler(void *userData); + bool initializeRuntime(QOpenGLFramebufferObject *inFbo); + void draw(); + void render() override; + void synchronize(QQuickFramebufferObject *inView) override; + void releaseRuntime(); + +protected: + bool m_visibleFlag; // Is the plugin visible? Prevents rendering hidden content. + CommandQueue m_commands; // A list of commands retrieved by the plugin to be applied. + bool m_initElements; // Flag set when the runtime is first ready to render. + Q3DSViewer::Q3DSViewerApp *m_runtime; // The Qt3DS viewer that renders all content. + QQuickWindow *m_window; // Window associated with the plugin; needed to reset OpenGL state. + + bool m_initialized; // Has the runtime and OpenGL state been initialized? + bool m_initializationFailure; // Initialization failed, no point in trying to init again + qt3ds::Qt3DSAssetVisitor *m_visitor; + + Q3DSViewerSettings *m_settings; + Q3DSPresentation *m_presentation; + QString m_error; + QElapsedTimer m_startupTimer; +}; + +QT_END_NAMESPACE + +#endif // Q3DS_RENDERER_H diff --git a/src/Runtime/api/studio3dqml/q3dsstudio3d.cpp b/src/Runtime/api/studio3dqml/q3dsstudio3d.cpp new file mode 100644 index 00000000..2a6c7be2 --- /dev/null +++ b/src/Runtime/api/studio3dqml/q3dsstudio3d.cpp @@ -0,0 +1,326 @@ +/**************************************************************************** +** +** Copyright (c) 2016 NVIDIA CORPORATION. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "q3dsstudio3d.h" +#include "q3dsrenderer.h" +#include "q3dspresentationitem.h" + +#include <QtStudio3D/private/q3dsviewersettings_p.h> +#include <QtStudio3D/private/q3dspresentation_p.h> +#include <QtStudio3D/private/q3dssceneelement_p.h> +#include <QtStudio3D/private/viewerqmlstreamproxy_p.h> + +#include <QtCore/qdebug.h> +#include <QtCore/qfileinfo.h> +#include <QtQuick/qquickwindow.h> + +QT_BEGIN_NAMESPACE + +Q3DSStudio3D::Q3DSStudio3D() + : m_viewerSettings(nullptr) + , m_presentation(nullptr) + , m_emitRunningChange(false) + , m_isRunning(false) + , m_ignoreMouseEvents(false) + , m_ignoreWheelEvents(false) + , m_ignoreKeyboardEvents(false) + , m_pixelRatio(1.0) +{ + setMirrorVertically(true); + connect(this, &Q3DSStudio3D::windowChanged, this, &Q3DSStudio3D::handleWindowChanged); + connect(this, &Q3DSStudio3D::visibleChanged, this, &Q3DSStudio3D::handleVisibleChanged); + + setIgnoreEvents(false, false, false); +} + +Q3DSStudio3D::~Q3DSStudio3D() +{ +} + +Q3DSPresentationItem *Q3DSStudio3D::presentation() const +{ + return m_presentation; +} + +Q3DSViewerSettings *Q3DSStudio3D::viewerSettings() const +{ + return m_viewerSettings; +} + +QString Q3DSStudio3D::error() const +{ + return m_error; +} + +void Q3DSStudio3D::setError(const QString &error) +{ + if (error != m_error) { + m_error = error; + Q_EMIT errorChanged(m_error); + } +} + +void Q3DSStudio3D::setIgnoreEvents(bool mouse, bool wheel, bool keyboard) +{ + // TODO: It might be beneficial to have these as properties so they could be acceessed from QML + m_ignoreMouseEvents = mouse; + m_ignoreWheelEvents = wheel; + m_ignoreKeyboardEvents = keyboard; + + if (mouse) + setAcceptedMouseButtons(Qt::NoButton); + else + setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton | Qt::MiddleButton); + setAcceptHoverEvents(!mouse); +} + +void Q3DSStudio3D::componentComplete() +{ + const auto childObjs = children(); + for (QObject *child : childObjs) { + auto settings = qobject_cast<Q3DSViewerSettings *>(child); + if (settings) { + if (m_viewerSettings) + qWarning("Duplicate ViewerSettings defined for Studio3D."); + else + m_viewerSettings = settings; + } + auto presentation = qobject_cast<Q3DSPresentationItem *>(child); + if (presentation) { + if (m_presentation) + qWarning("Duplicate Presentation defined for Studio3D."); + else + m_presentation = presentation; + } + } + if (!m_viewerSettings) + m_viewerSettings = new Q3DSViewerSettings(this); + if (!m_presentation) + m_presentation = new Q3DSPresentationItem(this); + + m_viewerSettings->d_ptr->setCommandQueue(&m_pendingCommands); + m_presentation->d_ptr->setCommandQueue(&m_pendingCommands); + + // Ensure qml stream proxy gets created on main thread + m_presentation->d_ptr->streamProxy(); + + QQuickFramebufferObject::componentComplete(); +} + +void Q3DSStudio3D::handleWindowChanged(QQuickWindow *window) +{ + if (!window) + return; + + window->setClearBeforeRendering(false); + m_pixelRatio = window->devicePixelRatio(); + + // Call tick every frame of the GUI thread to notify QML about new frame via frameUpdate signal + connect(window, &QQuickWindow::afterAnimating, this, &Q3DSStudio3D::tick); + // Call update after the frame is handled to queue another frame + connect(window, &QQuickWindow::afterSynchronizing, this, &Q3DSStudio3D::update); +} + +// Queue up a command to inform the renderer of a newly-changed visible/hidden status. +void Q3DSStudio3D::handleVisibleChanged() +{ + m_pendingCommands.m_visibleChanged = true; + m_pendingCommands.m_visible = isVisible(); +} + +void Q3DSStudio3D::reset() +{ + // Fake a source change to trigger a reloading of the presentation + m_pendingCommands.m_sourceChanged = true; + m_pendingCommands.m_source = m_presentation->source(); + m_pendingCommands.m_variantListChanged = true; + m_pendingCommands.m_variantList = m_presentation->variantList(); +} + +void Q3DSStudio3D::requestResponseHandler(const QString &elementPath, CommandType commandType, + void *requestData) +{ + switch (commandType) { + case CommandType_RequestSlideInfo: { + Q3DSSceneElement *handler = qobject_cast<Q3DSSceneElement *>( + m_presentation->registeredElement(elementPath)); + if (handler) + handler->d_ptr->requestResponseHandler(commandType, requestData); + else + qWarning() << __FUNCTION__ << "RequestSlideInfo response got for unregistered scene."; + break; + } + case CommandType_RequestDataInputs: { + Q3DSPresentation *handler = qobject_cast<Q3DSPresentation *>(m_presentation); + if (handler) { + handler->d_ptr->requestResponseHandler(commandType, requestData); + } else { + qWarning() << __FUNCTION__ + << "RequestDataInputs response got for invalid presentation."; + } + break; + } + default: + qWarning() << __FUNCTION__ << "Unknown command type."; + break; + } +} + +// Create the Q3DSRenderer. Invoked automatically by the QML scene graph. +QQuickFramebufferObject::Renderer *Q3DSStudio3D::createRenderer() const +{ + // It is "illegal" to create a connection between the renderer + // and the plugin, and vice-versa. The only valid time the two + // may communicate is during Q3DSRenderer::synchronize(). + Q3DSRenderer *renderer = new Q3DSRenderer(isVisible(), m_presentation->d_ptr->streamProxy()); + + connect(renderer, &Q3DSRenderer::enterSlide, + m_presentation->d_ptr, &Q3DSPresentationPrivate::handleSlideEntered); + connect(renderer, &Q3DSRenderer::exitSlide, + m_presentation, &Q3DSPresentation::slideExited); + connect(renderer, &Q3DSRenderer::customSignalEmitted, + m_presentation, &Q3DSPresentation::customSignalEmitted); + connect(renderer, &Q3DSRenderer::elementCreated, + m_presentation, &Q3DSPresentation::elementCreated); + connect(renderer, &Q3DSRenderer::materialCreated, + m_presentation, &Q3DSPresentation::materialCreated); + connect(renderer, &Q3DSRenderer::requestResponse, + this, &Q3DSStudio3D::requestResponseHandler); + connect(renderer, &Q3DSRenderer::presentationLoaded, + this, &Q3DSStudio3D::presentationLoaded); + connect(renderer, &Q3DSRenderer::presentationReady, + this, &Q3DSStudio3D::presentationReady); + return renderer; +} + +bool Q3DSStudio3D::isRunning() const +{ + return m_isRunning; +} + +/** Emit QML `runningChanged` and `frameUpdate` and signals. + * This method is called every frame, and emits the `frameUpdate` signal every frame, + * regardless of plugin visibility. This allows a hidden Qt3DSView to still process + * information every frame, even though the Renderer is not rendering. + * + * To prevent expensive onFrameUpdate handlers from being processed when hidden, + * add an early return to the top like: + * + * onFrameUpdate: { + * if (!visible) return; + * ... + * } + */ +void Q3DSStudio3D::tick() +{ + if (m_emitRunningChange) { + m_isRunning = true; + Q_EMIT runningChanged(true); + m_emitRunningChange = false; + } + + // Don't call onFrameUpdate until after onInitialize has been called + if (m_isRunning) { + // Give QML an opportunity to change Qt3DS values every frame + Q_EMIT frameUpdate(); + } +} + +// Copies the list of commands previously queued up. Called by Q3DSRenderer::synchronize(). +void Q3DSStudio3D::getCommands(bool emitInitialize, CommandQueue &renderQueue) +{ + if (emitInitialize) + m_emitRunningChange = true; + + renderQueue.copyCommands(m_pendingCommands); + m_pendingCommands.clear(false); +} + +void Q3DSStudio3D::mousePressEvent(QMouseEvent *event) +{ + if (!m_ignoreMouseEvents) { + if (m_pixelRatio != 1.0) { + QMouseEvent scaledEvent(event->type(), event->pos() * m_pixelRatio, + event->button(), event->buttons(), event->modifiers()); + m_presentation->mousePressEvent(&scaledEvent); + } else { + m_presentation->mousePressEvent(event); + } + } +} + +void Q3DSStudio3D::mouseReleaseEvent(QMouseEvent *event) +{ + if (!m_ignoreMouseEvents) { + if (m_pixelRatio != 1.0) { + QMouseEvent scaledEvent(event->type(), event->pos() * m_pixelRatio, + event->button(), event->buttons(), event->modifiers()); + m_presentation->mouseReleaseEvent(&scaledEvent); + } else { + m_presentation->mouseReleaseEvent(event); + } + } +} + +void Q3DSStudio3D::mouseMoveEvent(QMouseEvent *event) +{ + if (!m_ignoreMouseEvents) { + if (m_pixelRatio != 1.0) { + QMouseEvent scaledEvent(event->type(), event->pos() * m_pixelRatio, + event->button(), event->buttons(), event->modifiers()); + m_presentation->mouseMoveEvent(&scaledEvent); + } else { + m_presentation->mouseMoveEvent(event); + } + } +} + +void Q3DSStudio3D::wheelEvent(QWheelEvent *event) +{ + if (!m_ignoreWheelEvents) + m_presentation->wheelEvent(event); +} + +void Q3DSStudio3D::keyPressEvent(QKeyEvent *event) +{ + if (m_ignoreKeyboardEvents) + return; + m_presentation->keyPressEvent(event); +} + +void Q3DSStudio3D::keyReleaseEvent(QKeyEvent *event) +{ + if (m_ignoreKeyboardEvents) + return; + if (!event->isAutoRepeat()) + m_presentation->keyReleaseEvent(event); +} + +QT_END_NAMESPACE diff --git a/src/Runtime/api/studio3dqml/q3dsstudio3d.h b/src/Runtime/api/studio3dqml/q3dsstudio3d.h new file mode 100644 index 00000000..484e9f65 --- /dev/null +++ b/src/Runtime/api/studio3dqml/q3dsstudio3d.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (c) 2016 NVIDIA CORPORATION. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef Q3DS_STUDIO3D_H +#define Q3DS_STUDIO3D_H + +#include <QtStudio3D/private/q3dscommandqueue_p.h> +#include <QtGui/qopenglframebufferobject.h> +#include <QtQuick/qquickframebufferobject.h> + +QT_BEGIN_NAMESPACE + +class Q3DSRenderer; +class Q3DSViewerSettings; +class Q3DSPresentationItem; + +class Q3DSStudio3D : public QQuickFramebufferObject +{ + Q_OBJECT + Q_PROPERTY(bool running READ isRunning NOTIFY runningChanged) + Q_PROPERTY(Q3DSPresentationItem *presentation READ presentation CONSTANT) + Q_PROPERTY(Q3DSViewerSettings *viewerSettings READ viewerSettings CONSTANT) + Q_PROPERTY(QString error READ error NOTIFY errorChanged) + +public: + Q3DSStudio3D(); + virtual ~Q3DSStudio3D(); + + QQuickFramebufferObject::Renderer *createRenderer() const override; + + bool isRunning() const; + Q3DSPresentationItem *presentation() const; + Q3DSViewerSettings *viewerSettings() const; + QString error() const; + void setError(const QString &error); + + void getCommands(bool emitInitialize, CommandQueue &renderQueue); + + void mousePressEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void wheelEvent(QWheelEvent *event) override; + void keyPressEvent(QKeyEvent *event) override; + void keyReleaseEvent(QKeyEvent *event) override; + + void setIgnoreEvents(bool mouse, bool wheel, bool keyboard); + + void componentComplete() override; + +Q_SIGNALS: + void frameUpdate(); + void runningChanged(bool initialized); + void errorChanged(const QString &error); + void presentationReady(); + void presentationLoaded(); + +public Q_SLOTS: + void reset(); + +protected Q_SLOTS: + void handleWindowChanged(QQuickWindow *window); + void handleVisibleChanged(); + void tick(); + void requestResponseHandler(const QString &elementPath, CommandType commandType, + void *requestData); + +protected: + Q3DSViewerSettings *m_viewerSettings; + Q3DSPresentationItem *m_presentation; + + bool m_emitRunningChange; + bool m_isRunning; + bool m_ignoreMouseEvents; + bool m_ignoreWheelEvents; + bool m_ignoreKeyboardEvents; + + CommandQueue m_pendingCommands; + qreal m_pixelRatio; + QString m_error; +}; + +QT_END_NAMESPACE + +#endif // Q3DS_STUDIO3D_H diff --git a/src/Runtime/api/studio3dqml/qmldir b/src/Runtime/api/studio3dqml/qmldir new file mode 100644 index 00000000..1eaa8f2b --- /dev/null +++ b/src/Runtime/api/studio3dqml/qmldir @@ -0,0 +1,3 @@ +module QtStudio3D.OpenGL +plugin declarative_qtstudio3dopengl +classname Q3DSPlugin diff --git a/src/Runtime/api/studio3dqml/studio3dqml.pro b/src/Runtime/api/studio3dqml/studio3dqml.pro new file mode 100644 index 00000000..a7bdc392 --- /dev/null +++ b/src/Runtime/api/studio3dqml/studio3dqml.pro @@ -0,0 +1,34 @@ +include($$PWD/../../commoninclude.pri) + +QT += qml quick opengl studio3d-private +CONFIG += plugin + +qtHaveModule(multimedia) { +DEFINES += PLATFORM_HAS_QT_MULTIMEDIA_LIB +QT += multimedia +} + +TARGET = qtstudio3dopengl +TARGETPATH = QtStudio3D/OpenGL +IMPORT_VERSION = 2.4 + +SOURCES += \ + q3dsplugin.cpp \ + q3dsstudio3d.cpp \ + q3dsrenderer.cpp \ + q3dspresentationitem.cpp + +HEADERS += \ + q3dsplugin.h \ + q3dsstudio3d.h \ + q3dsrenderer.h \ + q3dspresentationitem.h + +LIBS += \ + -lqt3dsopengl$$qtPlatformTargetSuffix() \ + -lqt3dsqmlstreamer$$qtPlatformTargetSuffix() + +OTHER_FILES += \ + qmldir + +load(qml_plugin) |