diff options
author | Paul Lemire <paul.lemire@kdab.com> | 2019-08-07 07:47:31 +0200 |
---|---|---|
committer | Paul Lemire <paul.lemire@kdab.com> | 2019-08-07 08:33:30 +0200 |
commit | fd64e870fad0e619704e79689f20645760dbdc0e (patch) | |
tree | e5ef1654a217bf82f0bb3549d1c8f1762f1a9f25 | |
parent | 44470868450c440ca874ba585e2b71dfc8e89f1d (diff) | |
parent | 8af94d9a048f7d26a8137c3c51dcf47605fcf4b6 (diff) |
Merge "Merge remote-tracking branch 'qt-gerrit/dev' into wip/refactor"
64 files changed, 1342 insertions, 1716 deletions
diff --git a/src/animation/backend/animationutils.cpp b/src/animation/backend/animationutils.cpp index 29de69df6..92e614236 100644 --- a/src/animation/backend/animationutils.cpp +++ b/src/animation/backend/animationutils.cpp @@ -55,6 +55,10 @@ QT_BEGIN_NAMESPACE +namespace { +const auto slerpThreshold = 0.01f; +} + namespace Qt3DAnimation { namespace Animation { @@ -270,17 +274,38 @@ ClipResults evaluateClipAtLocalTime(AnimationClip *clip, float localTime) const int lowerKeyframeBound = channel.channelComponents[0].fcurve.lowerKeyframeBound(localTime); const auto lowerQuat = quaternionFromChannel(lowerKeyframeBound); const auto higherQuat = quaternionFromChannel(lowerKeyframeBound + 1); - const float omega = std::acos(qBound(-1.0f, QQuaternion::dotProduct(lowerQuat, higherQuat), 1.0f)); - - if (qFuzzyIsNull(omega)) { - // If the two keyframe quaternions are equal, just return the first one as the interpolated value. + auto cosHalfTheta = QQuaternion::dotProduct(lowerQuat, higherQuat); + // If the two keyframe quaternions are equal, just return the first one as the interpolated value. + if (std::abs(cosHalfTheta) >= 1.0f) { channelResults[i++] = lowerQuat.scalar(); channelResults[i++] = lowerQuat.x(); channelResults[i++] = lowerQuat.y(); channelResults[i++] = lowerQuat.z(); } else { - for (const auto &channelComponent : qAsConst(channel.channelComponents)) - channelResults[i++] = channelComponent.fcurve.evaluateAtTimeAsSlerp(localTime, lowerKeyframeBound, omega); + const auto sinHalfTheta = std::sqrt(1.0f - std::pow(cosHalfTheta,2.0f)); + if (std::abs(sinHalfTheta) < ::slerpThreshold) { + auto initial_i = i; + for (const auto &channelComponent : qAsConst(channel.channelComponents)) + channelResults[i++] = channelComponent.fcurve.evaluateAtTime(localTime, lowerKeyframeBound); + + // Normalize the resulting quaternion + QQuaternion quat{channelResults[initial_i], channelResults[initial_i+1], channelResults[initial_i+2], channelResults[initial_i+3]}; + quat.normalize(); + channelResults[initial_i+0] = quat.scalar(); + channelResults[initial_i+1] = quat.x(); + channelResults[initial_i+2] = quat.y(); + channelResults[initial_i+3] = quat.z(); + } else { + const auto reverseQ1 = cosHalfTheta < 0 ? -1.0f : 1.0f; + cosHalfTheta *= reverseQ1; + const auto halfTheta = std::acos(cosHalfTheta); + for (const auto &channelComponent : qAsConst(channel.channelComponents)) + channelResults[i++] = channelComponent.fcurve.evaluateAtTimeAsSlerp(localTime, + lowerKeyframeBound, + halfTheta, + sinHalfTheta, + reverseQ1); + } } } } diff --git a/src/animation/backend/fcurve.cpp b/src/animation/backend/fcurve.cpp index 490866d54..18f1f427e 100644 --- a/src/animation/backend/fcurve.cpp +++ b/src/animation/backend/fcurve.cpp @@ -97,7 +97,7 @@ float FCurve::evaluateAtTime(float localTime, int lowerBound) const return m_keyframes.first().value; } -float FCurve::evaluateAtTimeAsSlerp(float localTime, int lowerBound, float omega) const +float FCurve::evaluateAtTimeAsSlerp(float localTime, int lowerBound, float halfTheta, float sinHalfTheta, float reverseQ1) const { // TODO: Implement extrapolation beyond first/last keyframes if (localTime < m_localTimes.first()) @@ -119,10 +119,11 @@ float FCurve::evaluateAtTimeAsSlerp(float localTime, int lowerBound, float omega return keyframe0.value; case QKeyFrame::LinearInterpolation: if (localTime >= t0 && localTime <= t1 && t1 > t0) { - const float t = (localTime - t0) / (t1 - t0); - const float div = 1.0f / std::sin(omega); - return std::sin((1 - t) * omega) * div * keyframe0.value + - std::sin(t * omega) * div * keyframe1.value; + const auto t = (localTime - t0) / (t1 - t0); + + const auto A = std::sin((1.0f-t) * halfTheta) / sinHalfTheta; + const auto B = std::sin(t * halfTheta) / sinHalfTheta; + return A * keyframe0.value + reverseQ1 * B * keyframe1.value; } break; case QKeyFrame::BezierInterpolation: diff --git a/src/animation/backend/fcurve_p.h b/src/animation/backend/fcurve_p.h index 337eb615d..935db5922 100644 --- a/src/animation/backend/fcurve_p.h +++ b/src/animation/backend/fcurve_p.h @@ -84,7 +84,7 @@ public: float evaluateAtTime(float localTime) const; float evaluateAtTime(float localTime, int lowerBound) const; - float evaluateAtTimeAsSlerp(float localTime, int lowerBound, float omega) const; + float evaluateAtTimeAsSlerp(float localTime, int lowerBound, float halfTheta, float sinHalfTheta, float reverseQ1) const; int lowerKeyframeBound(float localTime) const; void read(const QJsonObject &json); diff --git a/src/core/qchangearbiter.cpp b/src/core/qchangearbiter.cpp index e0ee389c4..8cfc4b066 100644 --- a/src/core/qchangearbiter.cpp +++ b/src/core/qchangearbiter.cpp @@ -51,6 +51,8 @@ #include <Qt3DCore/private/qscene_p.h> #include <Qt3DCore/private/qsceneobserverinterface_p.h> +#include <mutex> + QT_BEGIN_NAMESPACE namespace Qt3DCore { @@ -76,7 +78,6 @@ namespace Qt3DCore { */ QChangeArbiter::QChangeArbiter(QObject *parent) : QObject(parent) - , m_mutex(QMutex::Recursive) , m_jobManager(nullptr) , m_postman(nullptr) , m_scene(nullptr) @@ -151,31 +152,31 @@ QThreadStorage<QChangeArbiter::QChangeQueue *> *QChangeArbiter::tlsChangeQueue() void QChangeArbiter::appendChangeQueue(QChangeArbiter::QChangeQueue *queue) { - QMutexLocker locker(&m_mutex); + const std::lock_guard<QRecursiveMutex> locker(m_mutex);; m_changeQueues.append(queue); } void QChangeArbiter::removeChangeQueue(QChangeArbiter::QChangeQueue *queue) { - QMutexLocker locker(&m_mutex); + const std::lock_guard<QRecursiveMutex> locker(m_mutex);; m_changeQueues.removeOne(queue); } void QChangeArbiter::appendLockingChangeQueue(QChangeArbiter::QChangeQueue *queue) { - QMutexLocker locker(&m_mutex); + const std::lock_guard<QRecursiveMutex> locker(m_mutex);; m_lockingChangeQueues.append(queue); } void QChangeArbiter::removeLockingChangeQueue(QChangeArbiter::QChangeQueue *queue) { - QMutexLocker locker(&m_mutex); + const std::lock_guard<QRecursiveMutex> locker(m_mutex);; m_lockingChangeQueues.removeOne(queue); } void QChangeArbiter::syncChanges() { - QMutexLocker locker(&m_mutex); + const std::lock_guard<QRecursiveMutex> locker(m_mutex);; for (QChangeArbiter::QChangeQueue *changeQueue : qAsConst(m_changeQueues)) distributeQueueChanges(changeQueue); @@ -202,7 +203,7 @@ void QChangeArbiter::registerObserver(QObserverInterface *observer, QNodeId nodeId, ChangeFlags changeFlags) { - QMutexLocker locker(&m_mutex); + const std::lock_guard<QRecursiveMutex> locker(m_mutex);; QObserverList &observerList = m_nodeObservations[nodeId]; observerList.append(QObserverPair(changeFlags, observer)); } @@ -216,7 +217,7 @@ void QChangeArbiter::registerSceneObserver(QSceneObserverInterface *observer) void QChangeArbiter::unregisterObserver(QObserverInterface *observer, QNodeId nodeId) { - QMutexLocker locker(&m_mutex); + const std::lock_guard<QRecursiveMutex> locker(m_mutex);; const auto it = m_nodeObservations.find(nodeId); if (it != m_nodeObservations.end()) { QObserverList &observers = it.value(); @@ -251,13 +252,13 @@ void QChangeArbiter::sceneChangeEvent(const QSceneChangePtr &e) void QChangeArbiter::sceneChangeEventWithLock(const QSceneChangePtr &e) { - QMutexLocker locker(&m_mutex); + const std::lock_guard<QRecursiveMutex> locker(m_mutex);; sceneChangeEvent(e); } void QChangeArbiter::sceneChangeEventWithLock(const QSceneChangeList &e) { - QMutexLocker locker(&m_mutex); + const std::lock_guard<QRecursiveMutex> locker(m_mutex);; QChangeQueue *localChangeQueue = m_tlsChangeQueue.localData(); qCDebug(ChangeArbiter) << Q_FUNC_INFO << "Handles " << e.size() << " changes at once"; localChangeQueue->insert(localChangeQueue->end(), e.begin(), e.end()); diff --git a/src/core/qchangearbiter_p.h b/src/core/qchangearbiter_p.h index ac52273ea..1f453ff56 100644 --- a/src/core/qchangearbiter_p.h +++ b/src/core/qchangearbiter_p.h @@ -137,7 +137,7 @@ protected: void removeLockingChangeQueue(QChangeQueue *queue); private: - mutable QMutex m_mutex; + mutable QRecursiveMutex m_mutex; QAbstractAspectJobManager *m_jobManager; // The lists of observers indexed by observable (QNodeId). diff --git a/src/core/services/qeventfilterservice.cpp b/src/core/services/qeventfilterservice.cpp index c4ec79a13..036bcd7b4 100644 --- a/src/core/services/qeventfilterservice.cpp +++ b/src/core/services/qeventfilterservice.cpp @@ -39,12 +39,13 @@ #include "qeventfilterservice_p.h" -#include <QtCore/QMap> #include <QtCore/QObject> -#include <QtCore/QVector> #include <Qt3DCore/private/qabstractserviceprovider_p.h> +#include <algorithm> +#include <vector> + QT_BEGIN_NAMESPACE namespace { @@ -54,10 +55,10 @@ namespace { int priority; }; - bool operator <(const FilterPriorityPair &a, const FilterPriorityPair &b) + const auto byPriority = [](const FilterPriorityPair &a, const FilterPriorityPair &b) noexcept { return a.priority < b.priority; - } + }; } Q_DECLARE_TYPEINFO(FilterPriorityPair, Q_PRIMITIVE_TYPE); @@ -89,32 +90,26 @@ public: void registerEventFilter(QObject *eventFilter, int priority) { - for (int i = 0, m = m_eventFilters.size(); i < m; ++i) - if (m_eventFilters.at(i).priority == priority) - return; - FilterPriorityPair fpPair; fpPair.filter = eventFilter; fpPair.priority = priority; - m_eventFilters.push_back(fpPair); - std::sort(m_eventFilters.begin(), m_eventFilters.end()); + const auto it = std::lower_bound(m_eventFilters.begin(), m_eventFilters.end(), fpPair, byPriority); + if (it == m_eventFilters.end() || it->priority != priority) + m_eventFilters.insert(it, std::move(fpPair)); } void unregisterEventFilter(QObject *eventFilter) { - QVector<FilterPriorityPair>::iterator it = m_eventFilters.begin(); - const QVector<FilterPriorityPair>::iterator end = m_eventFilters.end(); - while (it != end) { + for (auto it = m_eventFilters.begin(), end = m_eventFilters.end(); it != end; ++it) { if (it->filter == eventFilter) { m_eventFilters.erase(it); return; } - ++it; } } QScopedPointer<InternalEventListener> m_eventDispatcher; - QVector<FilterPriorityPair> m_eventFilters; + std::vector<FilterPriorityPair> m_eventFilters; }; /* !\internal @@ -179,8 +174,8 @@ InternalEventListener::InternalEventListener(QEventFilterServicePrivate *filterS bool InternalEventListener::eventFilter(QObject *obj, QEvent *e) { - for (int i = m_filterService->m_eventFilters.size() - 1; i >= 0; --i) { - const FilterPriorityPair &fPPair = m_filterService->m_eventFilters.at(i); + for (auto i = m_filterService->m_eventFilters.size(); i > 0; --i) { + const FilterPriorityPair &fPPair = m_filterService->m_eventFilters[i - 1]; if (fPPair.filter->eventFilter(obj, e)) return true; } diff --git a/src/doc/qt3d.qdocconf b/src/doc/qt3d.qdocconf index 25dafd2eb..ded8fea7a 100644 --- a/src/doc/qt3d.qdocconf +++ b/src/doc/qt3d.qdocconf @@ -1,4 +1,5 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) +include($QT_INSTALL_DOCS/config/exampleurl-qt3d.qdocconf) project = Qt3D description = Qt 3D Reference Documentation diff --git a/src/doc/src/qmlextramaterials.qdoc b/src/doc/src/qmlextramaterials.qdoc index c54cc948b..e0a2e9edf 100644 --- a/src/doc/src/qmlextramaterials.qdoc +++ b/src/doc/src/qmlextramaterials.qdoc @@ -69,6 +69,10 @@ Holds the current texture scale. It is applied as a multiplier to texture coordinates at render time. Defaults to 1.0. + + When used in conjunction with WrapMode.Repeat, textureScale provides a simple + way to tile a texture across a surface. For example, a texture scale of \c 4.0 + would result in 16 (4x4) tiles. */ /*! \qmlproperty TextureImage DiffuseMapMaterial::diffuse @@ -152,6 +156,10 @@ Holds the current texture scale. It is applied as a multiplier to texture coordinates at render time. Defaults to 1.0. + + When used in conjunction with WrapMode.Repeat, textureScale provides a simple + way to tile a texture across a surface. For example, a texture scale of \c 4.0 + would result in 16 (4x4) tiles. */ /*! @@ -292,6 +300,10 @@ Holds the current texture scale. It is applied as a multiplier to texture coordinates at render time. Defaults to 1.0. + + When used in conjunction with WrapMode.Repeat, textureScale provides a simple + way to tile a texture across a surface. For example, a texture scale of \c 4.0 + would result in 16 (4x4) tiles. */ /*! @@ -366,6 +378,10 @@ Holds the current texture scale. It is applied as a multiplier to texture coordinates at render time. Defaults to 1.0. + + When used in conjunction with WrapMode.Repeat, textureScale provides a simple + way to tile a texture across a surface. For example, a texture scale of \c 4.0 + would result in 16 (4x4) tiles. */ /*! @@ -449,6 +465,10 @@ Holds the current texture scale. It is applied as a multiplier to texture coordinates at render time. Defaults to 1.0. + + When used in conjunction with WrapMode.Repeat, textureScale provides a simple + way to tile a texture across a surface. For example, a texture scale of \c 4.0 + would result in 16 (4x4) tiles. */ /*! diff --git a/src/extras/defaults/qdiffusemapmaterial.cpp b/src/extras/defaults/qdiffusemapmaterial.cpp index d5e729b8e..83eec26a8 100644 --- a/src/extras/defaults/qdiffusemapmaterial.cpp +++ b/src/extras/defaults/qdiffusemapmaterial.cpp @@ -296,6 +296,9 @@ QAbstractTexture *QDiffuseMapMaterial::diffuse() const Holds the current texture scale. It is applied as a multiplier to texture coordinates at render time. Defaults to 1.0. + When used in conjunction with QTextureWrapMode::Repeat, textureScale provides a simple + way to tile a texture across a surface. For example, a texture scale of \c 4.0 + would result in 16 (4x4) tiles. */ float QDiffuseMapMaterial::textureScale() const { diff --git a/src/extras/defaults/qdiffusespecularmapmaterial.cpp b/src/extras/defaults/qdiffusespecularmapmaterial.cpp index e1d23622c..9a1092fbc 100644 --- a/src/extras/defaults/qdiffusespecularmapmaterial.cpp +++ b/src/extras/defaults/qdiffusespecularmapmaterial.cpp @@ -314,6 +314,10 @@ float QDiffuseSpecularMapMaterial::shininess() const Holds the current texture scale. It is applied as a multiplier to texture coordinates at render time. Defaults to 1.0. + + When used in conjunction with QTextureWrapMode::Repeat, textureScale provides a simple + way to tile a texture across a surface. For example, a texture scale of \c 4.0 + would result in 16 (4x4) tiles. */ float QDiffuseSpecularMapMaterial::textureScale() const { diff --git a/src/extras/defaults/qdiffusespecularmaterial.cpp b/src/extras/defaults/qdiffusespecularmaterial.cpp index be187b46a..8938ce19a 100644 --- a/src/extras/defaults/qdiffusespecularmaterial.cpp +++ b/src/extras/defaults/qdiffusespecularmaterial.cpp @@ -385,12 +385,20 @@ QVariant QDiffuseSpecularMaterial::normal() const Holds the current texture scale. It is applied as a multiplier to texture coordinates at render time. Defaults to 1.0. + + When used in conjunction with QTextureWrapMode::Repeat, textureScale provides a simple + way to tile a texture across a surface. For example, a texture scale of \c 4.0 + would result in 16 (4x4) tiles. */ /*! \qmlproperty real DiffuseSpecularMaterial::textureScale Holds the current texture scale. It is applied as a multiplier to texture coordinates at render time. Defaults to 1.0. + + When used in conjunction with WrapMode.Repeat, textureScale provides a simple + way to tile a texture across a surface. For example, a texture scale of \c 4.0 + would result in 16 (4x4) tiles. */ float QDiffuseSpecularMaterial::textureScale() const { diff --git a/src/extras/defaults/qmetalroughmaterial.cpp b/src/extras/defaults/qmetalroughmaterial.cpp index d404f03de..572bfecfd 100644 --- a/src/extras/defaults/qmetalroughmaterial.cpp +++ b/src/extras/defaults/qmetalroughmaterial.cpp @@ -306,12 +306,20 @@ QVariant QMetalRoughMaterial::normal() const Holds the current texture scale. It is applied as a multiplier to texture coordinates at render time. Defaults to 1.0. + + When used in conjunction with QTextureWrapMode::Repeat, textureScale provides a simple + way to tile a texture across a surface. For example, a texture scale of \c 4.0 + would result in 16 (4x4) tiles. */ /*! \qmlproperty real Qt3D.Extras::MetalRoughMaterial::textureScale Holds the current texture scale. It is applied as a multiplier to texture coordinates at render time. Defaults to 1.0. + + When used in conjunction with WrapMode.Repeat, textureScale provides a simple + way to tile a texture across a surface. For example, a texture scale of \c 4.0 + would result in 16 (4x4) tiles. */ float QMetalRoughMaterial::textureScale() const { diff --git a/src/extras/defaults/qnormaldiffusemapmaterial.cpp b/src/extras/defaults/qnormaldiffusemapmaterial.cpp index 7c8260084..9d41ddb32 100644 --- a/src/extras/defaults/qnormaldiffusemapmaterial.cpp +++ b/src/extras/defaults/qnormaldiffusemapmaterial.cpp @@ -338,6 +338,10 @@ float QNormalDiffuseMapMaterial::shininess() const Holds the current texture scale. It is applied as a multiplier to texture coordinates at render time. Defaults to 1.0. + + When used in conjunction with QTextureWrapMode::Repeat, textureScale provides a simple + way to tile a texture across a surface. For example, a texture scale of \c 4.0 + would result in 16 (4x4) tiles. */ float QNormalDiffuseMapMaterial::textureScale() const { diff --git a/src/extras/defaults/qnormaldiffusespecularmapmaterial.cpp b/src/extras/defaults/qnormaldiffusespecularmapmaterial.cpp index 5fb2b7e9e..a76d9856b 100644 --- a/src/extras/defaults/qnormaldiffusespecularmapmaterial.cpp +++ b/src/extras/defaults/qnormaldiffusespecularmapmaterial.cpp @@ -355,6 +355,10 @@ float QNormalDiffuseSpecularMapMaterial::shininess() const Holds the current texture scale. It is applied as a multiplier to texture coordinates at render time. Defaults to 1.0. + + When used in conjunction with QTextureWrapMode::Repeat, textureScale provides a simple + way to tile a texture across a surface. For example, a texture scale of \c 4.0 + would result in 16 (4x4) tiles. */ float QNormalDiffuseSpecularMapMaterial::textureScale() const { diff --git a/src/extras/defaults/qskyboxentity.cpp b/src/extras/defaults/qskyboxentity.cpp index 7de552b38..e82a30950 100644 --- a/src/extras/defaults/qskyboxentity.cpp +++ b/src/extras/defaults/qskyboxentity.cpp @@ -238,6 +238,30 @@ void QSkyboxEntityPrivate::reloadTexture() */ /*! + * \qmltype SkyboxEntity + * \instantiates Qt3DExtras::QSkyboxEntity + \inqmlmodule Qt3D.Extras + * + * \brief SkyboxEntity is a convenience Entity subclass that can be used to + * insert a skybox in a 3D scene. + * + * By specifying a base name and an extension, SkyboxEntity will take care of + * building a TextureCubeMap to be rendered at runtime. The images in the + * source directory should match the pattern: \b base name + * + * "_posx|_posy|_posz|_negx|_negy|_negz" + extension + * + * By default the extension defaults to .png. + * + * Be sure to disable frustum culling in the FrameGraph through which the + * skybox rendering happens. + * + * \note Please note that you shouldn't try to render a skybox with an + * orthographic projection. + * + * \since 5.5 + */ + +/*! * Constructs a new Qt3DExtras::QSkyboxEntity object with \a parent as parent. */ QSkyboxEntity::QSkyboxEntity(QNode *parent) @@ -269,6 +293,11 @@ void QSkyboxEntity::setBaseName(const QString &baseName) Contains the base name of the Skybox. */ /*! + \qmlproperty string QSkyboxEntity::baseName + + Contains the base name of the Skybox. +*/ +/*! * Returns the base name of the Skybox. */ QString QSkyboxEntity::baseName() const @@ -298,6 +327,15 @@ void QSkyboxEntity::setExtension(const QString &extension) The default value is: .png */ + +/*! + \qmlproperty string QSkyboxEntity::extension + + Contains the extension of the filename for the skybox image, including the + leading '.'. + + The default value is: .png +*/ /*! * Returns the extension */ @@ -336,5 +374,12 @@ bool QSkyboxEntity::isGammaCorrectEnabled() const \property QSkyboxEntity::gammaCorrect A boolean indicating whether gamma correction is enabled. + \since 5.9 +*/ +/*! + \qmlproperty bool QSkyboxEntity::gammaCorrect + + A boolean indicating whether gamma correction is enabled. + \since 5.9 */ QT_END_NAMESPACE diff --git a/src/input/frontend/qmouseevent.h b/src/input/frontend/qmouseevent.h index a7aa8fe2b..1402d8210 100644 --- a/src/input/frontend/qmouseevent.h +++ b/src/input/frontend/qmouseevent.h @@ -142,8 +142,8 @@ public: explicit QWheelEvent(const QT_PREPEND_NAMESPACE(QWheelEvent) &e); ~QWheelEvent(); - inline int x() const { return m_event.x(); } - inline int y() const { return m_event.y(); } + inline int x() const { return int(m_event.position().x()); } + inline int y() const { return int(m_event.position().y()); } inline QPoint angleDelta() const { return m_event.angleDelta(); } int buttons() const; Modifiers modifiers() const; diff --git a/src/logic/qframeaction.cpp b/src/logic/qframeaction.cpp index 77cdae943..a3ae748be 100644 --- a/src/logic/qframeaction.cpp +++ b/src/logic/qframeaction.cpp @@ -127,12 +127,12 @@ void QFrameAction::onTriggered(float dt) /*! \qmlsignal Qt3D.Logic::FrameAction::triggered(real dt) - This signal is emitted each frame. + This signal is emitted each frame with \a dt being the time (in seconds) since the last triggering. */ /*! \fn Qt3DLogic::QFrameAction::triggered(float dt) - This signal is emitted each frame with \a dt being the time since the last triggering. + This signal is emitted each frame with \a dt being the time (in seconds) since the last triggering. */ } // namespace Qt3DLogic diff --git a/src/plugins/sceneparsers/assimp/assimphelpers.cpp b/src/plugins/sceneparsers/assimp/assimphelpers.cpp index ce6619541..77209a7a9 100644 --- a/src/plugins/sceneparsers/assimp/assimphelpers.cpp +++ b/src/plugins/sceneparsers/assimp/assimphelpers.cpp @@ -157,29 +157,29 @@ void AssimpIOStream::Flush() * */ -/*! - * Builds a new instance of AssimpIOSystem. - */ -AssimpIOSystem::AssimpIOSystem() : - Assimp::IOSystem() -{ - m_openModeMaps[QByteArrayLiteral("r")] = QIODevice::ReadOnly; - m_openModeMaps[QByteArrayLiteral("r+")] = QIODevice::ReadWrite; - m_openModeMaps[QByteArrayLiteral("w")] = QIODevice::WriteOnly | QIODevice::Truncate; - m_openModeMaps[QByteArrayLiteral("w+")] = QIODevice::ReadWrite | QIODevice::Truncate; - m_openModeMaps[QByteArrayLiteral("a")] = QIODevice::WriteOnly | QIODevice::Append; - m_openModeMaps[QByteArrayLiteral("a+")] = QIODevice::ReadWrite | QIODevice::Append; - m_openModeMaps[QByteArrayLiteral("wb")] = QIODevice::WriteOnly; - m_openModeMaps[QByteArrayLiteral("wt")] = QIODevice::WriteOnly | QIODevice::Text; - m_openModeMaps[QByteArrayLiteral("rb")] = QIODevice::ReadOnly; - m_openModeMaps[QByteArrayLiteral("rt")] = QIODevice::ReadOnly | QIODevice::Text; -} - -/*! - * Clears an AssimpIOSystem instance before deletion. - */ -AssimpIOSystem::~AssimpIOSystem() +static QIODevice::OpenMode openModeFromText(const char *name) noexcept { + static const struct OpenModeMapping { + char name[2]; + ushort mode; + } openModeMapping[] = { + { { 'r', 0 }, QIODevice::ReadOnly }, + { { 'r', '+' }, QIODevice::ReadWrite }, + { { 'w', 0 }, QIODevice::WriteOnly | QIODevice::Truncate }, + { { 'w', '+' }, QIODevice::ReadWrite | QIODevice::Truncate }, + { { 'a', 0 }, QIODevice::WriteOnly | QIODevice::Append }, + { { 'a', '+' }, QIODevice::ReadWrite | QIODevice::Append }, + { { 'w', 'b' }, QIODevice::WriteOnly }, + { { 'w', 't' }, QIODevice::WriteOnly | QIODevice::Text }, + { { 'r', 'b' }, QIODevice::ReadOnly }, + { { 'r', 't' }, QIODevice::ReadOnly | QIODevice::Text }, + }; + + for (auto e : openModeMapping) { + if (qstrncmp(e.name, name, sizeof(OpenModeMapping::name)) == 0) + return static_cast<QIODevice::OpenMode>(e.mode); + } + return QIODevice::NotOpen; } /*! @@ -205,14 +205,13 @@ char AssimpIOSystem::getOsSeparator() const Assimp::IOStream *AssimpIOSystem::Open(const char *pFile, const char *pMode) { const QString fileName(QString::fromUtf8(pFile)); - const QByteArray cleanedMode(QByteArray(pMode).trimmed()); - - const QIODevice::OpenMode openMode = m_openModeMaps.value(cleanedMode, QIODevice::NotOpen); - - QScopedPointer<QFile> file(new QFile(fileName)); - if (file->open(openMode)) - return new AssimpIOStream(file.take()); + const QLatin1String cleanedMode = QLatin1String{pMode}.trimmed(); + if (const QIODevice::OpenMode openMode = openModeFromText(cleanedMode.data())) { + QScopedPointer<QFile> file(new QFile(fileName)); + if (file->open(openMode)) + return new AssimpIOStream(file.take()); + } return nullptr; } diff --git a/src/plugins/sceneparsers/assimp/assimphelpers.h b/src/plugins/sceneparsers/assimp/assimphelpers.h index 0db22ce7b..fd102213c 100644 --- a/src/plugins/sceneparsers/assimp/assimphelpers.h +++ b/src/plugins/sceneparsers/assimp/assimphelpers.h @@ -55,7 +55,6 @@ #include <assimp/IOStream.hpp> #include <assimp/IOSystem.hpp> #include <QtCore/QIODevice> -#include <QtCore/QMap> QT_BEGIN_NAMESPACE @@ -84,15 +83,10 @@ private: class AssimpIOSystem : public Assimp::IOSystem { public : - AssimpIOSystem(); - ~AssimpIOSystem(); bool Exists(const char *pFile) const override; char getOsSeparator() const override; Assimp::IOStream *Open(const char *pFile, const char *pMode) override; void Close(Assimp::IOStream *pFile) override; - -private: - QMap<QByteArray, QIODevice::OpenMode> m_openModeMaps; }; } // namespace AssimpHelper diff --git a/src/plugins/sceneparsers/assimp/assimpimporter.h b/src/plugins/sceneparsers/assimp/assimpimporter.h index 9a020b3e3..9d6bd73de 100644 --- a/src/plugins/sceneparsers/assimp/assimpimporter.h +++ b/src/plugins/sceneparsers/assimp/assimpimporter.h @@ -57,7 +57,6 @@ #include <assimp/postprocess.h> #include <assimp/DefaultLogger.hpp> -#include <QtCore/QMap> #include <QtCore/QDir> #include <QtCore/QLoggingCategory> #include <QtCore/QVector> @@ -139,7 +138,6 @@ private: Assimp::Importer *m_importer; mutable const aiScene *m_aiScene; - QMap<uint, QAbstractTexture *> m_embeddedTextures; QHash<aiTextureType, QString> m_textureToParameterName; QVector<Qt3DAnimation::QKeyframeAnimation *> m_animations; QVector<Qt3DAnimation::QMorphingAnimation *> m_morphAnimations; diff --git a/src/plugins/sceneparsers/gltf/gltfimporter.cpp b/src/plugins/sceneparsers/gltf/gltfimporter.cpp index 7cda33113..a10a83cca 100644 --- a/src/plugins/sceneparsers/gltf/gltfimporter.cpp +++ b/src/plugins/sceneparsers/gltf/gltfimporter.cpp @@ -1514,16 +1514,6 @@ void GLTFImporter::processJSONBufferView(const QString &id, const QJsonObject& j } else { target = targetValue.toInt(); } - Qt3DRender::QBuffer::BufferType ty(Qt3DRender::QBuffer::VertexBuffer); - - switch (target) { - case GL_ARRAY_BUFFER: ty = Qt3DRender::QBuffer::VertexBuffer; break; - case GL_ELEMENT_ARRAY_BUFFER: ty = Qt3DRender::QBuffer::IndexBuffer; break; - default: - qCWarning(GLTFImporterLog, "buffer %ls unsupported target: %d", - qUtf16PrintableImpl(id), target); - return; - } quint64 offset = 0; const auto byteOffset = json.value(KEY_BYTE_OFFSET); @@ -1541,7 +1531,6 @@ void GLTFImporter::processJSONBufferView(const QString &id, const QJsonObject& j } Qt3DRender::QBuffer *b = new Qt3DRender::QBuffer(); - b->setType(ty); b->setData(bytes); m_buffers[id] = b; } diff --git a/src/plugins/sceneparsers/gltf/gltfparser.cpp b/src/plugins/sceneparsers/gltf/gltfparser.cpp deleted file mode 100644 index 881e7f1b2..000000000 --- a/src/plugins/sceneparsers/gltf/gltfparser.cpp +++ /dev/null @@ -1,1560 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). -** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "gltfparser.h" - -#include <QtCore/QDir> -#include <QtCore/QFileInfo> -#include <QtCore/QJsonArray> -#include <QtCore/QJsonObject> - -#include <QtGui/QVector2D> - -#include <Qt3DCore/QCameraLens> -#include <Qt3DCore/QEntity> -#include <Qt3DCore/QTransform> - -#include <Qt3DRender/private/qurlhelper_p.h> - -#include <Qt3DRender/QAlphaCoverage> -#include <Qt3DRender/QBlendEquation> -#include <Qt3DRender/QBlendStateSeparate> -#include <Qt3DRender/QColorMask> -#include <Qt3DRender/QCullFace> -#include <Qt3DRender/QDepthMask> -#include <Qt3DRender/QDepthTest> -#include <Qt3DRender/QEffect> -#include <Qt3DRender/QFrontFace> -#include <Qt3DRender/QGeometry> -#include <Qt3DRender/QGeometryRenderer> -#include <Qt3DRender/QMaterial> -#include <Qt3DRender/QGraphicsApiFilter> -#include <Qt3DRender/QParameter> -#include <Qt3DRender/QParameterMapping> -#include <Qt3DRender/QPolygonOffset> -#include <Qt3DRender/QRenderState> -#include <Qt3DRender/QScissorTest> -#include <Qt3DRender/QShaderProgram> -#include <Qt3DRender/QTechnique> -#include <Qt3DRender/QTexture> - -#include <Qt3DRender/QPhongMaterial> -#include <Qt3DRender/QDiffuseMapMaterial> -#include <Qt3DRender/QDiffuseSpecularMapMaterial> -#include <Qt3DRender/QNormalDiffuseMapMaterial> -#include <Qt3DRender/QNormalDiffuseSpecularMapMaterial> - -QT_BEGIN_NAMESPACE - -using namespace Qt3DCore; - -namespace Qt3DRender { - -Q_LOGGING_CATEGORY(GLTFParserLog, "Qt3D.GLTFParser") - -namespace { - -const QString KEY_CAMERA = QStringLiteral("camera"); -const QString KEY_CAMERAS = QStringLiteral("cameras"); -const QString KEY_SCENES = QStringLiteral("scenes"); -const QString KEY_NODES = QStringLiteral("nodes"); -const QString KEY_MESHES = QStringLiteral("meshes"); -const QString KEY_CHILDREN = QStringLiteral("children"); -const QString KEY_MATRIX = QStringLiteral("matrix"); -const QString KEY_ROTATION = QStringLiteral("rotation"); -const QString KEY_SCALE = QStringLiteral("scale"); -const QString KEY_TRANSLATION = QStringLiteral("translation"); -const QString KEY_TYPE = QStringLiteral("type"); -const QString KEY_PERSPECTIVE =QStringLiteral("perspective"); -const QString KEY_NAME = QStringLiteral("name"); -const QString KEY_COUNT = QStringLiteral("count"); -const QString KEY_YFOV = QStringLiteral("yfov"); -const QString KEY_ZNEAR = QStringLiteral("znear"); -const QString KEY_ZFAR = QStringLiteral("zfar"); -const QString KEY_MATERIALS = QStringLiteral("materials"); -const QString KEY_EXTENSIONS = QStringLiteral("extensions"); -const QString KEY_COMMON_MAT = QStringLiteral("KHR_materials_common"); -const QString KEY_TECHNIQUE = QStringLiteral("technique"); -const QString KEY_VALUES = QStringLiteral("values"); -const QString KEY_BUFFERS = QStringLiteral("buffers"); -const QString KEY_SHADERS = QStringLiteral("shaders"); -const QString KEY_PROGRAMS = QStringLiteral("programs"); -const QString KEY_PROGRAM = QStringLiteral("program"); -const QString KEY_TECHNIQUES = QStringLiteral("techniques"); -const QString KEY_ACCESSORS = QStringLiteral("accessors"); -const QString KEY_IMAGES = QStringLiteral("images"); -const QString KEY_TEXTURES = QStringLiteral("textures"); -const QString KEY_SCENE = QStringLiteral("scene"); -const QString KEY_BUFFER = QStringLiteral("buffer"); -const QString KEY_TARGET = QStringLiteral("target"); -const QString KEY_BYTE_OFFSET = QStringLiteral("byteOffset"); -const QString KEY_BYTE_LENGTH = QStringLiteral("byteLength"); -const QString KEY_BYTE_STRIDE = QStringLiteral("byteStride"); -const QString KEY_PRIMITIVES = QStringLiteral("primitives"); -const QString KEY_MODE = QStringLiteral("mode"); -const QString KEY_MATERIAL = QStringLiteral("material"); -const QString KEY_ATTRIBUTES = QStringLiteral("attributes"); -const QString KEY_INDICES = QStringLiteral("indices"); -const QString KEY_URI = QStringLiteral("uri"); -const QString KEY_FORMAT = QStringLiteral("format"); -const QString KEY_PASSES = QStringLiteral("passes"); -const QString KEY_SOURCE = QStringLiteral("source"); -const QString KEY_SAMPLER = QStringLiteral("sampler"); -const QString KEY_SAMPLERS = QStringLiteral("samplers"); -const QString KEY_SEMANTIC = QStringLiteral("semantic"); -const QString KEY_STATES = QStringLiteral("states"); -const QString KEY_UNIFORMS = QStringLiteral("uniforms"); -const QString KEY_PARAMETERS = QStringLiteral("parameters"); -const QString KEY_WRAP_S = QStringLiteral("wrapS"); -const QString KEY_MIN_FILTER = QStringLiteral("minFilter"); -const QString KEY_MAG_FILTER = QStringLiteral("magFilter"); - -const QString KEY_INSTANCE_TECHNIQUE = QStringLiteral("instanceTechnique"); -const QString KEY_INSTANCE_PROGRAM = QStringLiteral("instanceProgram"); -const QString KEY_BUFFER_VIEWS = QStringLiteral("bufferViews"); -const QString KEY_BUFFER_VIEW = QStringLiteral("bufferView"); -const QString KEY_VERTEX_SHADER = QStringLiteral("vertexShader"); -const QString KEY_FRAGMENT_SHADER = QStringLiteral("fragmentShader"); -const QString KEY_INTERNAL_FORMAT = QStringLiteral("internalFormat"); -const QString KEY_COMPONENT_TYPE = QStringLiteral("componentType"); -const QString KEY_ASPECT_RATIO = QStringLiteral("aspect_ratio"); -const QString KEY_VALUE = QStringLiteral("value"); -const QString KEY_ENABLE = QStringLiteral("enable"); -const QString KEY_FUNCTIONS = QStringLiteral("functions"); -const QString KEY_TECHNIQUE_CORE = QStringLiteral("techniqueCore"); -const QString KEY_TECHNIQUE_GL2 = QStringLiteral("techniqueGL2"); - -} // of anonymous namespace - -GLTFParser::GLTFParser() : QAbstractSceneParser(), - m_parseDone(false) -{ -} - -GLTFParser::~GLTFParser() -{ - -} - -void GLTFParser::setBasePath(const QString& path) -{ - m_basePath = path; -} - -bool GLTFParser::setJSON(const QJsonDocument &json ) -{ - if ( !json.isObject() ) { - return false; - } - - m_json = json; - m_parseDone = false; - - cleanup(); - - return true; -} - -/* - * Sets the \a path used by the parser to load the scene file. - * If the file is valid, parsing is automatically triggered. - */ -void GLTFParser::setSource(const QUrl &source) -{ - const QString path = QUrlHelper::urlToLocalFileOrQrc(source); - QFile f(path); - if (Q_UNLIKELY(!f.open(QIODevice::ReadOnly))) { - qCWarning(GLTFParserLog) << "cannot open " << path << ": " << f.errorString(); - return; - } - - QByteArray jsonData = f.readAll(); - QJsonDocument sceneDocument = QJsonDocument::fromBinaryData(jsonData); - if (sceneDocument.isNull()) - sceneDocument = QJsonDocument::fromJson(jsonData); - - if (!setJSON(sceneDocument)) { - qCWarning(GLTFParserLog) << "not a JSON document"; - return; - } - - setBasePath(QFileInfo(path).dir().absolutePath()); -} - -/* - * Returns true if the extension of \a path is supported by the - * GLTF parser. - */ -bool GLTFParser::isExtensionSupported(const QUrl &source) const -{ - const QString path = QUrlHelper::urlToLocalFileOrQrc(source); - return GLTFParser::isGLTFPath(path); -} - -Qt3DCore::QEntity* GLTFParser::node(const QString &id) -{ - QJsonObject nodes = m_json.object().value(KEY_NODES).toObject(); - if (!nodes.contains(id)) { - qCWarning(GLTFParserLog) << "unknown node" << id << "in GLTF file" << m_basePath; - return NULL; - } - - QJsonObject jsonObj = nodes.value(id).toObject(); - QEntity* result = nullptr; - - // Qt3D has a limitation that a QEntity can only have 1 mesh and 1 material component - // So if the node has only 1 mesh, we only create 1 QEntity - // Otherwise if there are n meshes, there is 1 QEntity, with n children for each mesh/material combo - if (jsonObj.contains(KEY_MESHES)) { - QVector<QEntity *> entities; - - Q_FOREACH (QJsonValue mesh, jsonObj.value(KEY_MESHES).toArray()) { - if (!m_meshDict.contains(mesh.toString())) { - qCWarning(GLTFParserLog) << "node" << id << "references unknown mesh" << mesh.toString(); - continue; - } - - Q_FOREACH (QGeometryRenderer *geometryRenderer, m_meshDict.values(mesh.toString())) { - QEntity *entity = new QEntity; - entity->addComponent(geometryRenderer); - QMaterial *mat = material(m_meshMaterialDict[geometryRenderer]); - if (mat) - entity->addComponent(mat); - entities.append(entity); - } - - } - - if (entities.count() == 1) { - result = entities.first(); - } else { - result = new QEntity; - Q_FOREACH (QEntity *entity, entities) { - entity->setParent(result); - } - } - } - - //If the entity contains no meshes, results will still be null here - if (result == nullptr) - result = new QEntity; - - if ( jsonObj.contains(KEY_CHILDREN) ) { - Q_FOREACH (QJsonValue c, jsonObj.value(KEY_CHILDREN).toArray()) { - QEntity* child = node(c.toString()); - if (!child) - continue; - child->setParent(result); - } - } - - renameFromJson(jsonObj, result); - - - // Node Transforms - Qt3DCore::QTransform *trans = nullptr; - if ( jsonObj.contains(KEY_MATRIX) ) { - QMatrix4x4 m(Qt::Uninitialized); - - QJsonArray matrixValues = jsonObj.value(KEY_MATRIX).toArray(); - for (int i=0; i<16; ++i) { - double v = matrixValues.at( i ).toDouble(); - m(i % 4, i >> 2) = v; - } - - // ADD MATRIX TRANSFORM COMPONENT TO ENTITY - if (trans == nullptr) - trans = new Qt3DCore::QTransform; - trans->setMatrix(m); - } - - // Rotation quaternion - if (jsonObj.contains(KEY_ROTATION)) { - if (trans == nullptr) - trans = new Qt3DCore::QTransform; - - QJsonArray quaternionValues = jsonObj.value(KEY_ROTATION).toArray(); - QQuaternion quaternion(quaternionValues[0].toDouble(), - quaternionValues[1].toDouble(), - quaternionValues[2].toDouble(), - quaternionValues[3].toDouble()); - trans->setRotation(quaternion); - } - - // Translation - if (jsonObj.contains(KEY_TRANSLATION)) { - if (trans == nullptr) - trans = new Qt3DCore::QTransform; - - QJsonArray translationValues = jsonObj.value(KEY_TRANSLATION).toArray(); - trans->setTranslation(QVector3D(translationValues[0].toDouble(), - translationValues[1].toDouble(), - translationValues[2].toDouble())); - } - - // Scale - if (jsonObj.contains(KEY_SCALE)) { - if (trans == nullptr) - trans = new Qt3DCore::QTransform; - - QJsonArray scaleValues = jsonObj.value(KEY_SCALE).toArray(); - trans->setScale3D(QVector3D(scaleValues[0].toDouble(), - scaleValues[1].toDouble(), - scaleValues[2].toDouble())); - } - - // Add the Transform component - if (trans != nullptr) - result->addComponent(trans); - - if ( jsonObj.contains(KEY_CAMERA) ) { - QCameraLens* cam = camera( jsonObj.value(KEY_CAMERA).toString() ); - if (!cam) { - qCWarning(GLTFParserLog) << "failed to build camera:" << jsonObj.value(KEY_CAMERA) - << "on node" << id; - } else { - result->addComponent(cam); - } - } // of have camera attribute - - return result; -} - -Qt3DCore::QEntity* GLTFParser::scene(const QString &id) -{ - parse(); - - QJsonObject scenes = m_json.object().value(KEY_SCENES).toObject(); - if (!scenes.contains(id)) { - if (!id.isNull()) - qCWarning(GLTFParserLog) << "GLTF: no such scene" << id << "in file" << m_basePath; - return defaultScene(); - } - - QJsonObject sceneObj = scenes.value(id).toObject(); - QEntity* sceneEntity = new QEntity; - Q_FOREACH (QJsonValue nnv, sceneObj.value(KEY_NODES).toArray()) { - QString nodeName = nnv.toString(); - QEntity* child = node(nodeName); - if (!child) - continue; - child->setParent(sceneEntity); - } - - return sceneEntity; -} - -GLTFParser::BufferData::BufferData() - : length(0) - , data(nullptr) -{ -} - -GLTFParser::BufferData::BufferData(QJsonObject json) -{ - path = json.value(KEY_URI).toString(); - length = json.value(KEY_BYTE_LENGTH).toInt(); - data = nullptr; -} - -GLTFParser::ParameterData::ParameterData() : - type(0) -{ - -} - -GLTFParser::ParameterData::ParameterData(QJsonObject json) -{ - type = json.value(KEY_TYPE).toInt(); - semantic = json.value(KEY_SEMANTIC).toString(); -} - -GLTFParser::AccessorData::AccessorData() - : type(QAttribute::Float) - , dataSize(0) - , count(0) - , offset(0) - , stride(0) -{ - -} - -GLTFParser::AccessorData::AccessorData(const QJsonObject &json) -{ - bufferViewName = json.value(KEY_BUFFER_VIEW).toString(); - offset = 0; - stride = 0; - int componentType = json.value(KEY_COMPONENT_TYPE).toInt(); - type = accessorTypeFromJSON(componentType); - count = json.value(KEY_COUNT).toInt(); - dataSize = accessorDataSizeFromJson(json.value(KEY_TYPE).toString()); - - if ( json.contains(KEY_BYTE_OFFSET)) - offset = json.value(KEY_BYTE_OFFSET).toInt(); - if ( json.contains(KEY_BYTE_STRIDE)) - stride = json.value(KEY_BYTE_STRIDE).toInt(); -} - -bool GLTFParser::isGLTFPath(const QString& path) -{ - QFileInfo finfo(path); - if (!finfo.exists()) - return false; - - // might need to detect other things in the future, but would - // prefer to avoid doing a full parse. - QString suffix = finfo.suffix().toLower(); - return (suffix == QStringLiteral("json") || suffix == QStringLiteral("gltf") || suffix == QStringLiteral("qgltf")); -} - -void GLTFParser::renameFromJson(const QJsonObject &json, QObject * const object) -{ - if ( json.contains(KEY_NAME) ) - object->setObjectName( json.value(KEY_NAME).toString() ); -} - -QString GLTFParser::standardUniformNamefromSemantic(const QString &semantic) -{ - //Standard Uniforms - //if (semantic == QStringLiteral("LOCAL")); - if (semantic == QStringLiteral("MODEL")) - return QStringLiteral("modelMatrix"); - if (semantic == QStringLiteral("VIEW")) - return QStringLiteral("viewMatrix"); - if (semantic == QStringLiteral("PROJECTION")) - return QStringLiteral("projectionMatrix"); - if (semantic == QStringLiteral("MODELVIEW")) - return QStringLiteral("modelView"); - if (semantic == QStringLiteral("MODELVIEWPROJECTION")) - return QStringLiteral("modelViewProjection"); - if (semantic == QStringLiteral("MODELINVERSE")) - return QStringLiteral("inverseModelMatrix"); - if (semantic == QStringLiteral("VIEWINVERSE")) - return QStringLiteral("inverViewMatrix"); - if (semantic == QStringLiteral("PROJECTIONINVERSE")) - return QStringLiteral("inverseProjectionMatrix"); - if (semantic == QStringLiteral("MODELVIEWPROJECTIONINVERSE")) - return QStringLiteral("inverseModelViewProjection"); - if (semantic == QStringLiteral("MODELINVERSETRANSPOSE")) - return QStringLiteral("modelNormalMatrix"); - if (semantic == QStringLiteral("MODELVIEWINVERSETRANSPOSE")) - return QStringLiteral("modelViewNormal"); - if (semantic == QStringLiteral("VIEWPORT")) - return QStringLiteral("viewportMatrix"); - - return QString(); -} - -QString GLTFParser::standardAttributeNameFromSemantic(const QString &semantic) -{ - //Standard Attributes - if (semantic.startsWith(QStringLiteral("POSITION"))) - return QAttribute::defaultPositionAttributeName(); - if (semantic.startsWith(QStringLiteral("NORMAL"))) - return QAttribute::defaultNormalAttributeName(); - if (semantic.startsWith(QStringLiteral("TEXCOORD"))) - return QAttribute::defaultTextureCoordinateAttributeName(); - if (semantic.startsWith(QStringLiteral("COLOR"))) - return QAttribute::defaultColorAttributeName(); - if (semantic.startsWith(QStringLiteral("TANGENT"))) - return QAttribute::defaultTangentAttributeName(); - -// if (semantic.startsWith(QStringLiteral("JOINT"))); -// if (semantic.startsWith(QStringLiteral("JOINTMATRIX"))); -// if (semantic.startsWith(QStringLiteral("WEIGHT"))); - - return QString(); -} - -QParameter *GLTFParser::parameterFromTechnique(QTechnique *technique, const QString ¶meterName) -{ - Q_FOREACH (QParameter *parameter, technique->parameters()) { - if (parameter->name() == parameterName) { - return parameter; - } - } - - return nullptr; -} - -Qt3DCore::QEntity* GLTFParser::defaultScene() -{ - if (m_defaultScene.isEmpty()) { - qCWarning(GLTFParserLog) << Q_FUNC_INFO << "no default scene"; - return NULL; - } - - return scene(m_defaultScene); -} - -QMaterial *GLTFParser::materialWithCustomShader(const QString &id, const QJsonObject &jsonObj) -{ - //Default ES2 Technique - QString techniqueName = jsonObj.value(KEY_TECHNIQUE).toString(); - if (!m_techniques.contains(techniqueName)) { - qCWarning(GLTFParserLog) << "unknown technique" << techniqueName - << "for material" << id << "in GLTF file" << m_basePath; - return NULL; - } - QTechnique *technique = m_techniques.value(techniqueName); - technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGLES); - technique->graphicsApiFilter()->setMajorVersion(2); - technique->graphicsApiFilter()->setMinorVersion(0); - technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::NoProfile); - - - //Optional Core technique - QTechnique *coreTechnique = nullptr; - QTechnique *gl2Technique = nullptr; - QString coreTechniqueName = jsonObj.value(KEY_TECHNIQUE_CORE).toString(); - if (!coreTechniqueName.isNull()) { - if (!m_techniques.contains(coreTechniqueName)) { - qCWarning(GLTFParserLog) << "unknown technique" << coreTechniqueName - << "for material" << id << "in GLTF file" << m_basePath; - } else { - coreTechnique = m_techniques.value(coreTechniqueName); - coreTechnique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL); - coreTechnique->graphicsApiFilter()->setMajorVersion(3); - coreTechnique->graphicsApiFilter()->setMinorVersion(1); - coreTechnique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::CoreProfile); - } - } - //Optional GL2 technique - QString gl2TechniqueName = jsonObj.value(KEY_TECHNIQUE_GL2).toString(); - if (!gl2TechniqueName.isNull()) { - if (!m_techniques.contains(gl2TechniqueName)) { - qCWarning(GLTFParserLog) << "unknown technique" << gl2TechniqueName - << "for material" << id << "in GLTF file" << m_basePath; - } else { - gl2Technique = m_techniques.value(gl2TechniqueName); - gl2Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL); - gl2Technique->graphicsApiFilter()->setMajorVersion(2); - gl2Technique->graphicsApiFilter()->setMinorVersion(0); - gl2Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::NoProfile); - } - } - - - // glTF doesn't deal in effects, but we need a trivial one to wrap - // up our techniques - // However we need to create a unique effect for each material instead - // of caching because QMaterial does not keep up with effects - // its not the parent of. - QEffect* effect = new QEffect; - effect->setObjectName(techniqueName); - effect->addTechnique(technique); - if (coreTechnique != nullptr) - effect->addTechnique(coreTechnique); - if (gl2Technique != nullptr) - effect->addTechnique(gl2Technique); - - QMaterial* mat = new QMaterial; - mat->setEffect(effect); - - renameFromJson(jsonObj, mat); - - QJsonObject values = jsonObj.value(KEY_VALUES).toObject(); - Q_FOREACH (QString vName, values.keys()) { - QParameter *param = parameterFromTechnique(technique, vName); - - if (param == nullptr && coreTechnique != nullptr) { - param = parameterFromTechnique(coreTechnique, vName); - } - - if (param == nullptr && gl2Technique != nullptr) { - param = parameterFromTechnique(gl2Technique, vName); - } - - if (param == nullptr) { - qCWarning(GLTFParserLog) << "unknown parameter:" << vName << "in technique" << techniqueName - << "processing material" << id; - continue; - } - - ParameterData paramData = m_parameterDataDict.value(param); - QVariant var = parameterValueFromJSON(paramData.type, values.value(vName)); - - mat->addParameter(new QParameter(param->name(), var)); - } // of material technique-instance values iteration - - return mat; -} - -static inline QVariant vec4ToRgb(const QVariant &vec4Var) -{ - const QVector4D v = vec4Var.value<QVector4D>(); - return QVariant(QColor::fromRgbF(v.x(), v.y(), v.z())); -} - -QMaterial *GLTFParser::commonMaterial(const QJsonObject &jsonObj) -{ - QVariantHash params; - bool hasDiffuseMap = false; - bool hasSpecularMap = false; - bool hasNormalMap = false; - - QJsonObject values = jsonObj.value(KEY_VALUES).toObject(); - Q_FOREACH (const QString &vName, values.keys()) { - const QJsonValue val = values.value(vName); - QVariant var; - QString propertyName = vName; - if (vName == QStringLiteral("ambient") && val.isArray()) { - var = vec4ToRgb(parameterValueFromJSON(GL_FLOAT_VEC4, val)); - } else if (vName == QStringLiteral("diffuse")) { - if (val.isString()) { - var = parameterValueFromJSON(GL_SAMPLER_2D, val); - hasDiffuseMap = true; - } else if (val.isArray()) { - var = vec4ToRgb(parameterValueFromJSON(GL_FLOAT_VEC4, val)); - } - } else if (vName == QStringLiteral("specular")) { - if (val.isString()) { - var = parameterValueFromJSON(GL_SAMPLER_2D, val); - hasSpecularMap = true; - } else if (val.isArray()) { - var = vec4ToRgb(parameterValueFromJSON(GL_FLOAT_VEC4, val)); - } - } else if (vName == QStringLiteral("shininess") && val.isDouble()) { - var = parameterValueFromJSON(GL_FLOAT, val); - } else if (vName == QStringLiteral("normalmap") && val.isString()) { - var = parameterValueFromJSON(GL_SAMPLER_2D, val); - propertyName = QStringLiteral("normal"); - hasNormalMap = true; - } else if (vName == QStringLiteral("transparency")) { - qCWarning(GLTFParserLog) << "Semi-transparent common materials are not currently supported, ignoring alpha"; - } - if (var.isValid()) - params[propertyName] = var; - } - - QMaterial *mat = nullptr; - if (hasNormalMap) { - if (hasSpecularMap) { - mat = new QNormalDiffuseSpecularMapMaterial; - } else { - if (hasDiffuseMap) - mat = new QNormalDiffuseMapMaterial; - else - qCWarning(GLTFParserLog) << "Common material with normal and specular maps needs a diffuse map as well"; - } - } else { - if (hasSpecularMap) { - if (hasDiffuseMap) - mat = new QDiffuseSpecularMapMaterial; - else - qCWarning(GLTFParserLog) << "Common material with specular map needs a diffuse map as well"; - } else if (hasDiffuseMap) { - mat = new QDiffuseMapMaterial; - } else { - mat = new QPhongMaterial; - } - } - - if (mat) { - for (QVariantHash::const_iterator it = params.constBegin(), itEnd = params.constEnd(); it != itEnd; ++it) - mat->setProperty(it.key().toUtf8(), it.value()); - } else { - qCWarning(GLTFParserLog) << "Could not find a suitable built-in material for KHR_materials_common"; - } - - return mat; -} - -QMaterial* GLTFParser::material(const QString &id) -{ - if (m_materialCache.contains(id)) - return m_materialCache.value(id); - - QJsonObject mats = m_json.object().value(KEY_MATERIALS).toObject(); - if (!mats.contains(id)) { - qCWarning(GLTFParserLog) << "unknown material" << id << "in GLTF file" << m_basePath; - return NULL; - } - - QJsonObject jsonObj = mats.value(id).toObject(); - - QMaterial *mat = nullptr; - - // Prefer common materials over custom shaders. - if (jsonObj.contains(KEY_EXTENSIONS)) { - QJsonObject extensions = jsonObj.value(KEY_EXTENSIONS).toObject(); - if (extensions.contains(KEY_COMMON_MAT)) - mat = commonMaterial(extensions.value(KEY_COMMON_MAT).toObject()); - } - - if (!mat) - mat = materialWithCustomShader(id, jsonObj); - - m_materialCache[id] = mat; - return mat; -} - -QCameraLens* GLTFParser::camera(const QString &id) const -{ - QJsonObject cams = m_json.object().value(KEY_CAMERAS).toObject(); - if (!cams.contains(id)) { - qCWarning(GLTFParserLog) << "unknown camera" << id << "in GLTF file" << m_basePath; - return nullptr; - } - - QJsonObject jsonObj = cams.value(id).toObject(); - QString camTy = jsonObj.value(KEY_TYPE).toString(); - - if (camTy == QStringLiteral("perspective")) { - if (!jsonObj.contains(KEY_PERSPECTIVE)) { - qCWarning(GLTFParserLog) << "camera:" << id << "missing 'perspective' object"; - return nullptr; - } - - QJsonObject pObj = jsonObj.value(KEY_PERSPECTIVE).toObject(); - double aspectRatio = pObj.value(KEY_ASPECT_RATIO).toDouble(); - double yfov = pObj.value(KEY_YFOV).toDouble(); - double frustumNear = pObj.value(KEY_ZNEAR).toDouble(); - double frustumFar = pObj.value(KEY_ZFAR).toDouble(); - - QCameraLens* result = new QCameraLens; - result->setPerspectiveProjection(yfov, aspectRatio, frustumNear, frustumFar); - return result; - } else if (camTy == QStringLiteral("orthographic")) { - qCWarning(GLTFParserLog) << Q_FUNC_INFO << "implement me"; - - return nullptr; - } else { - qCWarning(GLTFParserLog) << "camera:" << id << "has unsupported type:" << camTy; - return nullptr; - } -} - - -void GLTFParser::parse() -{ - if (m_parseDone) - return; - - QJsonObject buffers = m_json.object().value(KEY_BUFFERS).toObject(); - Q_FOREACH (QString nm, buffers.keys()) { - processJSONBuffer( nm, buffers.value(nm).toObject() ); - } - - QJsonObject views = m_json.object().value(KEY_BUFFER_VIEWS).toObject(); - loadBufferData(); - Q_FOREACH (QString nm, views.keys()) { - processJSONBufferView( nm, views.value(nm).toObject() ); - } - unloadBufferData(); - - QJsonObject shaders = m_json.object().value(KEY_SHADERS).toObject(); - Q_FOREACH (QString nm, shaders.keys()) { - processJSONShader( nm, shaders.value(nm).toObject() ); - } - - QJsonObject programs = m_json.object().value(KEY_PROGRAMS).toObject(); - Q_FOREACH (QString nm, programs.keys()) { - processJSONProgram( nm, programs.value(nm).toObject() ); - } - - QJsonObject techniques = m_json.object().value(KEY_TECHNIQUES).toObject(); - Q_FOREACH (QString nm, techniques.keys()) { - processJSONTechnique( nm, techniques.value(nm).toObject() ); - } - - QJsonObject attrs = m_json.object().value(KEY_ACCESSORS).toObject(); - Q_FOREACH (QString nm, attrs.keys()) { - processJSONAccessor( nm, attrs.value(nm).toObject() ); - } - - QJsonObject meshes = m_json.object().value(KEY_MESHES).toObject(); - Q_FOREACH (QString nm, meshes.keys()) { - processJSONMesh( nm, meshes.value(nm).toObject() ); - } - - QJsonObject images = m_json.object().value(KEY_IMAGES).toObject(); - Q_FOREACH (QString nm, images.keys()) { - processJSONImage( nm, images.value(nm).toObject() ); - } - - QJsonObject textures = m_json.object().value(KEY_TEXTURES).toObject(); - Q_FOREACH (QString nm, textures.keys()) { - processJSONTexture(nm, textures.value(nm).toObject() ); - } - - m_defaultScene = m_json.object().value(KEY_SCENE).toString(); - m_parseDone = true; -} - -void GLTFParser::cleanup() -{ - m_meshDict.clear(); - m_meshMaterialDict.clear(); - m_accessorDict.clear(); - //Check for Materials with no parent - Q_FOREACH (QMaterial *material, m_materialCache.values()) { - if (material->parent() == nullptr) - delete material; - } - m_materialCache.clear(); - m_bufferDatas.clear(); - m_buffers.clear(); - m_shaderPaths.clear(); - //Check for ShaderPrograms with no parent - Q_FOREACH (QShaderProgram *program, m_programs.values()) { - if (program->parent() == nullptr) - delete program; - } - m_programs.clear(); - //Check for Techniques with no parent - Q_FOREACH (QTechnique *technique, m_techniques.values()) { - if (technique->parent() == nullptr) - delete technique; - } - m_techniques.clear(); - //Check for Textures with no parent - Q_FOREACH (QAbstractTextureProvider *texture, m_textures.values()) { - if (texture->parent() == nullptr) - delete texture; - } - m_textures.clear(); - m_imagePaths.clear(); - m_defaultScene.clear(); - m_parameterDataDict.clear(); -} - -void GLTFParser::processJSONBuffer(const QString &id, const QJsonObject& json) -{ - // simply cache buffers for lookup by buffer-views - m_bufferDatas[id] = BufferData(json); -} - -void GLTFParser::processJSONBufferView(const QString &id, const QJsonObject& json) -{ - QString bufName = json.value(KEY_BUFFER).toString(); - if (!m_bufferDatas.contains(bufName)) { - qCWarning(GLTFParserLog) << "unknown buffer:" << bufName << "processing view:" << id; - return; - } - - int target = json.value(KEY_TARGET).toInt(); - QBuffer::BufferType ty(QBuffer::VertexBuffer); - - switch (target) { - case GL_ARRAY_BUFFER: ty = QBuffer::VertexBuffer; break; - case GL_ELEMENT_ARRAY_BUFFER: ty = QBuffer::IndexBuffer; break; - default: - qCWarning(GLTFParserLog) << Q_FUNC_INFO << "buffer" << id << "unsupported target:" << target; - return; - } - - quint64 offset = 0; - if (json.contains(KEY_BYTE_OFFSET)) { - offset = json.value(KEY_BYTE_OFFSET).toInt(); - qCDebug(GLTFParserLog) << "bv:" << id << "has offset:" << offset; - } - - quint64 len = json.value(KEY_BYTE_LENGTH).toInt(); - - QByteArray bytes(m_bufferDatas[bufName].data->mid(offset, len)); - if (bytes.count() != (int) len) { - qCWarning(GLTFParserLog) << "failed to read sufficient bytes from:" << m_bufferDatas[bufName].path - << "for view" << id; - } - - QBuffer *b(new QBuffer(ty)); - b->setData(bytes); - m_buffers[id] = b; -} - -void GLTFParser::processJSONShader(const QString &id, const QJsonObject &jsonObject) -{ - // shaders are trivial for the moment, defer the real work - // to the program section - QString path = jsonObject.value(KEY_URI).toString(); - - QFileInfo info(m_basePath, path); - if (!info.exists()) { - qCWarning(GLTFParserLog) << "can't find shader" << id << "from path" << path; - return; - } - - m_shaderPaths[id] = info.absoluteFilePath(); -} - -void GLTFParser::processJSONProgram(const QString &id, const QJsonObject &jsonObject) -{ - QShaderProgram* prog = new QShaderProgram; - prog->setObjectName(id); - - QString fragName = jsonObject.value(KEY_FRAGMENT_SHADER).toString(), - vertName = jsonObject.value(KEY_VERTEX_SHADER).toString(); - if (!m_shaderPaths.contains(fragName) || !m_shaderPaths.contains(vertName)) { - qCWarning(GLTFParserLog) << Q_FUNC_INFO << "program:" << id << "missing shader:" - << fragName << vertName; - return; - } - - prog->setFragmentShaderCode(QShaderProgram::loadSource(QUrl::fromLocalFile(m_shaderPaths[fragName]))); - prog->setVertexShaderCode(QShaderProgram::loadSource(QUrl::fromLocalFile(m_shaderPaths[vertName]))); - m_programs[id] = prog; -} - -void GLTFParser::processJSONTechnique(const QString &id, const QJsonObject &jsonObject ) -{ - QTechnique *t = new QTechnique; - t->setObjectName(id); - - // Parameters - QHash<QString, QParameter*> paramDict; - QJsonObject params = jsonObject.value(KEY_PARAMETERS).toObject(); - Q_FOREACH (QString pname, params.keys()) { - QJsonObject po = params.value(pname).toObject(); - - //QString semantic = po.value(KEY_SEMANTIC).toString(); - QParameter *p = new QParameter(t); - p->setName(pname); - m_parameterDataDict.insert(p, ParameterData(po)); - - //If the parameter has default value, set it - QJsonValue value = po.value(KEY_VALUE); - if (!value.isUndefined()) { - int dataType = po.value(KEY_TYPE).toInt(); - p->setValue(parameterValueFromJSON(dataType, value)); - } - - t->addParameter(p); - - paramDict[pname] = p; - } // of parameters iteration - - // Program - QString programName = jsonObject.value(KEY_PROGRAM).toString(); - if (!m_programs.contains(programName)) { - qCWarning(GLTFParserLog) << Q_FUNC_INFO << "technique" << id - << ": missing program" << programName; - } - - QRenderPass* pass = new QRenderPass; - pass->setShaderProgram(m_programs[programName]); - - // Attributes - QJsonObject attrs = jsonObject.value(KEY_ATTRIBUTES).toObject(); - Q_FOREACH ( QString shaderAttributeName, attrs.keys() ) { - QString pname = attrs.value(shaderAttributeName).toString(); - QParameter *parameter = paramDict.value(pname, nullptr); - QString attributeName = pname; - if (parameter == nullptr) { - qCWarning(GLTFParserLog) << Q_FUNC_INFO << "attribute " << pname - << "defined in instanceProgram but not as parameter"; - continue; - } - //Check if the parameter has a standard attribute semantic - QString standardAttributeName = standardAttributeNameFromSemantic(m_parameterDataDict[parameter].semantic); - if (!standardAttributeName.isNull()) { - attributeName = standardAttributeName; - t->removeParameter(parameter); - m_parameterDataDict.remove(parameter); - delete parameter; - } - - pass->addBinding(new QParameterMapping(attributeName, shaderAttributeName, QParameterMapping::Attribute)); - } // of program-instance attributes - - // Uniforms - QJsonObject uniforms = jsonObject.value(KEY_UNIFORMS).toObject(); - Q_FOREACH (QString shaderUniformName, uniforms.keys()) { - QString pname = uniforms.value(shaderUniformName).toString(); - QParameter *parameter = paramDict.value(pname, nullptr); - if (parameter == nullptr) { - qCWarning(GLTFParserLog) << Q_FUNC_INFO << "uniform " << pname - << "defined in instanceProgram but not as parameter"; - continue; - } - //Check if the parameter has a standard uniform semantic - QString standardUniformName = standardUniformNamefromSemantic(m_parameterDataDict[parameter].semantic); - if (standardUniformName.isNull()) { - pass->addBinding(new QParameterMapping(pname, shaderUniformName, QParameterMapping::Uniform)); - } else { - pass->addBinding(new QParameterMapping(standardUniformName, shaderUniformName, QParameterMapping::StandardUniform)); - t->removeParameter(parameter); - m_parameterDataDict.remove(parameter); - delete parameter; - } - } // of program-instance uniforms - - - // States - QJsonObject states = jsonObject.value(KEY_STATES).toObject(); - - //Process states to enable - QJsonArray enableStatesArray = states.value(KEY_ENABLE).toArray(); - QVector<int> enableStates; - Q_FOREACH (QJsonValue enableValue, enableStatesArray) { - enableStates.append(enableValue.toInt()); - } - - //Process the list of state functions - QJsonObject functions = states.value(KEY_FUNCTIONS).toObject(); - Q_FOREACH (QString functionName, functions.keys()) { - int enableStateType = 0; - QRenderState *renderState = buildState(functionName, functions.value(functionName), enableStateType); - if (renderState != nullptr) { - //Remove the need to set a default state values for enableStateType - enableStates.removeOne(enableStateType); - pass->addRenderState(renderState); - } - } - - //Create render states with default values for any remaining enable states - Q_FOREACH (int enableState, enableStates) { - QRenderState *renderState = buildStateEnable(enableState); - if (renderState != nullptr) - pass->addRenderState(renderState); - } - - - t->addPass(pass); - - m_techniques[id] = t; -} - -void GLTFParser::processJSONAccessor( const QString &id, const QJsonObject& json ) -{ - m_accessorDict[id] = AccessorData(json); -} - -void GLTFParser::processJSONMesh(const QString &id, const QJsonObject &json) -{ - QJsonArray primitivesArray = json.value(KEY_PRIMITIVES).toArray(); - Q_FOREACH (QJsonValue primitiveValue, primitivesArray) { - QJsonObject primitiveObject = primitiveValue.toObject(); - int type = primitiveObject.value(KEY_MODE).toInt(); - QString material = primitiveObject.value(KEY_MATERIAL).toString(); - - if ( material.isEmpty()) { - qCWarning(GLTFParserLog) << "malformed primitive on " << id << ", missing material value" - << material; - continue; - } - - QGeometryRenderer *geometryRenderer = new QGeometryRenderer; - QGeometry *meshGeometry = new QGeometry(geometryRenderer); - - //Set Primitive Type - geometryRenderer->setPrimitiveType(static_cast<QGeometryRenderer::PrimitiveType>(type)); - - //Save Material for mesh - m_meshMaterialDict[geometryRenderer] = material; - - QJsonObject attrs = primitiveObject.value(KEY_ATTRIBUTES).toObject(); - Q_FOREACH (QString attrName, attrs.keys()) { - QString k = attrs.value(attrName).toString(); - if (!m_accessorDict.contains(k)) { - qCWarning(GLTFParserLog) << "unknown attribute accessor:" << k << "on mesh" << id; - continue; - } - - QString attributeName = standardAttributeNameFromSemantic(attrName); - if (attributeName.isEmpty()) - attributeName = attrName; - - //Get buffer handle for accessor - QBuffer *buffer = m_buffers.value(m_accessorDict[k].bufferViewName, nullptr); - if (buffer == nullptr) { - qCWarning(GLTFParserLog) << "unknown buffer-view:" << m_accessorDict[k].bufferViewName << "processing accessor:" << id; - continue; - } - - QAttribute *attribute = new QAttribute(buffer, - attributeName, - m_accessorDict[k].type, - m_accessorDict[k].dataSize, - m_accessorDict[k].count, - m_accessorDict[k].offset, - m_accessorDict[k].stride); - attribute->setAttributeType(QAttribute::VertexAttribute); - meshGeometry->addAttribute(attribute); - } - - if ( primitiveObject.contains(KEY_INDICES)) { - QString k = primitiveObject.value(KEY_INDICES).toString(); - if (!m_accessorDict.contains(k)) { - qCWarning(GLTFParserLog) << "unknown index accessor:" << k << "on mesh" << id; - } else { - //Get buffer handle for accessor - QBuffer *buffer = m_buffers.value(m_accessorDict[k].bufferViewName, nullptr); - if (buffer == nullptr) { - qCWarning(GLTFParserLog) << "unknown buffer-view:" << m_accessorDict[k].bufferViewName << "processing accessor:" << id; - continue; - } - - QAttribute *attribute = new QAttribute(buffer, - m_accessorDict[k].type, - m_accessorDict[k].dataSize, - m_accessorDict[k].count, - m_accessorDict[k].offset, - m_accessorDict[k].stride); - attribute->setAttributeType(QAttribute::IndexAttribute); - meshGeometry->addAttribute(attribute); - } - } // of has indices - - geometryRenderer->setGeometry(meshGeometry); - - m_meshDict.insert( id, geometryRenderer); - } // of primitives iteration -} - -void GLTFParser::processJSONImage(const QString &id, const QJsonObject &jsonObject) -{ - QString path = jsonObject.value(KEY_URI).toString(); - QFileInfo info(m_basePath, path); - if (!info.exists()) { - qCWarning(GLTFParserLog) << "can't find image" << id << "from path" << path; - return; - } - - m_imagePaths[id] = info.absoluteFilePath(); -} - -void GLTFParser::processJSONTexture(const QString &id, const QJsonObject &jsonObject) -{ - int target = jsonObject.value(KEY_TARGET).toInt(GL_TEXTURE_2D); - //TODO: support other targets that GL_TEXTURE_2D (though the spec doesn't support anything else) - if (target != GL_TEXTURE_2D) { - qCWarning(GLTFParserLog) << "unsupported texture target: " << target; - return; - } - - QTexture2D* tex = new QTexture2D; - - // TODO: Choose suitable internal format - may vary on OpenGL context type - //int pixelFormat = jsonObj.value(KEY_FORMAT).toInt(GL_RGBA); - int internalFormat = jsonObject.value(KEY_INTERNAL_FORMAT).toInt(GL_RGBA); - - tex->setFormat(static_cast<QAbstractTextureProvider::TextureFormat>(internalFormat)); - - QString samplerId = jsonObject.value(KEY_SAMPLER).toString(); - QString source = jsonObject.value(KEY_SOURCE).toString(); - if (!m_imagePaths.contains(source)) { - qCWarning(GLTFParserLog) << "texture" << id << "references missing image" << source; - return; - } - - QTextureImage *texImage = new QTextureImage(tex); - texImage->setSource(QUrl::fromLocalFile(m_imagePaths[source])); - tex->addTextureImage(texImage); - - QJsonObject samplersDict(m_json.object().value(KEY_SAMPLERS).toObject()); - if (!samplersDict.contains(samplerId)) { - qCWarning(GLTFParserLog) << "texture" << id << "references unknown sampler" << samplerId; - return; - } - - QJsonObject sampler = samplersDict.value(samplerId).toObject(); - - tex->setWrapMode(QTextureWrapMode(static_cast<QTextureWrapMode::WrapMode>(sampler.value(KEY_WRAP_S).toInt()))); - tex->setMinificationFilter(static_cast<QAbstractTextureProvider::Filter>(sampler.value(KEY_MIN_FILTER).toInt())); - if (tex->minificationFilter() == QAbstractTextureProvider::NearestMipMapLinear || - tex->minificationFilter() == QAbstractTextureProvider::LinearMipMapNearest || - tex->minificationFilter() == QAbstractTextureProvider::NearestMipMapNearest || - tex->minificationFilter() == QAbstractTextureProvider::LinearMipMapLinear) { - - tex->setGenerateMipMaps(true); - } - tex->setMagnificationFilter(static_cast<QAbstractTextureProvider::Filter>(sampler.value(KEY_MAG_FILTER).toInt())); - - m_textures[id] = tex; -} - -void GLTFParser::loadBufferData() -{ - Q_FOREACH (QString bufferName, m_bufferDatas.keys()) { - if (m_bufferDatas[bufferName].data == nullptr) { - QFile* bufferFile = resolveLocalData(m_bufferDatas[bufferName].path); - QByteArray *data = new QByteArray(bufferFile->readAll()); - m_bufferDatas[bufferName].data = data; - delete bufferFile; - } - } -} - -void GLTFParser::unloadBufferData() -{ - Q_FOREACH (QString bufferName, m_bufferDatas.keys()) { - QByteArray *data = m_bufferDatas[bufferName].data; - delete data; - } -} - -QFile *GLTFParser::resolveLocalData(QString path) const -{ - QDir d(m_basePath); - Q_ASSERT(d.exists()); - - QString absPath = d.absoluteFilePath(path); - QFile* f = new QFile(absPath); - f->open(QIODevice::ReadOnly); - return f; -} - -QVariant GLTFParser::parameterValueFromJSON(int type, const QJsonValue &value) const -{ - if (value.isBool()) { - if (type == GL_BOOL) - return QVariant(static_cast<GLboolean>(value.toBool())); - } else if (value.isString()) { - if (type == GL_SAMPLER_2D) { - //Textures are special because we need to do a lookup to return the - //QAbstractTextureProvider - QString textureId = value.toString(); - if (!m_textures.contains(textureId)) { - qCWarning(GLTFParserLog) << "unknown texture" << textureId; - return QVariant(); - } else { - return QVariant::fromValue(m_textures.value(textureId)); - } - } - } else if (value.isDouble()) { - switch (type) { - case GL_BYTE: - return QVariant(static_cast<GLbyte>(value.toInt())); - case GL_UNSIGNED_BYTE: - return QVariant(static_cast<GLubyte>(value.toInt())); - case GL_SHORT: - return QVariant(static_cast<GLshort>(value.toInt())); - case GL_UNSIGNED_SHORT: - return QVariant(static_cast<GLushort>(value.toInt())); - case GL_INT: - return QVariant(static_cast<GLint>(value.toInt())); - case GL_UNSIGNED_INT: - return QVariant(static_cast<GLuint>(value.toInt())); - case GL_FLOAT: - return QVariant(static_cast<GLfloat>(value.toDouble())); - } - } else if (value.isArray()) { - - QJsonArray valueArray = value.toArray(); - - QVector2D vector2D; - QVector3D vector3D; - QVector4D vector4D; - QVector<float> dataMat2(4, 0.0f); - QVector<float> dataMat3(9, 0.0f); - - switch (type) { - case GL_BYTE: - return QVariant(static_cast<GLbyte>(valueArray.first().toInt())); - case GL_UNSIGNED_BYTE: - return QVariant(static_cast<GLubyte>(valueArray.first().toInt())); - case GL_SHORT: - return QVariant(static_cast<GLshort>(valueArray.first().toInt())); - case GL_UNSIGNED_SHORT: - return QVariant(static_cast<GLushort>(valueArray.first().toInt())); - case GL_INT: - return QVariant(static_cast<GLint>(valueArray.first().toInt())); - case GL_UNSIGNED_INT: - return QVariant(static_cast<GLuint>(valueArray.first().toInt())); - case GL_FLOAT: - return QVariant(static_cast<GLfloat>(valueArray.first().toDouble())); - case GL_FLOAT_VEC2: - vector2D.setX(static_cast<GLfloat>(valueArray.at(0).toDouble())); - vector2D.setY(static_cast<GLfloat>(valueArray.at(1).toDouble())); - return QVariant(vector2D); - case GL_FLOAT_VEC3: - vector3D.setX(static_cast<GLfloat>(valueArray.at(0).toDouble())); - vector3D.setY(static_cast<GLfloat>(valueArray.at(1).toDouble())); - vector3D.setZ(static_cast<GLfloat>(valueArray.at(2).toDouble())); - return QVariant(vector3D); - case GL_FLOAT_VEC4: - vector4D.setX(static_cast<GLfloat>(valueArray.at(0).toDouble())); - vector4D.setY(static_cast<GLfloat>(valueArray.at(1).toDouble())); - vector4D.setZ(static_cast<GLfloat>(valueArray.at(2).toDouble())); - vector4D.setW(static_cast<GLfloat>(valueArray.at(3).toDouble())); - return QVariant(vector4D); - case GL_INT_VEC2: - vector2D.setX(static_cast<GLint>(valueArray.at(0).toInt())); - vector2D.setY(static_cast<GLint>(valueArray.at(1).toInt())); - return QVariant(vector2D); - case GL_INT_VEC3: - vector3D.setX(static_cast<GLint>(valueArray.at(0).toInt())); - vector3D.setY(static_cast<GLint>(valueArray.at(1).toInt())); - vector3D.setZ(static_cast<GLint>(valueArray.at(2).toInt())); - return QVariant(vector3D); - case GL_INT_VEC4: - vector4D.setX(static_cast<GLint>(valueArray.at(0).toInt())); - vector4D.setY(static_cast<GLint>(valueArray.at(1).toInt())); - vector4D.setZ(static_cast<GLint>(valueArray.at(2).toInt())); - vector4D.setW(static_cast<GLint>(valueArray.at(3).toInt())); - return QVariant(vector4D); - case GL_BOOL: - return QVariant(static_cast<GLboolean>(valueArray.first().toBool())); - case GL_BOOL_VEC2: - vector2D.setX(static_cast<GLboolean>(valueArray.at(0).toBool())); - vector2D.setY(static_cast<GLboolean>(valueArray.at(1).toBool())); - return QVariant(vector2D); - case GL_BOOL_VEC3: - vector3D.setX(static_cast<GLboolean>(valueArray.at(0).toBool())); - vector3D.setY(static_cast<GLboolean>(valueArray.at(1).toBool())); - vector3D.setZ(static_cast<GLboolean>(valueArray.at(2).toBool())); - return QVariant(vector3D); - case GL_BOOL_VEC4: - vector4D.setX(static_cast<GLboolean>(valueArray.at(0).toBool())); - vector4D.setY(static_cast<GLboolean>(valueArray.at(1).toBool())); - vector4D.setZ(static_cast<GLboolean>(valueArray.at(2).toBool())); - vector4D.setW(static_cast<GLboolean>(valueArray.at(3).toBool())); - return QVariant(vector4D); - case GL_FLOAT_MAT2: - //Matrix2x2 is in Row Major ordering (so we need to convert) - dataMat2[0] = static_cast<GLfloat>(valueArray.at(0).toDouble()); - dataMat2[1] = static_cast<GLfloat>(valueArray.at(2).toDouble()); - dataMat2[2] = static_cast<GLfloat>(valueArray.at(1).toDouble()); - dataMat2[3] = static_cast<GLfloat>(valueArray.at(3).toDouble()); - return QVariant::fromValue(QMatrix2x2(dataMat2.constData())); - case GL_FLOAT_MAT3: - //Matrix3x3 is in Row Major ordering (so we need to convert) - dataMat3[0] = static_cast<GLfloat>(valueArray.at(0).toDouble()); - dataMat3[1] = static_cast<GLfloat>(valueArray.at(3).toDouble()); - dataMat3[2] = static_cast<GLfloat>(valueArray.at(6).toDouble()); - dataMat3[3] = static_cast<GLfloat>(valueArray.at(1).toDouble()); - dataMat3[4] = static_cast<GLfloat>(valueArray.at(4).toDouble()); - dataMat3[5] = static_cast<GLfloat>(valueArray.at(7).toDouble()); - dataMat3[6] = static_cast<GLfloat>(valueArray.at(2).toDouble()); - dataMat3[7] = static_cast<GLfloat>(valueArray.at(5).toDouble()); - dataMat3[8] = static_cast<GLfloat>(valueArray.at(8).toDouble()); - return QVariant::fromValue(QMatrix3x3(dataMat3.constData())); - case GL_FLOAT_MAT4: - //Matrix4x4 is Column Major ordering - return QVariant(QMatrix4x4(static_cast<GLfloat>(valueArray.at(0).toDouble()), - static_cast<GLfloat>(valueArray.at(1).toDouble()), - static_cast<GLfloat>(valueArray.at(2).toDouble()), - static_cast<GLfloat>(valueArray.at(3).toDouble()), - static_cast<GLfloat>(valueArray.at(4).toDouble()), - static_cast<GLfloat>(valueArray.at(5).toDouble()), - static_cast<GLfloat>(valueArray.at(6).toDouble()), - static_cast<GLfloat>(valueArray.at(7).toDouble()), - static_cast<GLfloat>(valueArray.at(8).toDouble()), - static_cast<GLfloat>(valueArray.at(9).toDouble()), - static_cast<GLfloat>(valueArray.at(10).toDouble()), - static_cast<GLfloat>(valueArray.at(11).toDouble()), - static_cast<GLfloat>(valueArray.at(12).toDouble()), - static_cast<GLfloat>(valueArray.at(13).toDouble()), - static_cast<GLfloat>(valueArray.at(14).toDouble()), - static_cast<GLfloat>(valueArray.at(15).toDouble()))); - case GL_SAMPLER_2D: - return QVariant(valueArray.at(0).toString()); - } - } - return QVariant(); -} - -QAttribute::DataType GLTFParser::accessorTypeFromJSON(int componentType) -{ - if (componentType == GL_BYTE) { - return QAttribute::Byte; - } else if (componentType == GL_UNSIGNED_BYTE) { - return QAttribute::UnsignedByte; - } else if (componentType == GL_SHORT) { - return QAttribute::Short; - } else if (componentType == GL_UNSIGNED_SHORT) { - return QAttribute::UnsignedShort; - } else if (componentType == GL_UNSIGNED_INT) { - return QAttribute::UnsignedInt; - } else if (componentType == GL_FLOAT) { - return QAttribute::Float; - } - - //There shouldn't be an invalid case here - qCWarning(GLTFParserLog) << "unsupported accessor type" << componentType; - return QAttribute::Float; -} - -uint GLTFParser::accessorDataSizeFromJson(const QString &type) -{ - QString typeName = type.toUpper(); - if (typeName == "SCALAR") - return 1; - if (typeName == "VEC2") - return 2; - if (typeName == "VEC3") - return 3; - if (typeName == "VEC4") - return 4; - if (typeName == "MAT2") - return 4; - if (typeName == "MAT3") - return 9; - if (typeName == "MAT4") - return 16; - - return 0; -} - -QRenderState *GLTFParser::buildStateEnable(int state) -{ - int type = 0; - //By calling buildState with QJsonValue(), a Render State with - //default values is created. - - if (state == GL_BLEND) { - //It doesn't make sense to handle this state alone - return nullptr; - } - - if (state == GL_CULL_FACE) { - return buildState(QStringLiteral("cullFace"), QJsonValue(), type); - } - - if (state == GL_DEPTH_TEST) { - return buildState(QStringLiteral("depthFunc"), QJsonValue(), type); - } - - if (state == GL_POLYGON_OFFSET_FILL) { - return buildState(QStringLiteral("polygonOffset"), QJsonValue(), type); - } - - if (state == GL_SAMPLE_ALPHA_TO_COVERAGE) { - return new QAlphaCoverage(); - } - - if (state == GL_SCISSOR_TEST) { - return buildState(QStringLiteral("scissor"), QJsonValue(), type); - } - - qCWarning(GLTFParserLog) << Q_FUNC_INFO << "unsupported render state:" << state; - - return nullptr; -} - -QRenderState* GLTFParser::buildState(const QString& functionName, const QJsonValue &value, int &type) -{ - type = -1; - QJsonArray values = value.toArray(); - - if (functionName == QStringLiteral("blendColor")) { - type = GL_BLEND; - //TODO: support render state blendColor - qCWarning(GLTFParserLog) << Q_FUNC_INFO << "unsupported render state:" << functionName; - return nullptr; - } - - if (functionName == QStringLiteral("blendEquationSeparate")) { - type = GL_BLEND; - //TODO: support settings blendEquation alpha - QBlendEquation *blendEquation = new QBlendEquation; - blendEquation->setMode((QBlendEquation::BlendMode)values.at(0).toInt(GL_FUNC_ADD)); - return blendEquation; - } - - if (functionName == QStringLiteral("blendFuncSeparate")) { - type = GL_BLEND; - QBlendStateSeparate *blendState = new QBlendStateSeparate; - blendState->setSrcRGB((QBlendState::Blending)values.at(0).toInt(GL_ONE)); - blendState->setSrcAlpha((QBlendState::Blending)values.at(1).toInt(GL_ONE)); - blendState->setDstRGB((QBlendState::Blending)values.at(2).toInt(GL_ZERO)); - blendState->setDstAlpha((QBlendState::Blending)values.at(3).toInt(GL_ZERO)); - return blendState; - } - - if (functionName == QStringLiteral("colorMask")) { - QColorMask *colorMask = new QColorMask; - colorMask->setRed(values.at(0).toBool(true)); - colorMask->setGreen(values.at(1).toBool(true)); - colorMask->setBlue(values.at(2).toBool(true)); - colorMask->setAlpha(values.at(3).toBool(true)); - return colorMask; - } - - if (functionName == QStringLiteral("cullFace")) { - type = GL_CULL_FACE; - QCullFace *cullFace = new QCullFace; - cullFace->setMode((QCullFace::CullingMode)values.at(0).toInt(GL_BACK)); - return cullFace; - } - - if (functionName == QStringLiteral("depthFunc")) { - type = GL_DEPTH_TEST; - QDepthTest *depthTest = new QDepthTest; - depthTest->setFunc((QDepthTest::DepthFunc)values.at(0).toInt(GL_LESS)); - return depthTest; - } - - if (functionName == QStringLiteral("depthMask")) { - QDepthMask *depthMask = new QDepthMask; - depthMask->setMask(values.at(0).toBool(true)); - } - - if (functionName == QStringLiteral("depthRange")) { - //TODO: support render state depthRange - qCWarning(GLTFParserLog) << Q_FUNC_INFO << "unsupported render state:" << functionName; - return nullptr; - } - - if (functionName == QStringLiteral("frontFace")) { - QFrontFace *frontFace = new QFrontFace; - frontFace->setDirection((QFrontFace::FaceDir)values.at(0).toInt(GL_CCW)); - return frontFace; - } - - if (functionName == QStringLiteral("lineWidth")) { - //TODO: support render state lineWidth - qCWarning(GLTFParserLog) << Q_FUNC_INFO << "unsupported render state:" << functionName; - return nullptr; - } - - if (functionName == QStringLiteral("polygonOffset")) { - type = GL_POLYGON_OFFSET_FILL; - QPolygonOffset *polygonOffset = new QPolygonOffset; - polygonOffset->setFactor((float)values.at(0).toDouble(0.0f)); - polygonOffset->setUnits((float)values.at(1).toDouble(0.0f)); - return polygonOffset; - } - - if (functionName == QStringLiteral("scissor")) { - type = GL_SCISSOR_TEST; - QScissorTest *scissorTest = new QScissorTest; - scissorTest->setLeft(values.at(0).toDouble(0.0f)); - scissorTest->setBottom(values.at(1).toDouble(0.0f)); - scissorTest->setWidth(values.at(2).toDouble(0.0f)); - scissorTest->setHeight(values.at(3).toDouble(0.0f)); - return scissorTest; - } - - qCWarning(GLTFParserLog) << Q_FUNC_INFO << "unsupported render state:" << functionName; - return nullptr; -} - -} // namespace Qt3DRender - -QT_END_NAMESPACE diff --git a/src/quick3d/imports/scene3d/scene3drenderer.cpp b/src/quick3d/imports/scene3d/scene3drenderer.cpp index ca637f830..bda8e7343 100644 --- a/src/quick3d/imports/scene3d/scene3drenderer.cpp +++ b/src/quick3d/imports/scene3d/scene3drenderer.cpp @@ -313,6 +313,7 @@ void Scene3DRenderer::synchronize() m_lastMultisample = m_multisample; m_node->markDirty(QSGNode::DirtyMaterial); + m_item->update(); } } diff --git a/src/render/backend/commandexecuter.cpp b/src/render/backend/commandexecuter.cpp index 54c3548ba..8bccb1437 100644 --- a/src/render/backend/commandexecuter.cpp +++ b/src/render/backend/commandexecuter.cpp @@ -265,7 +265,7 @@ QJsonObject parameterPackToJson(const Render::ShaderParameterPack &pack) for (const auto & texture : textures) { QJsonObject textureObj; textureObj.insert(QLatin1String("name"), Render::StringToInt::lookupString(texture.glslNameId)); - textureObj.insert(QLatin1String("id"), qint64(texture.texId.id())); + textureObj.insert(QLatin1String("id"), qint64(texture.nodeId.id())); texturesArray.push_back(textureObj); } obj.insert(QLatin1String("textures"), texturesArray); diff --git a/src/render/backend/managers.cpp b/src/render/backend/managers.cpp index 26fd68600..aa7dbb741 100644 --- a/src/render/backend/managers.cpp +++ b/src/render/backend/managers.cpp @@ -110,6 +110,12 @@ void JointManager::addDirtyJoint(Qt3DCore::QNodeId jointId) m_dirtyJoints.push_back(jointHandle); } +void JointManager::removeDirtyJoint(Qt3DCore::QNodeId jointId) +{ + const HJoint jointHandle = lookupHandle(jointId); + m_dirtyJoints.removeAll(jointHandle); +} + QVector<HJoint> JointManager::dirtyJoints() { return std::move(m_dirtyJoints); diff --git a/src/render/backend/managers_p.h b/src/render/backend/managers_p.h index 89b02b86f..759c16f64 100644 --- a/src/render/backend/managers_p.h +++ b/src/render/backend/managers_p.h @@ -443,6 +443,7 @@ class JointManager : public Qt3DCore::QResourceManager< { public: void addDirtyJoint(Qt3DCore::QNodeId jointId); + void removeDirtyJoint(Qt3DCore::QNodeId jointId); QVector<HJoint> dirtyJoints(); private: diff --git a/src/render/backend/uniform.cpp b/src/render/backend/uniform.cpp index 41ee24967..17c26e6c7 100644 --- a/src/render/backend/uniform.cpp +++ b/src/render/backend/uniform.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include "uniform_p.h" +#include "qabstracttexture.h" QT_BEGIN_NAMESPACE @@ -261,6 +262,11 @@ UniformValue UniformValue::fromVariant(const QVariant &variant) memcpy(v.data<float>(), mat33.constData(), 9 * sizeof(float)); break; } + if (variant.userType() == qMetaTypeId<Qt3DRender::QAbstractTexture *>()) { + // silently ignore null texture pointers as they are common while textures are loading + if (variant.value<Qt3DRender::QAbstractTexture *>() == nullptr) + break; + } qWarning() << "Unknown uniform type or value:" << variant << "Please check your QParameters"; } } diff --git a/src/render/framegraph/qclearbuffers.cpp b/src/render/framegraph/qclearbuffers.cpp index 67773a6b7..4cc4c98b6 100644 --- a/src/render/framegraph/qclearbuffers.cpp +++ b/src/render/framegraph/qclearbuffers.cpp @@ -220,7 +220,7 @@ void QClearBuffers::setClearStencilValue(int clearStencilValue) ColorBuffer flag is set, all color buffers will be cleared. */ /*! - \qmlproperty RenderTargetOutput Qt3D.Render::ClearBuffers::colorbuffer + \qmlproperty RenderTargetOutput Qt3D.Render::ClearBuffers::colorBuffer Specifies a specific color buffer to clear. If set to NULL (default), and ColorBuffer flag is set, all color buffers will be cleared. */ diff --git a/src/render/frontend/qcamera.cpp b/src/render/frontend/qcamera.cpp index 274b555f6..29703878d 100644 --- a/src/render/frontend/qcamera.cpp +++ b/src/render/frontend/qcamera.cpp @@ -254,11 +254,14 @@ void QCameraPrivate::updateViewMatrixAndTransform(bool doEmit) /*! * \qmlproperty enumeration Qt3D.Render::Camera::projectionType * - * Holds the type of the camera projection. + * Holds the type of the camera projection. The default value is + * CameraLens.PerspectiveProjection. * * \list - * \li CameraLens.OrthographicProjection - * \li CameraLens.PerspectiveProjection + * \li CameraLens.OrthographicProjection - Parallel lines appear parallel. Objects appear + * the same size regardless of distance. + * \li CameraLens.PerspectiveProjection - Parallel lines appear to meet in the distance. + * Objects appear to shrink the farther they are from the camera. * \li CameraLens.FrustumProjection * \li CameraLens.CustomProjection * \endlist @@ -267,17 +270,28 @@ void QCameraPrivate::updateViewMatrixAndTransform(bool doEmit) /*! * \qmlproperty real Qt3D.Render::Camera::nearPlane - * Holds the current camera near plane of the camera. + * Holds the current camera near plane of the camera. Objects that + * are closer to the camera than the nearPlane will not be rendered. */ /*! * \qmlproperty real Qt3D.Render::Camera::farPlane - * Holds the current camera far plane of the camera. + * Holds the current camera far plane of the camera. Objects that + * are farther from the camera than the farPlane will not be rendered. */ /*! * \qmlproperty real Qt3D.Render::Camera::fieldOfView - * Holds the current field of view of the camera in degrees. + * Holds the current vertical field of view of the camera in degrees. + * + * Along with \l aspectRatio, this property determines how much of + * the scene is visible to the camera. In that respect you might + * think of it as analogous to choosing a wide angle (wide horizontal + * field of view) or telephoto (narrow horizontal field of view) lens, + * depending on how much of a scene you want to capture. + * + * fieldOfView is only relevant when \l projectionType is + * CameraLens.PerspectiveProjection. */ /*! @@ -288,21 +302,33 @@ void QCameraPrivate::updateViewMatrixAndTransform(bool doEmit) /*! *\qmlproperty real Qt3D.Render::Camera::left * Holds the current left of the camera. + * + * This property is only relevant when \l projectionType is + * CameraLens.OrthographicProjection. */ /*! * \qmlproperty real Qt3D.Render::Camera::right * Holds the current right of the camera. + * + * This property is only relevant when \l projectionType is + * CameraLens.OrthographicProjection. */ /*! * \qmlproperty real Qt3D.Render::Camera::bottom * Holds the current bottom of the camera. + * + * This property is only relevant when \l projectionType is + * CameraLens.OrthographicProjection. */ /*! * \qmlproperty real Qt3D.Render::Camera::top * Holds the current top of the camera. + * + * This property is only relevant when \l projectionType is + * CameraLens.OrthographicProjection. */ /*! @@ -321,19 +347,29 @@ void QCameraPrivate::updateViewMatrixAndTransform(bool doEmit) * \qmlproperty vector3d Qt3D.Render::Camera::upVector * Holds the current up vector of the camera in coordinates relative to * the parent entity. + * + * The up vector indicates which direction the top of the camera is + * facing. Think of taking a picture: after positioning yourself + * and pointing the camera at your target, you might rotate the camera + * left or right, giving you a portrait or landscape (or angled!) + * shot. upVector allows you to control this type of movement. */ /*! * \qmlproperty vector3d Qt3D.Render::Camera::viewCenter * Holds the current view center of the camera in coordinates relative to * the parent entity. - * \readonly + * + * Intuitively, the viewCenter is the location the camera is pointing at. */ /*! * \qmlproperty vector3d Qt3D.Render::Camera::viewVector * Holds the camera's view vector in coordinates relative to * the parent entity. + * + * This vector decribes the displacement from the camera (\l position) + * to its target (\l viewCenter). * \readonly */ @@ -348,30 +384,44 @@ void QCameraPrivate::updateViewMatrixAndTransform(bool doEmit) /*! * \property QCamera::projectionType * - * Holds the type of the camera projection. + * Holds the type of the camera projection. The default value is + * QCameraLens::PerspectiveProjection. * * \list - * \li CameraLens.OrthographicProjection - * \li CameraLens.PerspectiveProjection - * \li CameraLens.FrustumProjection - * \li CameraLens.CustomProjection + * \li QCameraLens::OrthographicProjection - Parallel lines appear parallel. Objects appear + * the same size regardless of distance. + * \li QCameraLens::PerspectiveProjection - Parallel lines appear to meet in the distance. + * Objects appear to shrink the farther they are from the camera. + * \li QCameraLens::FrustumProjection + * \li QCameraLens::CustomProjection * \endlist * \sa Qt3DRender::QCameraLens::ProjectionType */ /*! * \property QCamera::nearPlane - * Holds the current camera near plane. + * Holds the current camera near plane. Objects that are closer to the + * camera than the nearPlane will not be rendered. */ /*! * \property QCamera::farPlane - * Holds the current camera far plane. + * Holds the current camera far plane. Objects that are farther from the + * camera than the farPlane will not be rendered. */ /*! * \property QCamera::fieldOfView - * Holds the current field of view in degrees. + * Holds the current vertical field of view in degrees. + * + * Along with \l aspectRatio, this property determines how much of + * the scene is visible to the camera. In that respect you might + * think of it as analogous to choosing a wide angle (wide horizontal + * field of view) or telephoto (narrow horizontal field of view) lens + * depending on how much of a scene you want to capture. + * + * fieldOfView is only relevant when \l projectionType is + * QCameraLens::PerspectiveProjection. */ /*! @@ -382,21 +432,33 @@ void QCameraPrivate::updateViewMatrixAndTransform(bool doEmit) /*! *\property QCamera::left * Holds the current left of the camera. + * + * This property is only relevant when \l projectionType is + * QCameraLens::OrthographicProjection. */ /*! * \property QCamera::right * Holds the current right of the camera. + * + * This property is only relevant when \l projectionType is + * QCameraLens::OrthographicProjection. */ /*! * \property QCamera::bottom * Holds the current bottom of the camera. + * + * This property is only relevant when \l projectionType is + * QCameraLens::OrthographicProjection. */ /*! * \property QCamera::top * Holds the current top of the camera. + * + * This property is only relevant when \l projectionType is + * QCameraLens::OrthographicProjection. */ /*! @@ -419,18 +481,29 @@ void QCameraPrivate::updateViewMatrixAndTransform(bool doEmit) * \property QCamera::upVector * Holds the camera's up vector in coordinates relative to * the parent entity. + * + * The up vector indicates which direction the top of the camera is + * facing. Think of taking a picture: after positioning yourself + * and pointing the camera at your target, you might rotate the camera + * left or right, giving you a portrait or landscape (or angled!) + * shot. upVector allows you to control this type of movement. */ /*! * \property QCamera::viewCenter * Holds the camera's view center in coordinates relative to * the parent entity. + * + * Intuitively, the viewCenter is the location the camera is pointing at. */ /*! * \property QCamera::viewVector * Holds the camera's view vector in coordinates relative to * the parent entity. + * + * This vector decribes the displacement from the camera (\l position) + * to its target (\l viewCenter). */ /*! diff --git a/src/render/geometry/joint.cpp b/src/render/geometry/joint.cpp index 9c53b8ef8..c770564f9 100644 --- a/src/render/geometry/joint.cpp +++ b/src/render/geometry/joint.cpp @@ -153,6 +153,7 @@ Qt3DCore::QBackendNode *JointFunctor::get(Qt3DCore::QNodeId id) const void JointFunctor::destroy(Qt3DCore::QNodeId id) const { + m_jointManager->removeDirtyJoint(id); m_jointManager->releaseResource(id); } diff --git a/src/render/lights/qdirectionallight.cpp b/src/render/lights/qdirectionallight.cpp index 14bdb2c38..9b6e580de 100644 --- a/src/render/lights/qdirectionallight.cpp +++ b/src/render/lights/qdirectionallight.cpp @@ -76,6 +76,9 @@ QDirectionalLightPrivate::QDirectionalLightPrivate() \since 5.7 \brief Encapsulate a Directional Light object in a Qt 3D scene. + A directional light is a light source that behaves similar to sunlight. + The light from a directional light hits all objects from the same direction + and with the same intensity, regardless of where they are in the scene. */ /*! @@ -86,6 +89,9 @@ QDirectionalLightPrivate::QDirectionalLightPrivate() \since 5.7 \brief Encapsulate a Directional Light object in a Qt 3D scene. + A directional light is a light source that behaves similar to sunlight. + The light from a directional light hits all objects from the same direction + and with the same intensity, regardless of where they are in the scene. */ /*! diff --git a/src/render/lights/qenvironmentlight.cpp b/src/render/lights/qenvironmentlight.cpp index 866905fb6..b3dac56ff 100644 --- a/src/render/lights/qenvironmentlight.cpp +++ b/src/render/lights/qenvironmentlight.cpp @@ -53,6 +53,9 @@ namespace Qt3DRender * \instantiates Qt3DRender::QEnvironmentLight * \brief Encapsulate an environment light object in a Qt 3D scene. * \since 5.9 + * + * EnvironmentLight uses cubemaps to implement image-based lighting (IBL), a technique + * often used in conjunction with physically-based rendering (PBR). */ QEnvironmentLightPrivate::QEnvironmentLightPrivate() @@ -97,6 +100,9 @@ Qt3DCore::QNodeCreatedChangeBasePtr QEnvironmentLight::createNodeCreationChange( \inmodule Qt3DRender \brief Encapsulate an environment light object in a Qt 3D scene. \since 5.9 + + EnvironmentLight uses cubemaps to implement image-based lighting (IBL), a technique + often used in conjunction with physically-based rendering (PBR). */ QEnvironmentLight::QEnvironmentLight(Qt3DCore::QNode *parent) diff --git a/src/render/lights/qpointlight.cpp b/src/render/lights/qpointlight.cpp index 28dd265b8..2b042c91d 100644 --- a/src/render/lights/qpointlight.cpp +++ b/src/render/lights/qpointlight.cpp @@ -75,6 +75,19 @@ QPointLightPrivate::QPointLightPrivate() \since 5.5 \brief Encapsulate a Point Light object in a Qt 3D scene. + A point light is a light source that emits light in all directions, from a single point. + Conceptually, this is similar to light given off by a standard light bulb. + + A point light uses three attenuation factors to describe how the intensity of the light + decreases over distance. These factors are designed to be used together in calcuating total + attenuation. For the materials in Qt3D Extras the following formula is used, where distance + is the distance from the light to the surface being rendered: + + \code + totalAttenuation = 1.0 / (constantAttenuation + (linearAttenuation * distance) + (quadraticAttenuation * distance * distance)); + \endcode + + Custom materials may choose to interpret these factors differently. */ /*! @@ -84,6 +97,20 @@ QPointLightPrivate::QPointLightPrivate() \inqmlmodule Qt3D.Render \since 5.5 \brief Encapsulate a Point Light object in a Qt 3D scene. + + A point light is a light source that emits light in all directions, from a single point. + Conceptually, this is similar to light given off by a standard light bulb. + + A point light uses three attenuation factors to describe how the intensity of the light + decreases over distance. These factors are designed to be used together in calcuating total + attenuation. For the materials in Qt3D Extras the following formula is used, where distance + is the distance from the light to the surface being rendered: + + \code + totalAttenuation = 1.0 / (constantAttenuation + (linearAttenuation * distance) + (quadraticAttenuation * distance * distance)); + \endcode + + Custom materials may choose to interpret these factors differently. */ /*! diff --git a/src/render/lights/qspotlight.cpp b/src/render/lights/qspotlight.cpp index 81c18387b..c4deaf817 100644 --- a/src/render/lights/qspotlight.cpp +++ b/src/render/lights/qspotlight.cpp @@ -83,6 +83,18 @@ QSpotLightPrivate::QSpotLightPrivate() \since 5.5 \brief Encapsulate a Spot Light object in a Qt 3D scene. + A spotlight is a light source that emits a cone of light in a particular direction. + + A spotlight uses three attenuation factors to describe how the intensity of the light + decreases over distance. These factors are designed to be used together in calcuating total + attenuation. For the materials in Qt3D Extras the following formula is used, where distance + is the distance from the light to the surface being rendered: + + \code + totalAttenuation = 1.0 / (constantAttenuation + (linearAttenuation * distance) + (quadraticAttenuation * distance * distance)); + \endcode + + Custom materials may choose to interpret these factors differently. */ /*! @@ -93,6 +105,18 @@ QSpotLightPrivate::QSpotLightPrivate() \since 5.5 \brief Encapsulate a Spot Light object in a Qt 3D scene. + A spotlight is a light source that emits a cone of light in a particular direction. + + A spotlight uses three attenuation factors to describe how the intensity of the light + decreases over distance. These factors are designed to be used together in calcuating total + attenuation. For the materials in Qt3D Extras the following formula is used, where distance + is the distance from the light to the surface being rendered: + + \code + totalAttenuation = 1.0 / (constantAttenuation + (linearAttenuation * distance) + (quadraticAttenuation * distance * distance)); + \endcode + + Custom materials may choose to interpret these factors differently. */ /*! diff --git a/src/render/materialsystem/qshaderimage_p.h b/src/render/materialsystem/qshaderimage_p.h index 93eb8635d..33cffb84a 100644 --- a/src/render/materialsystem/qshaderimage_p.h +++ b/src/render/materialsystem/qshaderimage_p.h @@ -40,6 +40,17 @@ #ifndef QT3DRENDER_QSHADERIMAGE_P_H #define QT3DRENDER_QSHADERIMAGE_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <Qt3DCore/private/qnode_p.h> #include <Qt3DRender/qshaderimage.h> diff --git a/src/render/materialsystem/shaderdata.cpp b/src/render/materialsystem/shaderdata.cpp index de423c3c2..130333898 100644 --- a/src/render/materialsystem/shaderdata.cpp +++ b/src/render/materialsystem/shaderdata.cpp @@ -245,7 +245,7 @@ void ShaderData::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) // Note we aren't notified about nested QShaderData in this call // only scalar / vec properties m_originalProperties.insert(propertyName, propertyValue); - BackendNode::markDirty(AbstractRenderer::AllDirty); + BackendNode::markDirty(AbstractRenderer::ParameterDirty); } BackendNode::sceneChangeEvent(e); diff --git a/src/render/raycasting/qray3d.cpp b/src/render/raycasting/qray3d.cpp index d8ad25b50..18dd9a40a 100644 --- a/src/render/raycasting/qray3d.cpp +++ b/src/render/raycasting/qray3d.cpp @@ -101,7 +101,7 @@ QRay3D::QRay3D() */ QRay3D::QRay3D(const Vector3D &origin, const Vector3D &direction, float distance) : m_origin(origin) - , m_direction(direction) + , m_direction(direction.normalized()) , m_distance(distance) {} @@ -157,7 +157,7 @@ void QRay3D::setDirection(const Vector3D &value) if (value.isNull()) return; - m_direction = value; + m_direction = value.normalized(); } float QRay3D::distance() const @@ -178,14 +178,14 @@ Vector3D QRay3D::point(float t) const QRay3D &QRay3D::transform(const Matrix4x4 &matrix) { m_origin = matrix * m_origin; - m_direction = matrix.mapVector(m_direction); + m_direction = matrix.mapVector(m_direction).normalized(); return *this; } QRay3D QRay3D::transformed(const Matrix4x4 &matrix) const { - return QRay3D(matrix * m_origin, matrix.mapVector(m_direction)); + return QRay3D(matrix * m_origin, matrix.mapVector(m_direction).normalized()); } bool QRay3D::operator==(const QRay3D &other) const diff --git a/src/render/raycasting/qraycastingservice.cpp b/src/render/raycasting/qraycastingservice.cpp index a0f21aa41..bdb1557f7 100644 --- a/src/render/raycasting/qraycastingservice.cpp +++ b/src/render/raycasting/qraycastingservice.cpp @@ -43,7 +43,6 @@ #include <Qt3DRender/private/sphere_p.h> #include <Qt3DRender/private/qboundingvolumeprovider_p.h> -#include <QMap> #include <QtConcurrent> #include "math.h" diff --git a/src/render/renderers/opengl/jobs/renderviewjobutils.cpp b/src/render/renderers/opengl/jobs/renderviewjobutils.cpp index e55497d06..d2babe58a 100644 --- a/src/render/renderers/opengl/jobs/renderviewjobutils.cpp +++ b/src/render/renderers/opengl/jobs/renderviewjobutils.cpp @@ -194,8 +194,10 @@ void setRenderViewConfigFromFrameGraphLeafNode(RenderView *rv, const FrameGraphN rv->setStateSet(stateSet); } + // Add states from new stateSet we might be missing + // but don' t override existing states (lower StateSetNode always has priority) if (rStateSet->hasRenderStates()) - addToRenderStateSet(stateSet, rStateSet->renderStates(), manager->renderStateManager()); + addUniqueStatesToRenderStateSet(stateSet, rStateSet->renderStates(), manager->renderStateManager()); break; } @@ -433,14 +435,16 @@ void parametersFromMaterialEffectTechnique(ParameterInfoList *infoList, parametersFromParametersProvider(infoList, manager, technique); } -void addToRenderStateSet(RenderStateSet *stateSet, - const QVector<Qt3DCore::QNodeId> stateIds, - RenderStateManager *manager) +// Only add states with types we don't already have +void addUniqueStatesToRenderStateSet(RenderStateSet *stateSet, + const QVector<Qt3DCore::QNodeId> stateIds, + RenderStateManager *manager) { for (const Qt3DCore::QNodeId &stateId : stateIds) { RenderStateNode *node = manager->lookupResource(stateId); - if (node->isEnabled()) + if (node->isEnabled() && !stateSet->hasStateOfType(node->type())) { stateSet->addState(node->impl()); + } } } diff --git a/src/render/renderers/opengl/jobs/renderviewjobutils_p.h b/src/render/renderers/opengl/jobs/renderviewjobutils_p.h index 90c4a53cc..bd2e12534 100644 --- a/src/render/renderers/opengl/jobs/renderviewjobutils_p.h +++ b/src/render/renderers/opengl/jobs/renderviewjobutils_p.h @@ -150,9 +150,9 @@ void parametersFromParametersProvider(ParameterInfoList *infoList, Q_AUTOTEST_EXPORT ParameterInfoList::const_iterator findParamInfo(ParameterInfoList *infoList, const int nameId); -Q_AUTOTEST_EXPORT void addToRenderStateSet(RenderStateSet *stateSet, - const QVector<Qt3DCore::QNodeId> stateIds, - RenderStateManager *manager); +Q_AUTOTEST_EXPORT void addUniqueStatesToRenderStateSet(RenderStateSet *stateSet, + const QVector<Qt3DCore::QNodeId> stateIds, + RenderStateManager *manager); typedef QHash<int, QVariant> UniformBlockValueBuilderHash; diff --git a/src/render/renderers/opengl/renderer/renderer.cpp b/src/render/renderers/opengl/renderer/renderer.cpp index 68d31be71..b60eea33d 100644 --- a/src/render/renderers/opengl/renderer/renderer.cpp +++ b/src/render/renderers/opengl/renderer/renderer.cpp @@ -1648,7 +1648,7 @@ Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Ren // Reset state and call doneCurrent if the surface // is valid and was actually activated - if (surface && m_submissionContext->hasValidGLHelper()) { + if (lastUsedSurface && m_submissionContext->hasValidGLHelper()) { // Reset state to the default state if the last stateset is not the // defaultRenderStateSet if (m_submissionContext->currentStateSet() != m_defaultRenderStateSet) diff --git a/src/render/renderers/opengl/renderer/renderview.cpp b/src/render/renderers/opengl/renderer/renderview.cpp index ebb1ee7ab..5845fe147 100644 --- a/src/render/renderers/opengl/renderer/renderview.cpp +++ b/src/render/renderers/opengl/renderer/renderview.cpp @@ -656,10 +656,7 @@ QVector<RenderCommand *> RenderView::buildDrawRenderCommands(const QVector<Entit RenderPass *pass = passData.pass; if (pass->hasRenderStates()) { command->m_stateSet = new RenderStateSet(); - addToRenderStateSet(command->m_stateSet, pass->renderStates(), m_manager->renderStateManager()); - - // Merge per pass stateset with global stateset - // so that the local stateset only overrides + addUniqueStatesToRenderStateSet(command->m_stateSet, pass->renderStates(), m_manager->renderStateManager()); if (m_stateSet != nullptr) command->m_stateSet->merge(m_stateSet); command->m_changeCost = m_renderer->defaultRenderState()->changeCost(command->m_stateSet); @@ -779,15 +776,26 @@ QVector<RenderCommand *> RenderView::buildComputeRenderCommands(const QVector<En // 1 RenderCommand per RenderPass pass on an Entity with a Mesh for (const RenderPassParameterData &passData : renderPassData) { // Add the RenderPass Parameters - ParameterInfoList globalParameters = passData.parameterInfo; + RenderCommand *command = new RenderCommand(); RenderPass *pass = passData.pass; - parametersFromParametersProvider(&globalParameters, m_manager->parameterManager(), pass); - RenderCommand *command = new RenderCommand(); + if (pass->hasRenderStates()) { + command->m_stateSet = new RenderStateSet(); + addUniqueStatesToRenderStateSet(command->m_stateSet, pass->renderStates(), m_manager->renderStateManager()); + + // Merge per pass stateset with global stateset + // so that the local stateset only overrides + if (m_stateSet != nullptr) + command->m_stateSet->merge(m_stateSet); + command->m_changeCost = m_renderer->defaultRenderState()->changeCost(command->m_stateSet); + } + command->m_type = RenderCommand::Compute; command->m_workGroups[0] = std::max(m_workGroups[0], computeJob->x()); command->m_workGroups[1] = std::max(m_workGroups[1], computeJob->y()); command->m_workGroups[2] = std::max(m_workGroups[2], computeJob->z()); + + ParameterInfoList globalParameters = passData.parameterInfo; setShaderAndUniforms(command, pass, globalParameters, diff --git a/src/render/renderers/opengl/renderstates/renderstateset.cpp b/src/render/renderers/opengl/renderstates/renderstateset.cpp index f7fc279a1..b14695c77 100644 --- a/src/render/renderers/opengl/renderstates/renderstateset.cpp +++ b/src/render/renderers/opengl/renderstates/renderstateset.cpp @@ -103,9 +103,24 @@ StateMaskSet RenderStateSet::stateMask() const return m_stateMask; } +// This modifies our state to add states from others +// if we don't already contain a state with that type set void RenderStateSet::merge(RenderStateSet *other) { m_stateMask |= other->stateMask(); + const QVector<StateVariant> otherStates = other->states(); + + // We only add states which are new (different type) + for (const StateVariant &otherState : otherStates) { + const bool hasFoundStateOfSameType = hasStateOfType(otherState.type); + if (!hasFoundStateOfSameType) + m_states.push_back(otherState); + } +} + +bool RenderStateSet::hasStateOfType(StateMask type) const +{ + return (type & stateMask()); } bool RenderStateSet::contains(const StateVariant &ds) const diff --git a/src/render/renderers/opengl/renderstates/renderstateset_p.h b/src/render/renderers/opengl/renderstates/renderstateset_p.h index 09b58b859..29be4d2f1 100644 --- a/src/render/renderers/opengl/renderstates/renderstateset_p.h +++ b/src/render/renderers/opengl/renderstates/renderstateset_p.h @@ -93,6 +93,9 @@ public: QVector<StateVariant> states() const { return m_states; } + bool hasStateOfType(StateMask type) const; + + /** * @brief contains - check if this set contains a matching piece of state * @param ds diff --git a/src/render/renderstates/genericstate_p.h b/src/render/renderstates/genericstate_p.h index 69c3dee15..b07487d65 100644 --- a/src/render/renderstates/genericstate_p.h +++ b/src/render/renderstates/genericstate_p.h @@ -96,7 +96,7 @@ public: bool equalTo(const RenderStateImpl &renderState) const override { const GenericState *other = static_cast<const GenericState*>(&renderState); - return (other != NULL && other->m_values == m_values); + return (other != nullptr && other->m_values == m_values); } StateMask mask() const override diff --git a/src/render/renderstates/renderstatenode_p.h b/src/render/renderstates/renderstatenode_p.h index 886bb0c95..277b8a7c8 100644 --- a/src/render/renderstates/renderstatenode_p.h +++ b/src/render/renderstates/renderstatenode_p.h @@ -65,7 +65,7 @@ public: void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override; - StateMaskSet mask() const { return m_impl.type; } + StateMask type() const { return m_impl.type; } StateVariant impl() const { return m_impl; } protected: diff --git a/src/render/texture/qtextureimage.cpp b/src/render/texture/qtextureimage.cpp index 6bcdaba7d..b4e9ed46f 100644 --- a/src/render/texture/qtextureimage.cpp +++ b/src/render/texture/qtextureimage.cpp @@ -289,10 +289,12 @@ QImageTextureDataFunctor::QImageTextureDataFunctor(const QUrl &url, bool mirrore QTextureImageDataPtr QImageTextureDataFunctor::operator ()() { + if (!m_url.isValid()) + return QTextureImageDataPtr(); + // We assume that a texture image is going to contain a single image data // For compressed dds or ktx textures a warning should be issued if // there are layers or 3D textures - if (!Qt3DCore::QDownloadHelperService::isLocal(m_url)) qWarning() << "QTextureImage only supports local url"; diff --git a/tests/auto/render/gltexture/tst_gltexture.cpp b/tests/auto/render/gltexture/tst_gltexture.cpp index 8a8701f8e..e971078d0 100644 --- a/tests/auto/render/gltexture/tst_gltexture.cpp +++ b/tests/auto/render/gltexture/tst_gltexture.cpp @@ -864,6 +864,44 @@ private Q_SLOTS: // Cleanup texture.destroy(); } + + void checkPropertiesAfterLoadTextureDataFromImages() + { + // GIVEN + GLTexture texture; + TextureProperties props; + props.target = QAbstractTexture::TargetCubeMap; + props.format = QAbstractTexture::Automatic; + props.width = 1; + props.height = 1; + texture.setProperties(props); + QVector<GLTexture::Image> images; + // test a image texture data generator whose url is invalid + QImageTextureDataFunctorPtr gen = QImageTextureDataFunctorPtr::create(QUrl(), true); + images.push_back({gen, 0, 0, QAbstractTexture::CubeMapPositiveX}); + texture.setImages(images); + + // WHEN + texture.createOrUpdateGLTexture(); + + // THEN + QCOMPARE(texture.properties().format, QAbstractTexture::Automatic); + + // WHEN + // test a image texture data generator whose url is valid + gen = QImageTextureDataFunctorPtr::create(QUrl("qrc:/image.jpg"), true); + images.clear(); + images.push_back({gen, 0, 0, QAbstractTexture::CubeMapPositiveX}); + texture.setImages(images); + texture.createOrUpdateGLTexture(); + + // THEN + QVERIFY(texture.properties().format != QAbstractTexture::Automatic); + QVERIFY(texture.properties().format != QAbstractTexture::NoFormat); + + // Cleanup + texture.destroy(); + } }; QTEST_MAIN(tst_GLTexture); diff --git a/tests/auto/render/qray3d/tst_qray3d.cpp b/tests/auto/render/qray3d/tst_qray3d.cpp index dfc2a7396..ef0702a0a 100644 --- a/tests/auto/render/qray3d/tst_qray3d.cpp +++ b/tests/auto/render/qray3d/tst_qray3d.cpp @@ -108,23 +108,23 @@ void tst_QRay3D::create_data() // non-normalized direction vectors QTest::newRow("line on x-axis from origin - B") << Vector3D() - << Vector3D(2.0f, 0.0f, 0.0f); + << Vector3D(2.0f, 0.0f, 0.0f).normalized(); QTest::newRow("line parallel -z-axis from 3,3,3 - B") << Vector3D(3.0f, 3.0f, 3.0f) - << Vector3D(0.0f, 0.0f, -0.7f); + << Vector3D(0.0f, 0.0f, -0.7f).normalized(); QTest::newRow("vertical line (parallel to y-axis) - B") << Vector3D(0.5f, 0.0f, 0.5f) - << Vector3D(0.0f, 5.3f, 0.0f); + << Vector3D(0.0f, 5.3f, 0.0f).normalized(); QTest::newRow("equidistant from all 3 axes - B") << Vector3D(0.5f, 0.0f, 0.5f) - << Vector3D(1.0f, 1.0f, 1.0f); + << Vector3D(1.0f, 1.0f, 1.0f).normalized(); QTest::newRow("negative direction") << Vector3D(-3.0f, -3.0f, -3.0f) - << Vector3D(-1.2f, -1.8f, -2.4f); + << Vector3D(-1.2f, -1.8f, -2.4f).normalized(); } void tst_QRay3D::create() @@ -203,32 +203,32 @@ void tst_QRay3D::point_data() QTest::newRow("line on x-axis from origin") << Vector3D() << Vector3D(2.0f, 0.0f, 0.0f) - << Vector3D(1.2f, 0.0f, 0.0f) - << Vector3D(-14.4f, 0.0f, 0.0f); + << Vector3D(0.6f, 0.0f, 0.0f) + << Vector3D(-7.2f, 0.0f, 0.0f); QTest::newRow("line parallel -z-axis from 3,3,3") << Vector3D(3.0f, 3.0f, 3.0f) << Vector3D(0.0f, 0.0f, -0.7f) - << Vector3D(3.0f, 3.0f, 2.58f) - << Vector3D(3.0f, 3.0f, 8.04f); + << Vector3D(3.0f, 3.0f, 2.4f) + << Vector3D(3.0f, 3.0f, 10.2f); QTest::newRow("vertical line (parallel to y-axis)") << Vector3D(0.5f, 0.0f, 0.5f) << Vector3D(0.0f, 5.3f, 0.0f) - << Vector3D(0.5f, 3.18f, 0.5f) - << Vector3D(0.5f, -38.16f, 0.5f); + << Vector3D(0.5f, 0.6f, 0.5f) + << Vector3D(0.5f, -7.2f, 0.5f); QTest::newRow("equidistant from all 3 axes") << Vector3D(0.5f, 0.0f, 0.5f) << Vector3D(1.0f, 1.0f, 1.0f) - << Vector3D(1.1f, 0.6f, 1.1f) - << Vector3D(-6.7f, -7.2f, -6.7f); + << Vector3D(0.84641f, 0.34641f, 0.84641f) + << Vector3D(-3.65692f, -4.15692f, -3.65692f); QTest::newRow("negative direction") << Vector3D(-3.0f, -3.0f, -3.0f) << Vector3D(-1.2f, -1.8f, -2.4f) - << Vector3D(-3.72f, -4.08f, -4.44f) - << Vector3D(5.64f, 9.96f, 14.28f); + << Vector3D(-3.22283f, -3.33425f, -3.44567f) + << Vector3D(-0.325987f, 1.01102f, 2.34803f); } void tst_QRay3D::point() @@ -475,7 +475,7 @@ void tst_QRay3D::transform() QVERIFY(fuzzyCompare(ray1.direction(), ray3.direction())); QVERIFY(fuzzyCompare(ray1.origin(), m * point)); - QVERIFY(fuzzyCompare(ray1.direction(), m.mapVector(direction))); + QVERIFY(fuzzyCompare(ray1.direction(), m.mapVector(direction).normalized())); } class tst_QRay3DProperties : public QObject @@ -503,7 +503,7 @@ void tst_QRay3D::properties() Qt3DRender::RayCasting::QRay3D r = qvariant_cast<Qt3DRender::RayCasting::QRay3D>(obj.property("ray")); QCOMPARE(r.origin(), Vector3D(1, 2, 3)); - QCOMPARE(r.direction(), Vector3D(4, 5, 6)); + QCOMPARE(r.direction(), Vector3D(4, 5, 6).normalized()); obj.setProperty("ray", QVariant::fromValue @@ -511,7 +511,7 @@ void tst_QRay3D::properties() r = qvariant_cast<Qt3DRender::RayCasting::QRay3D>(obj.property("ray")); QCOMPARE(r.origin(), Vector3D(-1, -2, -3)); - QCOMPARE(r.direction(), Vector3D(-4, -5, -6)); + QCOMPARE(r.direction(), Vector3D(-4, -5, -6).normalized()); } void tst_QRay3D::metaTypes() diff --git a/tests/auto/render/qrenderstate/tst_qrenderstate.cpp b/tests/auto/render/qrenderstate/tst_qrenderstate.cpp index 4dc850b25..596aa9553 100644 --- a/tests/auto/render/qrenderstate/tst_qrenderstate.cpp +++ b/tests/auto/render/qrenderstate/tst_qrenderstate.cpp @@ -187,8 +187,8 @@ private Q_SLOTS: // THEN RenderStateNode *backend1 = createBackendNode(frontend1); RenderStateNode *backend2 = createBackendNode(frontend2); - QVERIFY(backend1->mask() == mask); - QVERIFY(backend2->mask() == mask); + QVERIFY(backend1->type() == mask); + QVERIFY(backend2->type() == mask); QVERIFY(backend1->impl() != backend2->impl()); // WHEN @@ -272,8 +272,8 @@ private Q_SLOTS: // THEN RenderStateNode *backend1 = createBackendNode(frontend1); RenderStateNode *backend2 = createBackendNode(frontend2); - QVERIFY(backend1->mask() == mask); - QVERIFY(backend2->mask() == mask); + QVERIFY(backend1->type() == mask); + QVERIFY(backend2->type() == mask); QVERIFY(backend1->impl() != backend2->impl()); // WHEN diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro index 88e339561..07f7f9132 100644 --- a/tests/manual/manual.pro +++ b/tests/manual/manual.pro @@ -64,6 +64,7 @@ SUBDIRS += \ raster-cpp \ raster-qml \ qtbug-72236 \ + qtbug-76766 \ shader-image-qml qtHaveModule(multimedia): { diff --git a/tests/manual/qtbug-76766/FrameGraph.qml b/tests/manual/qtbug-76766/FrameGraph.qml new file mode 100644 index 000000000..0b096bc19 --- /dev/null +++ b/tests/manual/qtbug-76766/FrameGraph.qml @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or 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.GPL2 and 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D.Core 2.9 +import Qt3D.Render 2.9 + +RenderSurfaceSelector { + id: surfaceSelector + + readonly property Layer layer: Layer { + recursive: true + } + + property alias camera: cameraSelector.camera + property alias clearColor: clearBuffers.clearColor + property alias fbo : renderToFboSelector.target + + Viewport { + normalizedRect: Qt.rect(0.0, 0.0, 1.0, 1.0) + + // 1st: render scene to texture + RenderTargetSelector { + id : renderToFboSelector + + RenderStateSet { + renderStates: [ + MultiSampleAntiAliasing {}, + DepthTest { + depthFunction: DepthTest.Less + }, + CullFace{ + mode: CullFace.Back + } + ] + + ClearBuffers { + id: clearBuffers + buffers: ClearBuffers.ColorDepthBuffer + NoDraw {} + } + + CameraSelector { + id: cameraSelector + + LayerFilter { + layers: [layer] + filterMode: LayerFilter.DiscardAllMatchingLayers + TechniqueFilter { + RenderPassFilter { + matchAny: FilterKey { name: "pass"; value: 0 } + } + SortPolicy { + sortTypes: [SortPolicy.BackToFront] + RenderPassFilter { + matchAny: FilterKey { name: "pass"; value: 1 } + } + } + } + } + + RenderStateSet { + renderStates: [ + DepthTest { + depthFunction: DepthTest.Always + } + ] + LayerFilter { + layers: [layer] + filterMode: LayerFilter.AcceptAnyMatchingLayers + TechniqueFilter { + RenderPassFilter { + matchAny: FilterKey { name: "pass"; value: 0 } + } + SortPolicy { + sortTypes: [SortPolicy.BackToFront] + RenderPassFilter { + matchAny: FilterKey { name: "pass"; value: 1 } + } + } + } + } + } + } + } + } + + RenderStateSet { + renderStates: [ + DepthTest {depthFunction: DepthTest.Always}, + BlendEquation {}, + BlendEquationArguments { + sourceRgb: BlendEquationArguments.One + sourceAlpha: BlendEquationArguments.One + destinationRgb: BlendEquationArguments.Zero + destinationAlpha: BlendEquationArguments.Zero + } + ] + + RenderPassFilter { + matchAny : FilterKey { name : "pass"; value : "final" } + } + } + } +} diff --git a/tests/manual/qtbug-76766/Material1.qml b/tests/manual/qtbug-76766/Material1.qml new file mode 100644 index 000000000..069d99c74 --- /dev/null +++ b/tests/manual/qtbug-76766/Material1.qml @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or 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.GPL2 and 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 + +Material { + id: root + + property color color: Qt.rgba(0.15, 0.35, 0.50, 1.0) + + parameters: [ + Parameter { name: "color"; value: Qt.vector3d(root.color.r, root.color.g, root.color.b) } + ] + + + effect: Effect { + property string vertex: "qrc:/shaders/shader.vert" + property string fragment: "qrc:/shaders/shader.frag" + + FilterKey { + id: forward + name: "renderingStyle" + value: "forward" + } + + ShaderProgram { + id: gl3Shader + vertexShaderCode: loadSource(parent.vertex) + fragmentShaderCode: loadSource(parent.fragment) + } + + techniques: [ + // OpenGL 3.1 + Technique { + filterKeys: [ forward ] + graphicsApiFilter { + api: GraphicsApiFilter.OpenGL + profile: GraphicsApiFilter.CoreProfile + majorVersion: 3 + minorVersion: 3 + } + renderPasses: RenderPass { + filterKeys: [ + FilterKey { + name: "pass" + value: 0 + } + ] + shaderProgram: gl3Shader + } + } + ] + } +} + + diff --git a/tests/manual/qtbug-76766/Material2.qml b/tests/manual/qtbug-76766/Material2.qml new file mode 100644 index 000000000..0af0ecb6c --- /dev/null +++ b/tests/manual/qtbug-76766/Material2.qml @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or 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.GPL2 and 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 + +Material { + id: root + + property color color: Qt.rgba(0.15, 0.35, 0.50, 1.0) + + parameters: [ + Parameter { name: "color"; value: Qt.vector3d(root.color.r, root.color.g, root.color.b) } + ] + + + effect: Effect { + property string vertex: "qrc:/shaders/shader.vert" + property string fragment: "qrc:/shaders/shader.frag" + + FilterKey { + id: forward + name: "renderingStyle" + value: "forward" + } + + ShaderProgram { + id: gl3Shader + vertexShaderCode: loadSource(parent.vertex) + fragmentShaderCode: loadSource(parent.fragment) + } + + techniques: [ + // OpenGL 3.1 + Technique { + filterKeys: [ forward ] + graphicsApiFilter { + api: GraphicsApiFilter.OpenGL + profile: GraphicsApiFilter.CoreProfile + majorVersion: 3 + minorVersion: 3 + } + renderPasses: [ + RenderPass { + filterKeys: [ + FilterKey { + name: "pass" + value: 1 + } + ] + shaderProgram: gl3Shader + renderStates: [ + NoDepthMask {}, + BlendEquation {}, + BlendEquationArguments { + sourceRgb: BlendEquationArguments.One + destinationRgb: BlendEquationArguments.One + sourceAlpha: BlendEquationArguments.Zero + destinationAlpha: BlendEquationArguments.One + } + ] + } + ] + } + ] + } +} + + diff --git a/tests/manual/qtbug-76766/PostProcess.qml b/tests/manual/qtbug-76766/PostProcess.qml new file mode 100644 index 000000000..cd4c9c0c6 --- /dev/null +++ b/tests/manual/qtbug-76766/PostProcess.qml @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or 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.GPL2 and 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D.Core 2.9 +import Qt3D.Render 2.9 +import Qt3D.Extras 2.0 + +Entity { + id: root + + property Texture colorTexture + readonly property int samples : colorTexture ? colorTexture.samples : 1 + + Effect { + id: materialEffect + techniques : [ + // OpenGL 3.2 + Technique { + graphicsApiFilter { + api : GraphicsApiFilter.OpenGL + profile : GraphicsApiFilter.CoreProfile + minorVersion : 3 + majorVersion : 2 + } + + renderPasses : RenderPass { + filterKeys : FilterKey { name : "pass"; value : "final" } + + shaderProgram : ShaderProgram { + vertexShaderCode: + "#version 150 core + + in vec3 vertexPosition; + out vec2 texCoords; + + void main() { + texCoords = vec2(0.5) + vec2(0.5) * vertexPosition.xz; + gl_Position = vec4(vertexPosition.x, vertexPosition.z, 0.0, 1.0); + }" + fragmentShaderCode: + "#version 150 core + + uniform sampler2DMS source; + + in vec2 texCoords; + out vec4 fragColor; + + void main() { + vec4 c = vec4(0.0); + c += texelFetch(source, ivec2(gl_FragCoord), 0); + fragColor = vec4(c.rgb / max(c.a, 0.01), c.a); + }" + } + } + } + ] + } + + Material { + id: materialWithoutTexture + + parameters: [ + Parameter { name: "source"; value: colorTexture }, + Parameter { name: "samples"; value: root.samples } + ] + + effect: materialEffect + } + + PlaneMesh { + id: planeMesh + width: 2.0 + height: 2.0 + meshResolution: Qt.size(2, 2) + } + + components : [ + planeMesh, + materialWithoutTexture + ] +} diff --git a/tests/manual/qtbug-76766/SceneRoot.qml b/tests/manual/qtbug-76766/SceneRoot.qml new file mode 100644 index 000000000..6e34633b1 --- /dev/null +++ b/tests/manual/qtbug-76766/SceneRoot.qml @@ -0,0 +1,176 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or 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.GPL2 and 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 +import Qt3D.Extras 2.0 +import Qt3D.Input 2.0 +import QtQuick 2.0 as QQ2 +import QtQuick 2.12 + + +Entity { + id: sceneRoot + + Camera { + id: camera + projectionType: CameraLens.OrthographicProjection + left: -2 + right: 2 + top: 2 + bottom: -2 + nearPlane: 0.1 + farPlane: 1000.0 + position: Qt.vector3d(0.0, 0.0, 1.0) + upVector: Qt.vector3d(0.0, 1.0, 0.0) + viewCenter: Qt.vector3d(0.0, 0.0, 0.0) + } + + RenderTarget { + id: renderTargetFBO + attachments : [ + RenderTargetOutput { + attachmentPoint : RenderTargetOutput.Color0 + texture : Texture2DMultisample { + id : colorAttachment + width : scene3d.width + height : scene3d.height + format : Texture.RGBA8_UNorm + generateMipMaps : false + samples: 1 + } + }, + RenderTargetOutput { + attachmentPoint : RenderTargetOutput.Depth + texture : Texture2DMultisample { + width : scene3d.width + height : scene3d.height + format : Texture.D32F + generateMipMaps : false + samples: 1 + } + } + ] + } + + components: [ + RenderSettings { + activeFrameGraph: FrameGraph { + id: framegraph + camera: camera + fbo: renderTargetFBO + } + renderPolicy: RenderSettings.Always + } + ] + + Entity { + id: firstPassEntities + + Entity { + components: [ + Transform { + translation: Qt.vector3d(0,0,-2) + }, + Material1 { + color: "red" + }, + SphereMesh { + } + ] + } + + + Entity { + components: [ + Transform { + translation: Qt.vector3d(1,0,-1) + }, + Material2 { + color: "green" + }, + SphereMesh { + } + ] + } + } + + Entity { + id: secondPassEntities + components: [framegraph.layer] + + Entity { + components: [ + Transform { + translation: Qt.vector3d(0,0,-4) + scale: 0.5 + }, + Material1 { + ColorAnimation on color { + from: "black" + to: "purple" + duration: 2000 + loops: Animation.Infinite + } + }, + SphereMesh { + } + ] + } + + + Entity { + components: [ + Transform { + translation: Qt.vector3d(1,0,-3) + scale: 0.5 + }, + Material2 { + color: "orange" + }, + SphereMesh { + } + ] + } + } + + PostProcess { + colorTexture: colorAttachment + } +} diff --git a/tests/manual/qtbug-76766/expected_output.png b/tests/manual/qtbug-76766/expected_output.png Binary files differnew file mode 100644 index 000000000..8f642e843 --- /dev/null +++ b/tests/manual/qtbug-76766/expected_output.png diff --git a/tests/manual/qtbug-76766/main.cpp b/tests/manual/qtbug-76766/main.cpp new file mode 100644 index 000000000..f9d49846a --- /dev/null +++ b/tests/manual/qtbug-76766/main.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or 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.GPL2 and 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QGuiApplication> +#include <QQuickView> +#include <QOpenGLContext> + +void setSurfaceFormat() +{ + QSurfaceFormat format; +#ifdef QT_OPENGL_ES_2 + format.setRenderableType(QSurfaceFormat::OpenGLES); +#else + if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) { + format.setVersion(4, 3); + format.setProfile(QSurfaceFormat::CoreProfile); + } +#endif + format.setDepthBufferSize(24); + format.setSamples(4); + format.setStencilBufferSize(8); + QSurfaceFormat::setDefaultFormat(format); +} + +int main(int argc, char **argv) +{ + QGuiApplication app(argc, argv); + setSurfaceFormat(); + + QQuickView view; + + view.resize(1920, 1080); + view.setResizeMode(QQuickView::SizeRootObjectToView); + view.setSource(QUrl("qrc:/main.qml")); + view.show(); + + return app.exec(); +} diff --git a/tests/manual/qtbug-76766/main.qml b/tests/manual/qtbug-76766/main.qml new file mode 100644 index 000000000..9b8f4b691 --- /dev/null +++ b/tests/manual/qtbug-76766/main.qml @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or 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.GPL2 and 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.12 +import QtQuick.Scene3D 2.12 +import Qt3D.Render 2.12 + +Item { + anchors.fill: parent + + Scene3D { + id: scene3d + anchors.fill: parent + focus: true + cameraAspectRatioMode: Scene3D.AutomaticAspectRatio + + SceneRoot { + id: root + } + } + + Image { + width: 400 + fillMode: Image.PreserveAspectFit + source: "qrc:/expected_output.png" + Text { + anchors.centerIn: parent + color: "white" + text: "This is the expected output" + } + Rectangle { + anchors.fill: parent + color: "transparent" + border { + color: "white" + width: 2 + } + } + } +} diff --git a/tests/manual/qtbug-76766/qml.qrc b/tests/manual/qtbug-76766/qml.qrc new file mode 100644 index 000000000..b1f8c2c21 --- /dev/null +++ b/tests/manual/qtbug-76766/qml.qrc @@ -0,0 +1,11 @@ +<RCC> + <qresource prefix="/"> + <file>main.qml</file> + <file>SceneRoot.qml</file> + <file>FrameGraph.qml</file> + <file>PostProcess.qml</file> + <file>Material1.qml</file> + <file>Material2.qml</file> + <file>expected_output.png</file> + </qresource> +</RCC> diff --git a/tests/manual/qtbug-76766/qtbug-76766.pro b/tests/manual/qtbug-76766/qtbug-76766.pro new file mode 100644 index 000000000..f332d7d57 --- /dev/null +++ b/tests/manual/qtbug-76766/qtbug-76766.pro @@ -0,0 +1,10 @@ +TEMPLATE = app + +QT += qml quick +CONFIG += c++11 + +SOURCES += main.cpp + +RESOURCES += qml.qrc \ + shaders.qrc + diff --git a/tests/manual/qtbug-76766/shaders.qrc b/tests/manual/qtbug-76766/shaders.qrc new file mode 100644 index 000000000..665814e55 --- /dev/null +++ b/tests/manual/qtbug-76766/shaders.qrc @@ -0,0 +1,6 @@ +<RCC> + <qresource prefix="/"> + <file>shaders/shader.frag</file> + <file>shaders/shader.vert</file> + </qresource> +</RCC> diff --git a/tests/manual/qtbug-76766/shaders/shader.frag b/tests/manual/qtbug-76766/shaders/shader.frag new file mode 100644 index 000000000..92d304640 --- /dev/null +++ b/tests/manual/qtbug-76766/shaders/shader.frag @@ -0,0 +1,11 @@ +#version 150 core + +uniform vec3 color; + +out vec4 fragColor; + +void main() +{ + fragColor = vec4(color,1.0); +} + diff --git a/tests/manual/qtbug-76766/shaders/shader.vert b/tests/manual/qtbug-76766/shaders/shader.vert new file mode 100644 index 000000000..fa836855d --- /dev/null +++ b/tests/manual/qtbug-76766/shaders/shader.vert @@ -0,0 +1,36 @@ +#version 150 core + +in vec3 vertexPosition; +in vec3 vertexNormal; +in vec2 vertexTexCoord; +in vec4 vertexTangent; + +out vec3 worldPosition; +out vec3 worldNormal; +out vec4 worldTangent; +out vec2 texCoord; + +uniform mat4 modelMatrix; +uniform mat3 modelNormalMatrix; +uniform mat4 mvp; + +void main() +{ + // Scale texture coordinates for for fragment shader + texCoord = vertexTexCoord; + + // Transform position, normal, and tangent to world coords + worldPosition = vec3(modelMatrix * vec4(vertexPosition, 1.0)); + worldNormal = normalize(modelNormalMatrix * vertexNormal); + worldTangent.xyz = normalize(vec3(modelMatrix * vec4(vertexTangent.xyz, 0.0))); + worldTangent.w = vertexTangent.w; + + // Calculate animated vertex positions + + float sinPos = (vertexPosition.z)+(vertexPosition.x); + float sinPos2 = (vertexPosition.y/2)+(vertexPosition.z); + vec3 vertMod = vec3(vertexPosition.x,vertexPosition.y,vertexPosition.z); + + // Calculate vertex position in clip coordinates + gl_Position = mvp * vec4(vertexPosition, 1.0); +} |