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