From b9930c53b256623fe8fa290f91138ac9b3c8b7c2 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Mon, 1 Jul 2019 16:02:11 +0200 Subject: Bump version Change-Id: I9e9da54e565ad7818e6ea8196a062af8b4931783 --- .qmake.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.qmake.conf b/.qmake.conf index 2064bc2d3..dbe097680 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -3,4 +3,4 @@ QT3D_BUILD_ROOT = $$shadowed($$PWD) load(qt_build_config) -MODULE_VERSION = 5.12.4 +MODULE_VERSION = 5.12.5 -- cgit v1.2.3 From e8809595df21ec6c6631f2148e15605c004e1ca7 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Mon, 24 Jun 2019 10:42:13 -0500 Subject: Document unit for FrameAction::triggered Task-number: QTBUG-74165 Change-Id: I4d3de42cddd8f6e1e6729cc16a52e135ab7fa3b1 Reviewed-by: Paul Lemire --- src/logic/qframeaction.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 -- cgit v1.2.3 From e919516c304f4d98fdc5311f4889c92852c718a3 Mon Sep 17 00:00:00 2001 From: Topi Reinio Date: Wed, 3 Jul 2019 11:29:53 +0200 Subject: Doc: Replace example file lists with links to code.qt.io Task-number: QTBUG-74391 Change-Id: Iec111e88d38fb9a143a60a647251601f331fc41e Reviewed-by: Paul Wicking --- src/doc/qt3d.qdocconf | 1 + 1 file changed, 1 insertion(+) 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 -- cgit v1.2.3 From 310d4e6d0baaa989c736220f837629e19ab14e05 Mon Sep 17 00:00:00 2001 From: Paul Wicking Date: Tue, 9 Jul 2019 13:58:15 +0200 Subject: Doc: Fix typo in property name colorbuffer -> colorBuffer Fixes: QTBUG-76342 Change-Id: Ic63ac9b333710ebab17aa7c4ccd9e864f10e6fcf Reviewed-by: Martin Smith Reviewed-by: Paul Lemire --- src/render/framegraph/qclearbuffers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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. */ -- cgit v1.2.3 From 650a169aa618dad762957337ba16f7fba22e5d05 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Wed, 10 Jul 2019 10:20:43 -0500 Subject: Expand documentation for Camera Change-Id: Id886decd4f2bd83a2319b4ad792a15b7280cb448 Reviewed-by: Paul Lemire --- src/render/frontend/qcamera.cpp | 103 ++++++++++++++++++++++++++++++++++------ 1 file changed, 88 insertions(+), 15 deletions(-) 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). */ /*! -- cgit v1.2.3 From c732dd6f6bb4d121a16f6ab53bbb571e9f7f5965 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Wed, 12 Jun 2019 14:37:19 +0200 Subject: Joints: remove removed joints from dirty list In case a joint is added and destroyed within the same loop of the event loop, we need to remove it from the list of dirty joints to process as this otherwise results in an assert. Change-Id: If2f4ece6e2d69a7801ce9c4ec2cb732f48895ad1 Reviewed-by: Sean Harmer --- src/render/backend/managers.cpp | 6 ++++++ src/render/backend/managers_p.h | 1 + src/render/geometry/joint.cpp | 1 + 3 files changed, 8 insertions(+) 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 JointManager::dirtyJoints() { return std::move(m_dirtyJoints); diff --git a/src/render/backend/managers_p.h b/src/render/backend/managers_p.h index b62e2f3e0..fc2a0b479 100644 --- a/src/render/backend/managers_p.h +++ b/src/render/backend/managers_p.h @@ -428,6 +428,7 @@ class JointManager : public Qt3DCore::QResourceManager< { public: void addDirtyJoint(Qt3DCore::QNodeId jointId); + void removeDirtyJoint(Qt3DCore::QNodeId jointId); QVector dirtyJoints(); private: 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); } -- cgit v1.2.3 From 69f112354dc09645a21db75f0630140c4480d809 Mon Sep 17 00:00:00 2001 From: Juan Jose Casafranca Date: Thu, 20 Jun 2019 14:02:07 +0200 Subject: Take shortest path on quaternion slerp Change-Id: I4499e945481a22adfbafcc82198f7c411d04301b Reviewed-by: Sean Harmer --- src/animation/backend/animationutils.cpp | 37 ++++++++++++++++++++++++++------ src/animation/backend/fcurve.cpp | 11 +++++----- src/animation/backend/fcurve_p.h | 2 +- 3 files changed, 38 insertions(+), 12 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); -- cgit v1.2.3 From c9eb1f347a501c6915595bfb705af3aecc2fbadd Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Thu, 11 Jul 2019 16:19:28 +0200 Subject: QRay3D: normalize the direction vector internally It can be created with a non normalized dir vector but we should always perform the computations with a normalized dir vector for correct results. Change-Id: Ie9108de7ed2092f6b979a70ad9391267fe6c4696 Reviewed-by: Sean Harmer --- src/render/raycasting/qray3d.cpp | 8 ++++---- tests/auto/render/qray3d/tst_qray3d.cpp | 36 ++++++++++++++++----------------- 2 files changed, 22 insertions(+), 22 deletions(-) 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/tests/auto/render/qray3d/tst_qray3d.cpp b/tests/auto/render/qray3d/tst_qray3d.cpp index e9d4d3033..008b89aca 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(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", qVariantFromValue @@ -511,7 +511,7 @@ void tst_QRay3D::properties() r = qvariant_cast(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() -- cgit v1.2.3 From f6816c121ab237c9956aeafd61d8d8a424edb07a Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Mon, 1 Jul 2019 08:20:22 +0200 Subject: Fix compilation with -qt3d-profile-jobs Which otherwise fails following the introduction of ShaderImage Change-Id: Ie41057974cef133e4e9b9718df370b82ee7d3d65 Reviewed-by: Sean Harmer --- src/render/backend/commandexecuter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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); -- cgit v1.2.3 From b63aaf574c6b4b5a40e2f137f077c694bcf79ae0 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Tue, 9 Jul 2019 09:41:13 -0500 Subject: Document an example of how textureScale might be used Change-Id: Iead857526a06b104080ab843b26c49efc22f05cc Reviewed-by: Paul Lemire --- src/doc/src/qmlextramaterials.qdoc | 20 ++++++++++++++++++++ src/extras/defaults/qdiffusemapmaterial.cpp | 3 +++ src/extras/defaults/qdiffusespecularmapmaterial.cpp | 4 ++++ src/extras/defaults/qdiffusespecularmaterial.cpp | 8 ++++++++ src/extras/defaults/qmetalroughmaterial.cpp | 8 ++++++++ src/extras/defaults/qnormaldiffusemapmaterial.cpp | 4 ++++ .../defaults/qnormaldiffusespecularmapmaterial.cpp | 4 ++++ 7 files changed, 51 insertions(+) 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 { -- cgit v1.2.3 From cc834ee647dee624805215d8270cb6f23083aa2a Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Mon, 17 Jun 2019 07:47:33 +0200 Subject: Fix following recent Scene3DRenderer changes f39178a415cb41470775a86e0aa358faa3686d81 makes QtQuick redraw only when something in the 3D scene has triggered a change. A function is connected to QQuickWindow::afterSynchronizing to check whether the 3D scene needs to be drawn again and if so the corresponding SceneGraph nodes are marked as dirty. However, we need to ensure the SceneGraph picks up that we've marked a node as dirty by calling QQuickItem::update(). This forces updatePaintNode to be called at the next frame since the afterSynchronizing stage occurs after that step. This fixes rendering freezes with the Always render policy. Change-Id: I041dbe69d12a7e6e884c8ee0e29720d74ce5fa2f Reviewed-by: Sean Harmer --- src/quick3d/imports/scene3d/scene3drenderer.cpp | 1 + 1 file changed, 1 insertion(+) 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(); } } -- cgit v1.2.3 From a7ca5cdec02ce67e28dacd0e6e2e5d666d872dcd Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Wed, 17 Jul 2019 12:43:47 +0200 Subject: RenderStates: fix override of nested RenderStates When merging states, make sure we don't add several states of the same types with possibly different values. We should only add states with type we don't already have. Since the FG traversal is done from leaf to root, we know that the states we already contain should override any state that may have been specified higher up in the FG branch. Change-Id: I9bd1eadd37e8addf740a4b85b2318f9be269fedb Task-number: QTBUG-76766 Reviewed-by: Sean Harmer --- .../renderers/opengl/jobs/renderviewjobutils.cpp | 14 +- .../renderers/opengl/jobs/renderviewjobutils_p.h | 6 +- .../renderers/opengl/renderer/renderview.cpp | 5 +- .../opengl/renderstates/renderstateset.cpp | 15 ++ .../opengl/renderstates/renderstateset_p.h | 3 + src/render/renderstates/genericstate_p.h | 2 +- src/render/renderstates/renderstatenode_p.h | 2 +- .../auto/render/qrenderstate/tst_qrenderstate.cpp | 8 +- tests/manual/manual.pro | 3 +- tests/manual/qtbug-76766/FrameGraph.qml | 140 ++++++++++++++++ tests/manual/qtbug-76766/Material1.qml | 93 +++++++++++ tests/manual/qtbug-76766/Material2.qml | 105 ++++++++++++ tests/manual/qtbug-76766/PostProcess.qml | 117 ++++++++++++++ tests/manual/qtbug-76766/SceneRoot.qml | 176 +++++++++++++++++++++ tests/manual/qtbug-76766/expected_output.png | Bin 0 -> 22639 bytes tests/manual/qtbug-76766/main.cpp | 74 +++++++++ tests/manual/qtbug-76766/main.qml | 76 +++++++++ tests/manual/qtbug-76766/qml.qrc | 11 ++ tests/manual/qtbug-76766/qtbug-76766.pro | 10 ++ tests/manual/qtbug-76766/shaders.qrc | 6 + tests/manual/qtbug-76766/shaders/shader.frag | 11 ++ tests/manual/qtbug-76766/shaders/shader.vert | 36 +++++ 22 files changed, 894 insertions(+), 19 deletions(-) create mode 100644 tests/manual/qtbug-76766/FrameGraph.qml create mode 100644 tests/manual/qtbug-76766/Material1.qml create mode 100644 tests/manual/qtbug-76766/Material2.qml create mode 100644 tests/manual/qtbug-76766/PostProcess.qml create mode 100644 tests/manual/qtbug-76766/SceneRoot.qml create mode 100644 tests/manual/qtbug-76766/expected_output.png create mode 100644 tests/manual/qtbug-76766/main.cpp create mode 100644 tests/manual/qtbug-76766/main.qml create mode 100644 tests/manual/qtbug-76766/qml.qrc create mode 100644 tests/manual/qtbug-76766/qtbug-76766.pro create mode 100644 tests/manual/qtbug-76766/shaders.qrc create mode 100644 tests/manual/qtbug-76766/shaders/shader.frag create mode 100644 tests/manual/qtbug-76766/shaders/shader.vert diff --git a/src/render/renderers/opengl/jobs/renderviewjobutils.cpp b/src/render/renderers/opengl/jobs/renderviewjobutils.cpp index acb38ffb9..49e85e1d3 100644 --- a/src/render/renderers/opengl/jobs/renderviewjobutils.cpp +++ b/src/render/renderers/opengl/jobs/renderviewjobutils.cpp @@ -193,8 +193,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; } @@ -417,14 +419,16 @@ void parametersFromMaterialEffectTechnique(ParameterInfoList *infoList, parametersFromParametersProvider(infoList, manager, technique); } -void addToRenderStateSet(RenderStateSet *stateSet, - const QVector stateIds, - RenderStateManager *manager) +// Only add states with types we don't already have +void addUniqueStatesToRenderStateSet(RenderStateSet *stateSet, + const QVector 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 stateIds, - RenderStateManager *manager); +Q_AUTOTEST_EXPORT void addUniqueStatesToRenderStateSet(RenderStateSet *stateSet, + const QVector stateIds, + RenderStateManager *manager); typedef QHash UniformBlockValueBuilderHash; diff --git a/src/render/renderers/opengl/renderer/renderview.cpp b/src/render/renderers/opengl/renderer/renderview.cpp index be9968d06..2c96939a7 100644 --- a/src/render/renderers/opengl/renderer/renderview.cpp +++ b/src/render/renderers/opengl/renderer/renderview.cpp @@ -603,10 +603,7 @@ QVector RenderView::buildDrawRenderCommands(const QVectorhasRenderStates()) { 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); 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 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 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(&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/tests/auto/render/qrenderstate/tst_qrenderstate.cpp b/tests/auto/render/qrenderstate/tst_qrenderstate.cpp index 6e90f4ce1..dc2a9b242 100644 --- a/tests/auto/render/qrenderstate/tst_qrenderstate.cpp +++ b/tests/auto/render/qrenderstate/tst_qrenderstate.cpp @@ -183,8 +183,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 @@ -268,8 +268,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 4900add69..5b197ff47 100644 --- a/tests/manual/manual.pro +++ b/tests/manual/manual.pro @@ -61,7 +61,8 @@ SUBDIRS += \ raycasting-qml \ shared_texture_image \ texture_property_updates \ - qtbug-72236 + qtbug-72236 \ + qtbug-76766 qtHaveModule(widgets): { SUBDIRS += \ 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 new file mode 100644 index 000000000..8f642e843 Binary files /dev/null and b/tests/manual/qtbug-76766/expected_output.png differ 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 +#include +#include + +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 @@ + + + main.qml + SceneRoot.qml + FrameGraph.qml + PostProcess.qml + Material1.qml + Material2.qml + expected_output.png + + 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 @@ + + + shaders/shader.frag + shaders/shader.vert + + 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); +} -- cgit v1.2.3 From 509e5730b02284fa2998032b97524e367abcf262 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 10 Jul 2019 20:45:04 +0200 Subject: Remove unused file gltfparser.cpp Found because it's full of Q_FOREACH when the module compiles fine with QT_NO_FOREACH... Change-Id: I8e34a3f54c1070d4dcc9b5c7b578760860eab72c Reviewed-by: Paul Lemire --- src/plugins/sceneparsers/gltf/gltfparser.cpp | 1560 -------------------------- 1 file changed, 1560 deletions(-) delete mode 100644 src/plugins/sceneparsers/gltf/gltfparser.cpp 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 -#include -#include -#include - -#include - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -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 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(); - 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 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 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(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(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(sampler.value(KEY_WRAP_S).toInt()))); - tex->setMinificationFilter(static_cast(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(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(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(value.toInt())); - case GL_UNSIGNED_BYTE: - return QVariant(static_cast(value.toInt())); - case GL_SHORT: - return QVariant(static_cast(value.toInt())); - case GL_UNSIGNED_SHORT: - return QVariant(static_cast(value.toInt())); - case GL_INT: - return QVariant(static_cast(value.toInt())); - case GL_UNSIGNED_INT: - return QVariant(static_cast(value.toInt())); - case GL_FLOAT: - return QVariant(static_cast(value.toDouble())); - } - } else if (value.isArray()) { - - QJsonArray valueArray = value.toArray(); - - QVector2D vector2D; - QVector3D vector3D; - QVector4D vector4D; - QVector dataMat2(4, 0.0f); - QVector dataMat3(9, 0.0f); - - switch (type) { - case GL_BYTE: - return QVariant(static_cast(valueArray.first().toInt())); - case GL_UNSIGNED_BYTE: - return QVariant(static_cast(valueArray.first().toInt())); - case GL_SHORT: - return QVariant(static_cast(valueArray.first().toInt())); - case GL_UNSIGNED_SHORT: - return QVariant(static_cast(valueArray.first().toInt())); - case GL_INT: - return QVariant(static_cast(valueArray.first().toInt())); - case GL_UNSIGNED_INT: - return QVariant(static_cast(valueArray.first().toInt())); - case GL_FLOAT: - return QVariant(static_cast(valueArray.first().toDouble())); - case GL_FLOAT_VEC2: - vector2D.setX(static_cast(valueArray.at(0).toDouble())); - vector2D.setY(static_cast(valueArray.at(1).toDouble())); - return QVariant(vector2D); - case GL_FLOAT_VEC3: - vector3D.setX(static_cast(valueArray.at(0).toDouble())); - vector3D.setY(static_cast(valueArray.at(1).toDouble())); - vector3D.setZ(static_cast(valueArray.at(2).toDouble())); - return QVariant(vector3D); - case GL_FLOAT_VEC4: - vector4D.setX(static_cast(valueArray.at(0).toDouble())); - vector4D.setY(static_cast(valueArray.at(1).toDouble())); - vector4D.setZ(static_cast(valueArray.at(2).toDouble())); - vector4D.setW(static_cast(valueArray.at(3).toDouble())); - return QVariant(vector4D); - case GL_INT_VEC2: - vector2D.setX(static_cast(valueArray.at(0).toInt())); - vector2D.setY(static_cast(valueArray.at(1).toInt())); - return QVariant(vector2D); - case GL_INT_VEC3: - vector3D.setX(static_cast(valueArray.at(0).toInt())); - vector3D.setY(static_cast(valueArray.at(1).toInt())); - vector3D.setZ(static_cast(valueArray.at(2).toInt())); - return QVariant(vector3D); - case GL_INT_VEC4: - vector4D.setX(static_cast(valueArray.at(0).toInt())); - vector4D.setY(static_cast(valueArray.at(1).toInt())); - vector4D.setZ(static_cast(valueArray.at(2).toInt())); - vector4D.setW(static_cast(valueArray.at(3).toInt())); - return QVariant(vector4D); - case GL_BOOL: - return QVariant(static_cast(valueArray.first().toBool())); - case GL_BOOL_VEC2: - vector2D.setX(static_cast(valueArray.at(0).toBool())); - vector2D.setY(static_cast(valueArray.at(1).toBool())); - return QVariant(vector2D); - case GL_BOOL_VEC3: - vector3D.setX(static_cast(valueArray.at(0).toBool())); - vector3D.setY(static_cast(valueArray.at(1).toBool())); - vector3D.setZ(static_cast(valueArray.at(2).toBool())); - return QVariant(vector3D); - case GL_BOOL_VEC4: - vector4D.setX(static_cast(valueArray.at(0).toBool())); - vector4D.setY(static_cast(valueArray.at(1).toBool())); - vector4D.setZ(static_cast(valueArray.at(2).toBool())); - vector4D.setW(static_cast(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(valueArray.at(0).toDouble()); - dataMat2[1] = static_cast(valueArray.at(2).toDouble()); - dataMat2[2] = static_cast(valueArray.at(1).toDouble()); - dataMat2[3] = static_cast(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(valueArray.at(0).toDouble()); - dataMat3[1] = static_cast(valueArray.at(3).toDouble()); - dataMat3[2] = static_cast(valueArray.at(6).toDouble()); - dataMat3[3] = static_cast(valueArray.at(1).toDouble()); - dataMat3[4] = static_cast(valueArray.at(4).toDouble()); - dataMat3[5] = static_cast(valueArray.at(7).toDouble()); - dataMat3[6] = static_cast(valueArray.at(2).toDouble()); - dataMat3[7] = static_cast(valueArray.at(5).toDouble()); - dataMat3[8] = static_cast(valueArray.at(8).toDouble()); - return QVariant::fromValue(QMatrix3x3(dataMat3.constData())); - case GL_FLOAT_MAT4: - //Matrix4x4 is Column Major ordering - return QVariant(QMatrix4x4(static_cast(valueArray.at(0).toDouble()), - static_cast(valueArray.at(1).toDouble()), - static_cast(valueArray.at(2).toDouble()), - static_cast(valueArray.at(3).toDouble()), - static_cast(valueArray.at(4).toDouble()), - static_cast(valueArray.at(5).toDouble()), - static_cast(valueArray.at(6).toDouble()), - static_cast(valueArray.at(7).toDouble()), - static_cast(valueArray.at(8).toDouble()), - static_cast(valueArray.at(9).toDouble()), - static_cast(valueArray.at(10).toDouble()), - static_cast(valueArray.at(11).toDouble()), - static_cast(valueArray.at(12).toDouble()), - static_cast(valueArray.at(13).toDouble()), - static_cast(valueArray.at(14).toDouble()), - static_cast(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 -- cgit v1.2.3 From a576ce8e0e4a5fb0aa2a09523f17522f0357faae Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Wed, 17 Jul 2019 12:49:01 +0200 Subject: Align RenderView::buildComputeRenderCommands with buildDrawRenderCommands State and parameter handling are the same between the two branches Change-Id: Ic8394a969184daead33253c9303c20ecf1a97484 Reviewed-by: Sean Harmer --- src/render/renderers/opengl/renderer/renderview.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/render/renderers/opengl/renderer/renderview.cpp b/src/render/renderers/opengl/renderer/renderview.cpp index 2c96939a7..62758bb53 100644 --- a/src/render/renderers/opengl/renderer/renderview.cpp +++ b/src/render/renderers/opengl/renderer/renderview.cpp @@ -718,15 +718,26 @@ QVector RenderView::buildComputeRenderCommands(const QVectorparameterManager(), 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, -- cgit v1.2.3 From 0e250e9e943daf88df09f1ad1bd11a46e1084da0 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Fri, 19 Jul 2019 10:16:31 +0200 Subject: Renderer: use last known good surface to reset render states We were instead checking against the last surface used (which could be null) instead of the last known good surface to reset the render states. This could result in not resetting the render states and keeping dangling pointers around. To know if we can render, we check find the first non null surface in the list of RV. In most cases we can safelly assume that if first RV has a surface, all following ones will likely use the same surface. If we have no good surface we skip the rendering. However in the case you have a FG where the first RV has a surface but not the last one (which wouldn't really make sense but can happen if you mess up), we could end up in the above case where surface is nullptr though we have partially rendered something for the RV which had valid surfaces. Change-Id: I902b8c7a943ad2ca7e2f487873f73990cf8db433 Reviewed-by: Mike Krus --- src/render/renderers/opengl/renderer/renderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/renderers/opengl/renderer/renderer.cpp b/src/render/renderers/opengl/renderer/renderer.cpp index 59949ee34..aeb3e513d 100644 --- a/src/render/renderers/opengl/renderer/renderer.cpp +++ b/src/render/renderers/opengl/renderer/renderer.cpp @@ -1585,7 +1585,7 @@ Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVectorhasValidGLHelper()) { + 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) -- cgit v1.2.3 From 1bb43d7be48813ba318bc2613d020dc8a3b71746 Mon Sep 17 00:00:00 2001 From: Mike Krus Date: Fri, 19 Jul 2019 10:29:36 +0100 Subject: Silence warnings about null textures in uniforms It's common while textures are loading Change-Id: I360c88c72fbd0a034aff07451fd49be17b348d40 Reviewed-by: Paul Lemire --- src/render/backend/uniform.cpp | 6 ++++++ 1 file changed, 6 insertions(+) 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(), mat33.constData(), 9 * sizeof(float)); break; } + if (variant.userType() == qMetaTypeId()) { + // silently ignore null texture pointers as they are common while textures are loading + if (variant.value() == nullptr) + break; + } qWarning() << "Unknown uniform type or value:" << variant << "Please check your QParameters"; } } -- cgit v1.2.3 From 91abded59c7d212788059e76234beeddb0bd2af7 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Sun, 21 Jul 2019 13:13:47 +0300 Subject: Remove unused includes Change-Id: I402937171aca2eaaeaea5ced3fd9095db08a38d5 Reviewed-by: Paul Lemire --- src/core/services/qeventfilterservice.cpp | 1 - src/render/raycasting/qraycastingservice.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/src/core/services/qeventfilterservice.cpp b/src/core/services/qeventfilterservice.cpp index c4ec79a13..4855d69ed 100644 --- a/src/core/services/qeventfilterservice.cpp +++ b/src/core/services/qeventfilterservice.cpp @@ -39,7 +39,6 @@ #include "qeventfilterservice_p.h" -#include #include #include 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 #include -#include #include #include "math.h" -- cgit v1.2.3 From 7c5f56277cd0c7450a168af6188ee4753655ca31 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Sun, 21 Jul 2019 13:28:08 +0300 Subject: AssimpImporter: remove unused QMap The variable is referenced no-where else. Change-Id: Iad385c83a1fd3de260f830bf27edabeab7f17cb5 Reviewed-by: Paul Lemire --- src/plugins/sceneparsers/assimp/assimpimporter.h | 2 -- 1 file changed, 2 deletions(-) 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 #include -#include #include #include #include @@ -139,7 +138,6 @@ private: Assimp::Importer *m_importer; mutable const aiScene *m_aiScene; - QMap m_embeddedTextures; QHash m_textureToParameterName; QVector m_animations; QVector m_morphAnimations; -- cgit v1.2.3 From 9b91d68df0a812b2fa0dd3da3f06ff0724033a46 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Tue, 17 May 2016 13:05:26 +0200 Subject: assimp plugin: replace QMap with a C array The keys are statically known, short, and few, so replace the QMap with a C array of a {char[2]; OpenMode} struct, which occupies just 40B in read-only memory. We don't even need to sort the list, as binary search in a list of ten entries is slower than linear search (five comparisons each, on average, with the linear scan having a predictable memory access pattern. This is a port of dd1d8f51e67ec93031fdd7f7930d63761d1238e6 to the other copy of this code, which shows that arguments like 'this is just a tool, not a library' are ill-advised. Code _will_ be copied. Change-Id: Ie04137f94e487ce998ec077daf655b09bcbbcfc7 Reviewed-by: Paul Lemire --- src/plugins/sceneparsers/assimp/assimphelpers.cpp | 57 +++++++++++------------ src/plugins/sceneparsers/assimp/assimphelpers.h | 6 --- 2 files changed, 28 insertions(+), 35 deletions(-) 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(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 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 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 #include #include -#include 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 m_openModeMaps; }; } // namespace AssimpHelper -- cgit v1.2.3 From 51c49dc6f0ade027ba390cb28a7424fc5903c069 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Mon, 22 Jul 2019 09:23:58 -0500 Subject: Provide more detail in *Light documentation Change-Id: I8d56836f1f075c7239b262454131062c10058026 Reviewed-by: Paul Lemire --- src/render/lights/qdirectionallight.cpp | 6 ++++++ src/render/lights/qenvironmentlight.cpp | 6 ++++++ src/render/lights/qpointlight.cpp | 27 +++++++++++++++++++++++++++ src/render/lights/qspotlight.cpp | 24 ++++++++++++++++++++++++ 4 files changed, 63 insertions(+) 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. */ /*! -- cgit v1.2.3 From c1e4d12d22112ed12471f6929f293d4db854e882 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Tue, 23 Jul 2019 14:25:54 +0200 Subject: Add QML documentation to QSkyboxEntity Change-Id: Id82777c111827e8db8924d2d39b5844386344b69 Task-number: QTBUG-76767 Reviewed-by: Mike Krus --- src/extras/defaults/qskyboxentity.cpp | 45 +++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) 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 @@ -237,6 +237,30 @@ void QSkyboxEntityPrivate::reloadTexture() * \since 5.5 */ +/*! + * \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. */ @@ -268,6 +292,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. */ @@ -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 -- cgit v1.2.3 From 309c3139f8111ea246dd3a1f996578d0b35bb151 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Wed, 24 Jul 2019 14:09:55 +0200 Subject: ShaderData: don't call markDirty(AllDirty) But only markDirty(ParametersDirty) as that's the only thing this is affecting. Change-Id: I450d013dc266ca70ca51cfa866b731a6e8b6499a Reviewed-by: Mike Krus --- src/render/materialsystem/shaderdata.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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); -- cgit v1.2.3 From a5c148c89344ff230d984a6c9036fd11df48d37d Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Wed, 24 Jul 2019 14:09:55 +0200 Subject: ShaderData: don't call markDirty(AllDirty) But only markDirty(ParametersDirty) as that's the only thing this is affecting. Change-Id: I450d013dc266ca70ca51cfa866b731a6e8b6499a Reviewed-by: Mike Krus --- src/render/materialsystem/shaderdata.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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); -- cgit v1.2.3 From ff884fcc2c9ddf7b5bc37dad8c998f56b67a8c14 Mon Sep 17 00:00:00 2001 From: Mike Krus Date: Mon, 29 Jul 2019 14:43:17 +0100 Subject: Fix deprecation warnings Change-Id: Ie36f38180d7cca5d8586aec765608bb2cdfb3d4a Reviewed-by: Sean Harmer --- src/plugins/sceneparsers/gltf/gltfimporter.cpp | 11 ----------- 1 file changed, 11 deletions(-) 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; } -- cgit v1.2.3 From d2c52680884095238ec3859fabaad03157af3985 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 31 Jul 2019 08:54:08 +0300 Subject: QWheelEvent: temporarily disable deprecation warnings around x(), y() ... in an attempt to unblock qt5 integration. Put the warning suppression macros further apart than necessary to avoid clashing with the actual fix. Change-Id: I362712d1c6b3035966179755cdc6e631d1954255 Reviewed-by: Friedemann Kleint --- src/input/frontend/qmouseevent.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/input/frontend/qmouseevent.h b/src/input/frontend/qmouseevent.h index a7aa8fe2b..87b648be3 100644 --- a/src/input/frontend/qmouseevent.h +++ b/src/input/frontend/qmouseevent.h @@ -107,6 +107,8 @@ private: typedef QSharedPointer QMouseEventPtr; +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED #if QT_CONFIG(wheelevent) class Q_3DINPUTSHARED_EXPORT QWheelEvent : public QObject { @@ -155,6 +157,7 @@ public: private: QT_PREPEND_NAMESPACE(QWheelEvent) m_event; }; +QT_WARNING_POP typedef QSharedPointer QWheelEventPtr; #endif -- cgit v1.2.3 From f3b6963f8b873c190cc1033cb8dabaf1d63ee2b6 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Sat, 27 Jul 2019 16:32:28 +0300 Subject: QEventFilterService: these aren't the algorithms you're looking for The event filters are ordered by priority, so don't use a linear scan in order to find whether one with the same position already exists, use lower_bound, whose result at the same time gives the position of an existing filter (if any), as well as the insertion position for the new element. So no need to do a full sort afterwards, either. Change the exisitng op< into an aptly-named lambda, and don't depend on transitive includes. Also, since this code does not need the CoW feature of QVector, port to std::vector, which is faster and produces more compact code. Altogether saves ~2KiB (0.47%) in text size on optimized Linux AMD64 GCC 9.1 builds. Change-Id: Ie46ca2fbb2dcbea23a0098a72336604776dcc296 Reviewed-by: Mike Krus --- src/core/services/qeventfilterservice.cpp | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/core/services/qeventfilterservice.cpp b/src/core/services/qeventfilterservice.cpp index 4855d69ed..036bcd7b4 100644 --- a/src/core/services/qeventfilterservice.cpp +++ b/src/core/services/qeventfilterservice.cpp @@ -40,10 +40,12 @@ #include "qeventfilterservice_p.h" #include -#include #include +#include +#include + QT_BEGIN_NAMESPACE namespace { @@ -53,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); @@ -88,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::iterator it = m_eventFilters.begin(); - const QVector::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 m_eventDispatcher; - QVector m_eventFilters; + std::vector m_eventFilters; }; /* !\internal @@ -178,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; } -- cgit v1.2.3 From 9df4bab665115177b35ca1aeee6a18e9610e3a32 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Sat, 27 Jul 2019 16:58:26 +0300 Subject: QMouseEvent: port away from deprecated QWheelEvent::x/y() Inline the function's QtBase implementations into the code here. Change-Id: I9e9b8b7612f3ca5dcbff7bb8cd33d3355ea170f5 Reviewed-by: Liang Qi --- src/input/frontend/qmouseevent.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/input/frontend/qmouseevent.h b/src/input/frontend/qmouseevent.h index 87b648be3..fb9d4f86f 100644 --- a/src/input/frontend/qmouseevent.h +++ b/src/input/frontend/qmouseevent.h @@ -144,8 +144,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; -- cgit v1.2.3 From 238ea650cc711668b4c55fe5f208fba31da98b57 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 31 Jul 2019 07:50:36 +0000 Subject: Revert "QWheelEvent: temporarily disable deprecation warnings around x(), y()" This reverts commit d2c52680884095238ec3859fabaad03157af3985. That was a temporary measure to get qt5 integration going. The code has since been ported, so this can now be removed again. Change-Id: I96e0470481ad8744048bef72a45f07a3bb63e2ba Reviewed-by: Volker Hilsheimer --- src/input/frontend/qmouseevent.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/input/frontend/qmouseevent.h b/src/input/frontend/qmouseevent.h index fb9d4f86f..1402d8210 100644 --- a/src/input/frontend/qmouseevent.h +++ b/src/input/frontend/qmouseevent.h @@ -107,8 +107,6 @@ private: typedef QSharedPointer QMouseEventPtr; -QT_WARNING_PUSH -QT_WARNING_DISABLE_DEPRECATED #if QT_CONFIG(wheelevent) class Q_3DINPUTSHARED_EXPORT QWheelEvent : public QObject { @@ -157,7 +155,6 @@ public: private: QT_PREPEND_NAMESPACE(QWheelEvent) m_event; }; -QT_WARNING_POP typedef QSharedPointer QWheelEventPtr; #endif -- cgit v1.2.3 From 9a7fc48ba656ef2ba5c5f43926346a7af417d121 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Fri, 28 Jun 2019 12:13:57 +0200 Subject: Port from QMutex::Recursive to QRecursiveMutex Also port from QMutexLocker to std::lock_guard, as the former will not support QRecursiveMutex going forward. Change-Id: I65e14492fc0583e5d0018aef64e18db8a6023dc8 Reviewed-by: Thiago Macieira --- src/core/qchangearbiter.cpp | 21 +++++++++++---------- src/core/qchangearbiter_p.h | 2 +- 2 files changed, 12 insertions(+), 11 deletions(-) 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 #include +#include + 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::tlsChangeQueue() void QChangeArbiter::appendChangeQueue(QChangeArbiter::QChangeQueue *queue) { - QMutexLocker locker(&m_mutex); + const std::lock_guard locker(m_mutex);; m_changeQueues.append(queue); } void QChangeArbiter::removeChangeQueue(QChangeArbiter::QChangeQueue *queue) { - QMutexLocker locker(&m_mutex); + const std::lock_guard locker(m_mutex);; m_changeQueues.removeOne(queue); } void QChangeArbiter::appendLockingChangeQueue(QChangeArbiter::QChangeQueue *queue) { - QMutexLocker locker(&m_mutex); + const std::lock_guard locker(m_mutex);; m_lockingChangeQueues.append(queue); } void QChangeArbiter::removeLockingChangeQueue(QChangeArbiter::QChangeQueue *queue) { - QMutexLocker locker(&m_mutex); + const std::lock_guard locker(m_mutex);; m_lockingChangeQueues.removeOne(queue); } void QChangeArbiter::syncChanges() { - QMutexLocker locker(&m_mutex); + const std::lock_guard 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 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 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 locker(m_mutex);; sceneChangeEvent(e); } void QChangeArbiter::sceneChangeEventWithLock(const QSceneChangeList &e) { - QMutexLocker locker(&m_mutex); + const std::lock_guard 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). -- cgit v1.2.3 From 2efe9d733c162f425c993c586f524e9d1de88f31 Mon Sep 17 00:00:00 2001 From: Wang Chuan Date: Mon, 29 Jul 2019 21:51:19 +0800 Subject: QImageTextureDataFunctor: return invalid data when url is invalid Since QSkyboxEntity creating empty cube map first and using QTimer to delay loading real cube map, in render thread, GLTexture will use the generator function of empty cube map to generate a QTextureImageDataPtr at first, this will set the format of property of GLTexture to NoFormat, and terminate the creation of GLTexture. Although GLTexture read real real cube map next time, format will not be reset and the creation of GLTexture terminates. [ChangeLog][Qt3DRender][QImageTextureDataFunctor] return a invalid image data when url is invalid to ensure the property of GLTexture will not be set to NoFormat Fixes: QTBUG-74017 Change-Id: If48f727dba817a931d618b2b88c7ebd54c508c47 Reviewed-by: Paul Lemire --- src/render/texture/qtextureimage.cpp | 4 ++- tests/auto/render/gltexture/tst_gltexture.cpp | 38 +++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) 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 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); -- cgit v1.2.3 From 7be8029d4c2cd0ce24f0277d6ee87041161edab4 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Mon, 5 Aug 2019 09:15:40 +0200 Subject: qshaderimage_p.h: add missing We mean it warning Change-Id: Idbf02a3852c5128e41f79d376900e6d06ba1a0c5 Reviewed-by: Mike Krus --- src/render/materialsystem/qshaderimage_p.h | 11 +++++++++++ 1 file changed, 11 insertions(+) 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 #include -- cgit v1.2.3