summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2020-04-22 10:11:08 +0200
committerQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2020-04-22 10:11:08 +0200
commit153ad09effc7388d331c478f0cfe697232a89705 (patch)
treef8cc97601e2a238188b71fc8b2c2f6692fdc576b
parent652bedbc0824d7887c8983924e54c08eb8833ffb (diff)
parenta01dbe5b0e1b912c7210abc304700020e685aff0 (diff)
downloadqt3d-153ad09effc7388d331c478f0cfe697232a89705.tar.gz
Merge remote-tracking branch 'origin/5.15' into 5.15.0
Change-Id: I7eabf19598b9f23919ee803c2e784fcf653eb741
-rw-r--r--dist/changes-5.14.220
-rw-r--r--examples/qt3d/basicshapes-cpp/main.cpp5
-rw-r--r--src/animation/backend/handler.cpp25
-rw-r--r--src/animation/frontend/qchannelmapper.cpp3
-rw-r--r--src/core/jobs/qaspectjob_p.h2
-rw-r--r--src/core/transforms/matrix4x4_avx2_p.h4
-rw-r--r--src/extras/defaults/qmetalroughmaterial.cpp29
-rw-r--r--src/extras/defaults/qt3dwindow.cpp6
-rw-r--r--src/extras/extras.qrc17
-rw-r--r--src/extras/shaders/es2/phong.inc.frag1008
-rw-r--r--src/extras/shaders/graphs/phong.graph466
-rw-r--r--src/extras/shaders/rhi/coordinatesystems.inc70
-rw-r--r--src/extras/shaders/rhi/default.vert82
-rw-r--r--src/extras/shaders/rhi/distancefieldtext.frag39
-rw-r--r--src/extras/shaders/rhi/distancefieldtext.vert19
-rw-r--r--src/extras/shaders/rhi/gooch.frag63
-rw-r--r--src/extras/shaders/rhi/gooch.vert19
-rw-r--r--src/extras/shaders/rhi/light.inc.frag26
-rw-r--r--src/extras/shaders/rhi/metalrough.inc.frag346
-rw-r--r--src/extras/shaders/rhi/morphphong.vert34
-rw-r--r--src/extras/shaders/rhi/pervertexcolor.frag17
-rw-r--r--src/extras/shaders/rhi/pervertexcolor.vert22
-rw-r--r--src/extras/shaders/rhi/phong.inc.frag138
-rw-r--r--src/extras/shaders/rhi/skybox.frag24
-rw-r--r--src/extras/shaders/rhi/skybox.vert16
-rw-r--r--src/extras/shaders/rhi/unlittexture.frag13
-rw-r--r--src/extras/shaders/rhi/unlittexture.vert20
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/submissioncontext.cpp16
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/submissioncontext_p.h2
-rw-r--r--src/plugins/renderers/opengl/jobs/renderviewjobutils.cpp9
-rw-r--r--src/plugins/renderers/opengl/jobs/renderviewjobutils_p.h4
-rw-r--r--src/plugins/renderers/opengl/renderer/glshader.cpp80
-rw-r--r--src/plugins/renderers/opengl/renderer/glshader_p.h35
-rw-r--r--src/plugins/renderers/opengl/renderer/renderer.cpp11
-rw-r--r--src/plugins/renderers/opengl/renderer/renderview.cpp106
-rw-r--r--src/plugins/renderers/opengl/renderer/renderview_p.h16
-rw-r--r--src/plugins/renderers/opengl/renderer/renderviewbuilder.cpp2
-rw-r--r--src/plugins/renderers/opengl/renderer/shaderparameterpack.cpp5
-rw-r--r--src/plugins/renderers/opengl/renderer/shaderparameterpack_p.h6
-rw-r--r--src/plugins/renderers/rhi/renderer/renderview.cpp56
-rw-r--r--src/quick3d/imports/scene3d/importsscene3d.pro2
-rw-r--r--src/quick3d/imports/scene3d/scene3dcleaner.cpp75
-rw-r--r--src/quick3d/imports/scene3d/scene3dcleaner_p.h82
-rw-r--r--src/quick3d/imports/scene3d/scene3ditem.cpp120
-rw-r--r--src/quick3d/imports/scene3d/scene3ditem_p.h10
-rw-r--r--src/quick3d/imports/scene3d/scene3drenderer.cpp44
-rw-r--r--src/quick3d/imports/scene3d/scene3drenderer_p.h15
-rw-r--r--src/render/framegraph/qlayerfilter.cpp3
-rw-r--r--src/render/framegraph/qrenderpassfilter.cpp6
-rw-r--r--src/render/framegraph/qrenderstateset.cpp3
-rw-r--r--src/render/framegraph/qtechniquefilter.cpp6
-rw-r--r--src/render/frontend/qrenderaspect.cpp7
-rw-r--r--src/render/frontend/qrendertarget.cpp3
-rw-r--r--src/render/geometry/qgeometry.cpp3
-rw-r--r--src/render/materialsystem/prototypes/default.json72
-rw-r--r--src/render/materialsystem/qeffect.cpp9
-rw-r--r--src/render/materialsystem/qgraphicsapifilter.cpp22
-rw-r--r--src/render/materialsystem/qgraphicsapifilter_p.h2
-rw-r--r--src/render/materialsystem/qmaterial.cpp4
-rw-r--r--src/render/materialsystem/qrenderpass.cpp9
-rw-r--r--src/render/materialsystem/qtechnique.cpp9
-rw-r--r--src/render/materialsystem/shaderbuilder.cpp5
-rw-r--r--src/render/materialsystem/shaderdata.cpp2
-rw-r--r--src/render/materialsystem/shaderdata_p.h2
-rw-r--r--src/render/picking/qabstractraycaster.cpp3
-rw-r--r--src/render/shadergraph/qshadergenerator.cpp375
-rw-r--r--src/render/shadergraph/qshadernodesloader.cpp3
-rw-r--r--src/render/texture/qabstracttexture.cpp3
-rw-r--r--tests/auto/render/shadergraph/qshadergenerator/tst_qshadergenerator.cpp2
-rw-r--r--tests/manual/manual.pro2
-rw-r--r--tests/manual/quickwidget-switch/main.cpp125
-rw-r--r--tests/manual/quickwidget-switch/main.qml152
-rw-r--r--tests/manual/quickwidget-switch/quickwidget-switch.pro13
-rw-r--r--tests/manual/quickwidget-switch/quickwidget-switch.qrc5
-rw-r--r--tests/manual/quickwindow-switch/main.cpp68
-rw-r--r--tests/manual/quickwindow-switch/main.qml181
-rw-r--r--tests/manual/quickwindow-switch/quickwindow-switch.pro13
-rw-r--r--tests/manual/quickwindow-switch/quickwindow-switch.qrc5
-rw-r--r--tools/qgltf/qgltf.cpp2
79 files changed, 2851 insertions, 497 deletions
diff --git a/dist/changes-5.14.2 b/dist/changes-5.14.2
new file mode 100644
index 000000000..68a005176
--- /dev/null
+++ b/dist/changes-5.14.2
@@ -0,0 +1,20 @@
+Qt 5.14.2 is a bug-fix release. It maintains both forward and backward
+compatibility (source and binary) with Qt 5.14.0 through 5.14.1.
+
+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.14 series is binary compatible with the 5.13.x series.
+Applications compiled for 5.13 will continue to run with 5.14.
+
+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/examples/qt3d/basicshapes-cpp/main.cpp b/examples/qt3d/basicshapes-cpp/main.cpp
index fffb83a20..a347e9fb2 100644
--- a/examples/qt3d/basicshapes-cpp/main.cpp
+++ b/examples/qt3d/basicshapes-cpp/main.cpp
@@ -63,8 +63,6 @@
#include <QtWidgets/QCommandLinkButton>
#include <QtGui/QScreen>
-#include <Qt3DInput/QInputAspect>
-
#include <Qt3DExtras/qtorusmesh.h>
#include <Qt3DRender/qmesh.h>
#include <Qt3DRender/qtechnique.h>
@@ -103,9 +101,6 @@ int main(int argc, char **argv)
widget->setWindowTitle(QStringLiteral("Basic shapes"));
- Qt3DInput::QInputAspect *input = new Qt3DInput::QInputAspect;
- view->registerAspect(input);
-
// Root entity
Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity();
diff --git a/src/animation/backend/handler.cpp b/src/animation/backend/handler.cpp
index 84543c264..95363d56f 100644
--- a/src/animation/backend/handler.cpp
+++ b/src/animation/backend/handler.cpp
@@ -44,6 +44,7 @@
#include <Qt3DAnimation/private/animationlogging_p.h>
#include <Qt3DAnimation/private/buildblendtreesjob_p.h>
#include <Qt3DAnimation/private/evaluateblendclipanimatorjob_p.h>
+#include <Qt3DCore/private/qaspectjob_p.h>
QT_BEGIN_NAMESPACE
@@ -115,11 +116,7 @@ void Handler::setClipAnimatorRunning(const HClipAnimator &handle, bool running)
// If being marked as not running, remove from set of running clips
if (!running) {
- const auto it = std::find_if(m_runningClipAnimators.begin(),
- m_runningClipAnimators.end(),
- [handle](const HClipAnimator &h) { return h == handle; });
- if (it != m_runningClipAnimators.end())
- m_runningClipAnimators.erase(it);
+ m_runningClipAnimators.removeAll(handle);
}
}
@@ -205,13 +202,14 @@ QVector<Qt3DCore::QAspectJobPtr> Handler::jobsToExecute(qint64 time)
const bool hasFindRunningClipAnimatorsJob = !m_dirtyClipAnimators.isEmpty();
if (hasFindRunningClipAnimatorsJob) {
qCDebug(HandlerLogic) << "Added FindRunningClipAnimatorsJob";
- m_findRunningClipAnimatorsJob->removeDependency(QWeakPointer<Qt3DCore::QAspectJob>());
cleanupHandleList(&m_dirtyClipAnimators);
m_findRunningClipAnimatorsJob->setDirtyClipAnimators(m_dirtyClipAnimators);
+ // Only set the dependency once
+ if (Q_UNLIKELY(m_findRunningClipAnimatorsJob->dependencies().empty()))
+ m_findRunningClipAnimatorsJob->addDependency(m_loadAnimationClipJob);
jobs.push_back(m_findRunningClipAnimatorsJob);
if (hasLoadAnimationClipJob)
- m_findRunningClipAnimatorsJob->addDependency(m_loadAnimationClipJob);
- m_dirtyClipAnimators.clear();
+ m_dirtyClipAnimators.clear();
}
// Rebuild blending trees if a blend tree is dirty
@@ -244,13 +242,10 @@ QVector<Qt3DCore::QAspectJobPtr> Handler::jobsToExecute(qint64 time)
// Set each job up with an animator to process and set dependencies
for (int i = 0; i < newSize; ++i) {
m_evaluateClipAnimatorJobs[i]->setClipAnimator(m_runningClipAnimators[i]);
- m_evaluateClipAnimatorJobs[i]->removeDependency(QWeakPointer<Qt3DCore::QAspectJob>());
- if (hasLoadAnimationClipJob &&
- !m_evaluateClipAnimatorJobs[i]->dependencies().contains(m_loadAnimationClipJob))
+ Qt3DCore::QAspectJobPrivate::get(m_evaluateClipAnimatorJobs[i].data())->clearDependencies();
+ if (hasLoadAnimationClipJob)
m_evaluateClipAnimatorJobs[i]->addDependency(m_loadAnimationClipJob);
-
- if (hasFindRunningClipAnimatorsJob &&
- !m_evaluateClipAnimatorJobs[i]->dependencies().contains(m_findRunningClipAnimatorsJob))
+ if (hasFindRunningClipAnimatorsJob)
m_evaluateClipAnimatorJobs[i]->addDependency(m_findRunningClipAnimatorsJob);
jobs.push_back(m_evaluateClipAnimatorJobs[i]);
}
@@ -273,7 +268,7 @@ QVector<Qt3DCore::QAspectJobPtr> Handler::jobsToExecute(qint64 time)
// Set each job up with an animator to process and set dependencies
for (int i = 0; i < newSize; ++i) {
m_evaluateBlendClipAnimatorJobs[i]->setBlendClipAnimator(m_runningBlendedClipAnimators[i]);
- m_evaluateBlendClipAnimatorJobs[i]->removeDependency(QWeakPointer<Qt3DCore::QAspectJob>());
+ Qt3DCore::QAspectJobPrivate::get(m_evaluateBlendClipAnimatorJobs[i].data())->clearDependencies();
if (hasLoadAnimationClipJob)
m_evaluateBlendClipAnimatorJobs[i]->addDependency(m_loadAnimationClipJob);
if (hasBuildBlendTreesJob)
diff --git a/src/animation/frontend/qchannelmapper.cpp b/src/animation/frontend/qchannelmapper.cpp
index c5909adbc..aa88add1a 100644
--- a/src/animation/frontend/qchannelmapper.cpp
+++ b/src/animation/frontend/qchannelmapper.cpp
@@ -94,7 +94,8 @@ void QChannelMapper::removeMapping(QAbstractChannelMapping *mapping)
{
Q_ASSERT(mapping);
Q_D(QChannelMapper);
- d->m_mappings.removeOne(mapping);
+ if (!d->m_mappings.removeOne(mapping))
+ return;
d->updateNode(mapping, "mappings", Qt3DCore::PropertyValueRemoved);
// Remove bookkeeping connection
d->unregisterDestructionHelper(mapping);
diff --git a/src/core/jobs/qaspectjob_p.h b/src/core/jobs/qaspectjob_p.h
index 0337fa107..0c7802b02 100644
--- a/src/core/jobs/qaspectjob_p.h
+++ b/src/core/jobs/qaspectjob_p.h
@@ -75,6 +75,8 @@ public:
virtual bool isRequired() const;
virtual void postFrame(QAspectManager *aspectManager);
+ void clearDependencies() { m_dependencies.clear(); }
+
QVector<QWeakPointer<QAspectJob> > m_dependencies;
JobId m_jobId;
QString m_jobName;
diff --git a/src/core/transforms/matrix4x4_avx2_p.h b/src/core/transforms/matrix4x4_avx2_p.h
index 0b35f0016..de40ee2a0 100644
--- a/src/core/transforms/matrix4x4_avx2_p.h
+++ b/src/core/transforms/matrix4x4_avx2_p.h
@@ -485,8 +485,8 @@ public:
friend Vector4D operator*(const Vector4D &vector, const Matrix4x4_AVX2 &matrix);
friend Vector4D operator*(const Matrix4x4_AVX2 &matrix, const Vector4D &vector);
- friend Q_3DCORE_PRIVATE_EXPORT Vector3D operator*(const Vector3D &vector, const Matrix4x4_AVX2 &matrix);
- friend Q_3DCORE_PRIVATE_EXPORT Vector3D operator*(const Matrix4x4_AVX2 &matrix, const Vector3D &vector);
+ friend Vector3D operator*(const Vector3D &vector, const Matrix4x4_AVX2 &matrix);
+ friend Vector3D operator*(const Matrix4x4_AVX2 &matrix, const Vector3D &vector);
friend Q_3DCORE_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const Matrix4x4_AVX2 &m);
diff --git a/src/extras/defaults/qmetalroughmaterial.cpp b/src/extras/defaults/qmetalroughmaterial.cpp
index a969593db..7d5ee61ea 100644
--- a/src/extras/defaults/qmetalroughmaterial.cpp
+++ b/src/extras/defaults/qmetalroughmaterial.cpp
@@ -143,6 +143,11 @@ void QMetalRoughMaterialPrivate::init()
m_metalRoughES3Technique->addRenderPass(m_metalRoughES3RenderPass);
m_metalRoughEffect->addTechnique(m_metalRoughES3Technique);
+ // Given parameters a parent
+ m_baseColorMapParameter->setParent(m_metalRoughEffect);
+ m_metalnessMapParameter->setParent(m_metalRoughEffect);
+ m_roughnessMapParameter->setParent(m_metalRoughEffect);
+
m_metalRoughEffect->addParameter(m_baseColorParameter);
m_metalRoughEffect->addParameter(m_metalnessParameter);
m_metalRoughEffect->addParameter(m_roughnessParameter);
@@ -338,11 +343,13 @@ void QMetalRoughMaterial::setBaseColor(const QVariant &baseColor)
layers.removeAll(QStringLiteral("baseColor"));
layers.append(QStringLiteral("baseColorMap"));
d->m_metalRoughEffect->addParameter(d->m_baseColorMapParameter);
- d->m_metalRoughEffect->removeParameter(d->m_baseColorParameter);
+ if (d->m_metalRoughEffect->parameters().contains(d->m_baseColorParameter))
+ d->m_metalRoughEffect->removeParameter(d->m_baseColorParameter);
} else {
layers.removeAll(QStringLiteral("baseColorMap"));
layers.append(QStringLiteral("baseColor"));
- d->m_metalRoughEffect->removeParameter(d->m_baseColorMapParameter);
+ if (d->m_metalRoughEffect->parameters().contains(d->m_baseColorMapParameter))
+ d->m_metalRoughEffect->removeParameter(d->m_baseColorMapParameter);
d->m_metalRoughEffect->addParameter(d->m_baseColorParameter);
}
d->m_metalRoughGL3ShaderBuilder->setEnabledLayers(layers);
@@ -360,11 +367,13 @@ void QMetalRoughMaterial::setMetalness(const QVariant &metalness)
layers.removeAll(QStringLiteral("metalness"));
layers.append(QStringLiteral("metalnessMap"));
d->m_metalRoughEffect->addParameter(d->m_metalnessMapParameter);
- d->m_metalRoughEffect->removeParameter(d->m_metalnessParameter);
+ if (d->m_metalRoughEffect->parameters().contains(d->m_metalnessParameter))
+ d->m_metalRoughEffect->removeParameter(d->m_metalnessParameter);
} else {
layers.removeAll(QStringLiteral("metalnessMap"));
layers.append(QStringLiteral("metalness"));
- d->m_metalRoughEffect->removeParameter(d->m_metalnessMapParameter);
+ if (d->m_metalRoughEffect->parameters().contains(d->m_metalnessMapParameter))
+ d->m_metalRoughEffect->removeParameter(d->m_metalnessMapParameter);
d->m_metalRoughEffect->addParameter(d->m_metalnessParameter);
}
d->m_metalRoughGL3ShaderBuilder->setEnabledLayers(layers);
@@ -382,11 +391,13 @@ void QMetalRoughMaterial::setRoughness(const QVariant &roughness)
layers.removeAll(QStringLiteral("roughness"));
layers.append(QStringLiteral("roughnessMap"));
d->m_metalRoughEffect->addParameter(d->m_roughnessMapParameter);
- d->m_metalRoughEffect->removeParameter(d->m_roughnessParameter);
+ if (d->m_metalRoughEffect->parameters().contains(d->m_roughnessParameter))
+ d->m_metalRoughEffect->removeParameter(d->m_roughnessParameter);
} else {
layers.removeAll(QStringLiteral("roughnessMap"));
layers.append(QStringLiteral("roughness"));
- d->m_metalRoughEffect->removeParameter(d->m_roughnessMapParameter);
+ if (d->m_metalRoughEffect->parameters().contains(d->m_roughnessMapParameter))
+ d->m_metalRoughEffect->removeParameter(d->m_roughnessMapParameter);
d->m_metalRoughEffect->addParameter(d->m_roughnessParameter);
}
d->m_metalRoughGL3ShaderBuilder->setEnabledLayers(layers);
@@ -406,7 +417,8 @@ void QMetalRoughMaterial::setAmbientOcclusion(const QVariant &ambientOcclusion)
} else {
layers.removeAll(QStringLiteral("ambientOcclusionMap"));
layers.append(QStringLiteral("ambientOcclusion"));
- d->m_metalRoughEffect->removeParameter(d->m_ambientOcclusionMapParameter);
+ if (d->m_metalRoughEffect->parameters().contains(d->m_ambientOcclusionMapParameter))
+ d->m_metalRoughEffect->removeParameter(d->m_ambientOcclusionMapParameter);
}
d->m_metalRoughGL3ShaderBuilder->setEnabledLayers(layers);
d->m_metalRoughES3ShaderBuilder->setEnabledLayers(layers);
@@ -425,7 +437,8 @@ void QMetalRoughMaterial::setNormal(const QVariant &normal)
} else {
layers.removeAll(QStringLiteral("normalMap"));
layers.append(QStringLiteral("normal"));
- d->m_metalRoughEffect->removeParameter(d->m_normalMapParameter);
+ if (d->m_metalRoughEffect->parameters().contains(d->m_normalMapParameter))
+ d->m_metalRoughEffect->removeParameter(d->m_normalMapParameter);
}
d->m_metalRoughGL3ShaderBuilder->setEnabledLayers(layers);
d->m_metalRoughES3ShaderBuilder->setEnabledLayers(layers);
diff --git a/src/extras/defaults/qt3dwindow.cpp b/src/extras/defaults/qt3dwindow.cpp
index eb0961113..4cf3af250 100644
--- a/src/extras/defaults/qt3dwindow.cpp
+++ b/src/extras/defaults/qt3dwindow.cpp
@@ -183,6 +183,12 @@ Qt3DWindow::Qt3DWindow(QScreen *screen, Qt3DRender::API api)
format.setProfile(QSurfaceFormat::CoreProfile);
}
#endif
+
+ if (!userRequestedApi.isEmpty()) {
+ // This is used for RHI
+ format.setVersion(1, 0);
+ }
+
format.setDepthBufferSize(24);
format.setSamples(4);
format.setStencilBufferSize(8);
diff --git a/src/extras/extras.qrc b/src/extras/extras.qrc
index 2aedc6622..8d7085264 100644
--- a/src/extras/extras.qrc
+++ b/src/extras/extras.qrc
@@ -39,5 +39,22 @@
<file>shaders/es2/distancefieldtext.vert</file>
<file>shaders/gl3/morphphong.vert</file>
<file>shaders/es2/morphphong.vert</file>
+ <file>shaders/graphs/phong.graph</file>
+ <file>shaders/rhi/unlittexture.vert</file>
+ <file>shaders/rhi/unlittexture.frag</file>
+ <file>shaders/rhi/skybox.vert</file>
+ <file>shaders/rhi/skybox.frag</file>
+ <file>shaders/rhi/phong.inc.frag</file>
+ <file>shaders/rhi/pervertexcolor.vert</file>
+ <file>shaders/rhi/pervertexcolor.frag</file>
+ <file>shaders/rhi/morphphong.vert</file>
+ <file>shaders/rhi/metalrough.inc.frag</file>
+ <file>shaders/rhi/light.inc.frag</file>
+ <file>shaders/rhi/gooch.vert</file>
+ <file>shaders/rhi/gooch.frag</file>
+ <file>shaders/rhi/distancefieldtext.vert</file>
+ <file>shaders/rhi/distancefieldtext.frag</file>
+ <file>shaders/rhi/default.vert</file>
+ <file>shaders/rhi/coordinatesystems.inc</file>
</qresource>
</RCC>
diff --git a/src/extras/shaders/es2/phong.inc.frag100 b/src/extras/shaders/es2/phong.inc.frag100
index 0c326d0b6..c68c8e41a 100644
--- a/src/extras/shaders/es2/phong.inc.frag100
+++ b/src/extras/shaders/es2/phong.inc.frag100
@@ -66,8 +66,8 @@ void adsModel(const in FP vec3 vpos, const in FP vec3 vnormal, const in FP vec3
if ( lights[0].type != TYPE_DIRECTIONAL ) {
s = lights[0].position - vpos;
if (lights[0].constantAttenuation != 0.0
- || light[0].linearAttenuation != 0.0
- || light[0].quadraticAttenuation != 0.0) {
+ || lights[0].linearAttenuation != 0.0
+ || lights[0].quadraticAttenuation != 0.0) {
FP float dist = length(s);
att = 1.0 / (lights[0].constantAttenuation + lights[0].linearAttenuation * dist + lights[0].quadraticAttenuation * dist * dist);
}
@@ -99,8 +99,8 @@ void adsModel(const in FP vec3 vpos, const in FP vec3 vnormal, const in FP vec3
if ( lights[1].type != TYPE_DIRECTIONAL ) {
s = lights[1].position - vpos;
if (lights[1].constantAttenuation != 0.0
- || light[1].linearAttenuation != 0.0
- || light[1].quadraticAttenuation != 0.0) {
+ || lights[1].linearAttenuation != 0.0
+ || lights[1].quadraticAttenuation != 0.0) {
FP float dist = length(s);
att = 1.0 / (lights[1].constantAttenuation + lights[1].linearAttenuation * dist + lights[1].quadraticAttenuation * dist * dist);
}
diff --git a/src/extras/shaders/graphs/phong.graph b/src/extras/shaders/graphs/phong.graph
new file mode 100644
index 000000000..dedeb1067
--- /dev/null
+++ b/src/extras/shaders/graphs/phong.graph
@@ -0,0 +1,466 @@
+{
+ "nodes": [
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000001}",
+ "type": "input",
+ "parameters": {
+ "name": "worldPosition",
+ "qualifier": {
+ "type": "QShaderLanguage::StorageQualifier",
+ "value": "QShaderLanguage::Input"
+ },
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000002}",
+ "type": "eyePosition"
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000003}",
+ "type": "input",
+ "parameters": {
+ "name": "worldNormal",
+ "qualifier": {
+ "type": "QShaderLanguage::StorageQualifier",
+ "value": "QShaderLanguage::Input"
+ },
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000004}",
+ "type": "input",
+ "layers": ["normalTexture"],
+ "parameters": {
+ "name": "worldTangent",
+ "qualifier": {
+ "type": "QShaderLanguage::StorageQualifier",
+ "value": "QShaderLanguage::Input"
+ },
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec4"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000005}",
+ "type": "input",
+ "layers": ["diffuseTexture", "specularTexture", "normalTexture"],
+ "parameters": {
+ "name": "texCoord",
+ "qualifier": {
+ "type": "QShaderLanguage::StorageQualifier",
+ "value": "QShaderLanguage::Input"
+ },
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec2"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000006}",
+ "type": "input",
+ "parameters": {
+ "name": "ka",
+ "qualifier": {
+ "type": "QShaderLanguage::StorageQualifier",
+ "value": "QShaderLanguage::Uniform"
+ },
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec4"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000007}",
+ "type": "input",
+ "layers": ["diffuse"],
+ "parameters": {
+ "name": "kd",
+ "qualifier": {
+ "type": "QShaderLanguage::StorageQualifier",
+ "value": "QShaderLanguage::Uniform"
+ },
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec4"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000008}",
+ "type": "sampleTexture",
+ "layers": ["diffuseTexture"],
+ "parameters": {
+ "name": "diffuseTexture"
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000009}",
+ "type": "input",
+ "layers": ["specular"],
+ "parameters": {
+ "name": "ks",
+ "qualifier": {
+ "type": "QShaderLanguage::StorageQualifier",
+ "value": "QShaderLanguage::Uniform"
+ },
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec4"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000010}",
+ "layers": ["specularTexture"],
+ "type": "sampleTexture",
+ "parameters": {
+ "name": "specularTexture"
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000011}",
+ "type": "input",
+ "parameters": {
+ "name": "shininess",
+ "qualifier": {
+ "type": "QShaderLanguage::StorageQualifier",
+ "value": "QShaderLanguage::Uniform"
+ },
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Float"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000012}",
+ "type": "subtract",
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000013}",
+ "type": "normalize",
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000014}",
+ "type": "normalize",
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000015}",
+ "type": "worldSpaceToTangentSpaceMatrix",
+ "layers": ["normalTexture"]
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000016}",
+ "type": "transpose",
+ "layers": ["normalTexture"],
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Mat3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000017}",
+ "type": "sampleTexture",
+ "layers": ["normalTexture"],
+ "parameters": {
+ "name": "normalTexture"
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000018}",
+ "type": "swizzle",
+ "layers": ["normalTexture"],
+ "parameters": {
+ "fields": "rgb",
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000019}",
+ "type": "constant",
+ "layers": ["normalTexture"],
+ "parameters": {
+ "constant": "2.0",
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Float"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000020}",
+ "type": "multiply",
+ "layers": ["normalTexture"],
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000021}",
+ "type": "constant",
+ "layers": ["normalTexture"],
+ "parameters": {
+ "constant": "1.0",
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000022}",
+ "type": "subtract",
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000023}",
+ "type": "multiply",
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000024}",
+ "type": "phongFunction"
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000025}",
+ "type": "fragColor"
+ }
+ ],
+ "edges": [
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000001}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000024}",
+ "targetPort": "worldPosition"
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000001}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000012}",
+ "targetPort": "subtrahend"
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000002}",
+ "sourcePort": "eyePosition",
+ "targetUuid": "{00000000-0000-0000-0000-000000000012}",
+ "targetPort": "minuend"
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000012}",
+ "sourcePort": "difference",
+ "targetUuid": "{00000000-0000-0000-0000-000000000013}",
+ "targetPort": "input"
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000013}",
+ "sourcePort": "output",
+ "targetUuid": "{00000000-0000-0000-0000-000000000024}",
+ "targetPort": "worldView"
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000003}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000014}",
+ "targetPort": "input",
+ "layers": ["normal"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000003}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000015}",
+ "targetPort": "worldNormal",
+ "layers": ["normalTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000004}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000015}",
+ "targetPort": "worldTangent",
+ "layers": ["normalTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000015}",
+ "sourcePort": "matrix",
+ "targetUuid": "{00000000-0000-0000-0000-000000000016}",
+ "targetPort": "input",
+ "layers": ["normalTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000016}",
+ "sourcePort": "output",
+ "targetUuid": "{00000000-0000-0000-0000-000000000023}",
+ "targetPort": "first",
+ "layers": ["normalTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000005}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000017}",
+ "targetPort": "coord",
+ "layers": ["normalTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000017}",
+ "sourcePort": "color",
+ "targetUuid": "{00000000-0000-0000-0000-000000000018}",
+ "targetPort": "input",
+ "layers": ["normalTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000018}",
+ "sourcePort": "output",
+ "targetUuid": "{00000000-0000-0000-0000-000000000020}",
+ "targetPort": "first",
+ "layers": ["normalTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000019}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000020}",
+ "targetPort": "second",
+ "layers": ["normalTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000020}",
+ "sourcePort": "product",
+ "targetUuid": "{00000000-0000-0000-0000-000000000022}",
+ "targetPort": "minuend",
+ "layers": ["normalTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000021}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000022}",
+ "targetPort": "subtrahend",
+ "layers": ["normalTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000022}",
+ "sourcePort": "difference",
+ "targetUuid": "{00000000-0000-0000-0000-000000000023}",
+ "targetPort": "second",
+ "layers": ["normalTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000023}",
+ "sourcePort": "product",
+ "targetUuid": "{00000000-0000-0000-0000-000000000014}",
+ "targetPort": "input",
+ "layers": ["normalTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000014}",
+ "sourcePort": "output",
+ "targetUuid": "{00000000-0000-0000-0000-000000000024}",
+ "targetPort": "worldNormal"
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000006}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000024}",
+ "targetPort": "ambient"
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000007}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000024}",
+ "targetPort": "diffuse",
+ "layers": ["diffuse"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000005}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000008}",
+ "targetPort": "coord",
+ "layers": ["diffuseTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000008}",
+ "sourcePort": "color",
+ "targetUuid": "{00000000-0000-0000-0000-000000000024}",
+ "targetPort": "diffuse",
+ "layers": ["diffuseTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000009}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000024}",
+ "targetPort": "specular",
+ "layers": ["specular"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000005}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000010}",
+ "targetPort": "coord",
+ "layers": ["specularTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000010}",
+ "sourcePort": "color",
+ "targetUuid": "{00000000-0000-0000-0000-000000000024}",
+ "targetPort": "specular",
+ "layers": ["specularTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000011}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000024}",
+ "targetPort": "shininess"
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000024}",
+ "sourcePort": "outputColor",
+ "targetUuid": "{00000000-0000-0000-0000-000000000025}",
+ "targetPort": "fragColor"
+ }
+ ]
+}
diff --git a/src/extras/shaders/rhi/coordinatesystems.inc b/src/extras/shaders/rhi/coordinatesystems.inc
new file mode 100644
index 000000000..ed3d2cb92
--- /dev/null
+++ b/src/extras/shaders/rhi/coordinatesystems.inc
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+mat3 calcWorldSpaceToTangentSpaceMatrix(const in vec3 wNormal, const in vec4 wTangent)
+{
+ // Make the tangent truly orthogonal to the normal by using Gram-Schmidt.
+ // This allows to build the tangentMatrix below by simply transposing the
+ // tangent -> eyespace matrix (which would now be orthogonal)
+ vec3 wFixedTangent = normalize(wTangent.xyz - dot(wTangent.xyz, wNormal) * wNormal);
+
+ // Calculate binormal vector. No "real" need to renormalize it,
+ // as built by crossing two normal vectors.
+ // To orient the binormal correctly, use the fourth coordinate of the tangent,
+ // which is +1 for a right hand system, and -1 for a left hand system.
+ vec3 wBinormal = cross(wNormal, wFixedTangent.xyz) * wTangent.w;
+
+ // Construct matrix to transform from world space to tangent space
+ // This is the transpose of the tangentToWorld transformation matrix
+ mat3 tangentToWorldMatrix = mat3(wFixedTangent, wBinormal, wNormal);
+ mat3 worldToTangentMatrix = transpose(tangentToWorldMatrix);
+ return worldToTangentMatrix;
+}
+
diff --git a/src/extras/shaders/rhi/default.vert b/src/extras/shaders/rhi/default.vert
new file mode 100644
index 000000000..f97cd099d
--- /dev/null
+++ b/src/extras/shaders/rhi/default.vert
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#version 150 core
+
+in vec3 vertexPosition;
+in vec3 vertexNormal;
+in vec4 vertexTangent;
+in vec2 vertexTexCoord;
+
+out vec3 worldPosition;
+out vec3 worldNormal;
+out vec4 worldTangent;
+out vec2 texCoord;
+
+uniform mat4 modelMatrix;
+uniform mat3 modelNormalMatrix;
+uniform mat4 modelViewProjection;
+
+uniform float texCoordScale;
+
+void main()
+{
+ // Pass through scaled texture coordinates
+ texCoord = vertexTexCoord * texCoordScale;
+
+ // Transform position, normal, and tangent to world space
+ 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 vertex position in clip coordinates
+ gl_Position = modelViewProjection * vec4(vertexPosition, 1.0);
+}
diff --git a/src/extras/shaders/rhi/distancefieldtext.frag b/src/extras/shaders/rhi/distancefieldtext.frag
new file mode 100644
index 000000000..998fa6e79
--- /dev/null
+++ b/src/extras/shaders/rhi/distancefieldtext.frag
@@ -0,0 +1,39 @@
+#version 150 core
+
+uniform sampler2D distanceFieldTexture;
+uniform float minAlpha;
+uniform float maxAlpha;
+uniform float textureSize;
+uniform vec4 color;
+
+in vec2 texCoord;
+in float zValue;
+
+out vec4 fragColor;
+
+void main()
+{
+ // determine the scale of the glyph texture within pixel-space coordinates
+ // (that is, how many pixels are drawn for each texel)
+ vec2 texelDeltaX = abs(dFdx(texCoord));
+ vec2 texelDeltaY = abs(dFdy(texCoord));
+ float avgTexelDelta = textureSize * 0.5 * (texelDeltaX.x + texelDeltaX.y + texelDeltaY.x + texelDeltaY.y);
+ float texScale = 1.0 / avgTexelDelta;
+
+ // scaled to interval [0.0, 0.15]
+ float devScaleMin = 0.00;
+ float devScaleMax = 0.15;
+ float scaled = (clamp(texScale, devScaleMin, devScaleMax) - devScaleMin) / (devScaleMax - devScaleMin);
+
+ // thickness of glyphs should increase a lot for very small glyphs to make them readable
+ float base = 0.5;
+ float threshold = base * scaled;
+ float range = 0.06 / texScale;
+
+ float minAlpha = threshold - range;
+ float maxAlpha = threshold + range;
+
+ float distVal = texture(distanceFieldTexture, texCoord).r;
+ fragColor = vec4(color.rgb, color.a * smoothstep(minAlpha, maxAlpha, distVal));
+ gl_FragDepth = gl_FragCoord.z - zValue * 0.000001;
+}
diff --git a/src/extras/shaders/rhi/distancefieldtext.vert b/src/extras/shaders/rhi/distancefieldtext.vert
new file mode 100644
index 000000000..f6743001c
--- /dev/null
+++ b/src/extras/shaders/rhi/distancefieldtext.vert
@@ -0,0 +1,19 @@
+#version 150 core
+
+in vec3 vertexPosition;
+in vec2 vertexTexCoord;
+
+out vec2 texCoord;
+out float zValue;
+
+uniform mat4 modelView;
+uniform mat4 mvp;
+
+void main()
+{
+ texCoord = vertexTexCoord;
+ zValue = vertexPosition.z;
+
+ gl_Position = mvp * vec4(vertexPosition.xy, 0.0, 1.0);
+}
+
diff --git a/src/extras/shaders/rhi/gooch.frag b/src/extras/shaders/rhi/gooch.frag
new file mode 100644
index 000000000..168a862f8
--- /dev/null
+++ b/src/extras/shaders/rhi/gooch.frag
@@ -0,0 +1,63 @@
+#version 150 core
+
+// TODO: Replace with a struct
+uniform vec3 kd; // Diffuse reflectivity
+uniform vec3 ks; // Specular reflectivity
+uniform vec3 kblue; // Cool color
+uniform vec3 kyellow; // Warm color
+uniform float alpha; // Fraction of diffuse added to kblue
+uniform float beta; // Fraction of diffuse added to kyellow
+uniform float shininess; // Specular shininess factor
+
+uniform vec3 eyePosition;
+
+in vec3 worldPosition;
+in vec3 worldNormal;
+
+out vec4 fragColor;
+
+#pragma include light.inc.frag
+
+vec3 goochModel( const in vec3 pos, const in vec3 n )
+{
+ // Based upon the original Gooch lighting model paper at:
+ // http://www.cs.northwestern.edu/~ago820/SIG98/abstract.html
+
+ // Calculate kcool and kwarm from equation (3)
+ vec3 kcool = clamp(kblue + alpha * kd, 0.0, 1.0);
+ vec3 kwarm = clamp(kyellow + beta * kd, 0.0, 1.0);
+
+ vec3 result = vec3(0.0);
+ for (int i = 0; i < lightCount; ++i) {
+ // Calculate the vector from the light to the fragment
+ vec3 s = normalize( vec3( lights[i].position ) - pos );
+
+ // Calculate the cos theta factor mapped onto the range [0,1]
+ float sDotNFactor = ( 1.0 + dot( s, n ) ) / 2.0;
+
+ // Calculate the tone by blending the kcool and kwarm contributions
+ // as per equation (2)
+ vec3 intensity = mix( kcool, kwarm, sDotNFactor );
+
+ // Calculate the vector from the fragment to the eye position
+ vec3 v = normalize( eyePosition - pos );
+
+ // Reflect the light beam using the normal at this fragment
+ vec3 r = reflect( -s, n );
+
+ // Calculate the specular component
+ float specular = 0.0;
+ if ( dot( s, n ) > 0.0 )
+ specular = pow( max( dot( r, v ), 0.0 ), shininess );
+
+ // Sum the blended tone and specular highlight
+ result += intensity + ks * specular;
+ }
+
+ return result;
+}
+
+void main()
+{
+ fragColor = vec4( goochModel( worldPosition, normalize( worldNormal ) ), 1.0 );
+}
diff --git a/src/extras/shaders/rhi/gooch.vert b/src/extras/shaders/rhi/gooch.vert
new file mode 100644
index 000000000..5230fb70e
--- /dev/null
+++ b/src/extras/shaders/rhi/gooch.vert
@@ -0,0 +1,19 @@
+#version 150 core
+
+in vec3 vertexPosition;
+in vec3 vertexNormal;
+
+out vec3 worldPosition;
+out vec3 worldNormal;
+
+uniform mat4 modelMatrix;
+uniform mat3 modelNormalMatrix;
+uniform mat4 mvp;
+
+void main()
+{
+ worldNormal = normalize( modelNormalMatrix * vertexNormal );
+ worldPosition = vec3( modelMatrix * vec4( vertexPosition, 1.0 ) );
+
+ gl_Position = mvp * vec4( vertexPosition, 1.0 );
+}
diff --git a/src/extras/shaders/rhi/light.inc.frag b/src/extras/shaders/rhi/light.inc.frag
new file mode 100644
index 000000000..861e1ba4a
--- /dev/null
+++ b/src/extras/shaders/rhi/light.inc.frag
@@ -0,0 +1,26 @@
+const int MAX_LIGHTS = 8;
+const int TYPE_POINT = 0;
+const int TYPE_DIRECTIONAL = 1;
+const int TYPE_SPOT = 2;
+struct Light {
+ int type;
+ vec3 position;
+ vec3 color;
+ float intensity;
+ vec3 direction;
+ float constantAttenuation;
+ float linearAttenuation;
+ float quadraticAttenuation;
+ float cutOffAngle;
+};
+
+
+layout(std140, binding = auto) uniform qt3d_light_uniforms {
+ uniform Light lights[MAX_LIGHTS];
+ uniform int lightCount;
+ uniform int envLightCount;
+};
+
+// Pre-convolved environment maps
+layout(binding = auto) uniform samplerCube envLight_irradiance; // For diffuse contribution
+layout(binding = auto) uniform samplerCube envLight_specular; // For specular contribution
diff --git a/src/extras/shaders/rhi/metalrough.inc.frag b/src/extras/shaders/rhi/metalrough.inc.frag
new file mode 100644
index 000000000..cf85f3b22
--- /dev/null
+++ b/src/extras/shaders/rhi/metalrough.inc.frag
@@ -0,0 +1,346 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// Exposure correction
+uniform float exposure = 0.0;
+// Gamma correction
+uniform float gamma = 2.2;
+
+#pragma include light.inc.frag
+
+int mipLevelCount(const in samplerCube cube)
+{
+ int baseSize = textureSize(cube, 0).x;
+ int nMips = int(log2(float(baseSize > 0 ? baseSize : 1))) + 1;
+ return nMips;
+}
+
+float remapRoughness(const in float roughness)
+{
+ // As per page 14 of
+ // http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf
+ // we remap the roughness to give a more perceptually linear response
+ // of "bluriness" as a function of the roughness specified by the user.
+ // r = roughness^2
+ const float maxSpecPower = 999999.0;
+ const float minRoughness = sqrt(2.0 / (maxSpecPower + 2));
+ return max(roughness * roughness, minRoughness);
+}
+
+float alphaToMipLevel(float alpha)
+{
+ float specPower = 2.0 / (alpha * alpha) - 2.0;
+
+ // We use the mip level calculation from Lys' default power drop, which in
+ // turn is a slight modification of that used in Marmoset Toolbag. See
+ // https://docs.knaldtech.com/doku.php?id=specular_lys for details.
+ // For now we assume a max specular power of 999999 which gives
+ // maxGlossiness = 1.
+ const float k0 = 0.00098;
+ const float k1 = 0.9921;
+ float glossiness = (pow(2.0, -10.0 / sqrt(specPower)) - k0) / k1;
+
+ // TODO: Optimize by doing this on CPU and set as
+ // uniform int envLight.specularMipLevels say (if present in shader).
+ // Lookup the number of mips in the specular envmap
+ int mipLevels = mipLevelCount(envLight_specular);
+
+ // Offset of smallest miplevel we should use (corresponds to specular
+ // power of 1). I.e. in the 32x32 sized mip.
+ const float mipOffset = 5.0;
+
+ // The final factor is really 1 - g / g_max but as mentioned above g_max
+ // is 1 by definition here so we can avoid the division. If we make the
+ // max specular power for the spec map configurable, this will need to
+ // be handled properly.
+ float mipLevel = (mipLevels - 1.0 - mipOffset) * (1.0 - glossiness);
+ return mipLevel;
+}
+
+float normalDistribution(const in vec3 n, const in vec3 h, const in float alpha)
+{
+ // Blinn-Phong approximation - see
+ // http://graphicrants.blogspot.co.uk/2013/08/specular-brdf-reference.html
+ float specPower = 2.0 / (alpha * alpha) - 2.0;
+ return (specPower + 2.0) / (2.0 * 3.14159) * pow(max(dot(n, h), 0.0), specPower);
+}
+
+vec3 fresnelFactor(const in vec3 color, const in float cosineFactor)
+{
+ // Calculate the Fresnel effect value
+ vec3 f = color;
+ vec3 F = f + (1.0 - f) * pow(1.0 - cosineFactor, 5.0);
+ return clamp(F, f, vec3(1.0));
+}
+
+float geometricModel(const in float lDotN,
+ const in float vDotN,
+ const in vec3 h)
+{
+ // Implicit geometric model (equal to denominator in specular model).
+ // This currently assumes that there is no attenuation by geometric shadowing or
+ // masking according to the microfacet theory.
+ return lDotN * vDotN;
+}
+
+vec3 specularModel(const in vec3 F0,
+ const in float sDotH,
+ const in float sDotN,
+ const in float vDotN,
+ const in vec3 n,
+ const in vec3 h)
+{
+ // Clamp sDotN and vDotN to small positive value to prevent the
+ // denominator in the reflection equation going to infinity. Balance this
+ // by using the clamped values in the geometric factor function to
+ // avoid ugly seams in the specular lighting.
+ float sDotNPrime = max(sDotN, 0.001);
+ float vDotNPrime = max(vDotN, 0.001);
+
+ vec3 F = fresnelFactor(F0, sDotH);
+ float G = geometricModel(sDotNPrime, vDotNPrime, h);
+
+ vec3 cSpec = F * G / (4.0 * sDotNPrime * vDotNPrime);
+ return clamp(cSpec, vec3(0.0), vec3(1.0));
+}
+
+vec3 pbrModel(const in int lightIndex,
+ const in vec3 wPosition,
+ const in vec3 wNormal,
+ const in vec3 wView,
+ const in vec3 baseColor,
+ const in float metalness,
+ const in float alpha,
+ const in float ambientOcclusion)
+{
+ // Calculate some useful quantities
+ vec3 n = wNormal;
+ vec3 s = vec3(0.0);
+ vec3 v = wView;
+ vec3 h = vec3(0.0);
+
+ float vDotN = dot(v, n);
+ float sDotN = 0.0;
+ float sDotH = 0.0;
+ float att = 1.0;
+
+ if (lights[lightIndex].type != TYPE_DIRECTIONAL) {
+ // Point and Spot lights
+ vec3 sUnnormalized = vec3(lights[lightIndex].position) - wPosition;
+ s = normalize(sUnnormalized);
+
+ // Calculate the attenuation factor
+ sDotN = dot(s, n);
+ if (sDotN > 0.0) {
+ if (lights[lightIndex].constantAttenuation != 0.0
+ || lights[lightIndex].linearAttenuation != 0.0
+ || lights[lightIndex].quadraticAttenuation != 0.0) {
+ float dist = length(sUnnormalized);
+ att = 1.0 / (lights[lightIndex].constantAttenuation +
+ lights[lightIndex].linearAttenuation * dist +
+ lights[lightIndex].quadraticAttenuation * dist * dist);
+ }
+
+ // The light direction is in world space already
+ if (lights[lightIndex].type == TYPE_SPOT) {
+ // Check if fragment is inside or outside of the spot light cone
+ if (degrees(acos(dot(-s, lights[lightIndex].direction))) > lights[lightIndex].cutOffAngle)
+ sDotN = 0.0;
+ }
+ }
+ } else {
+ // Directional lights
+ // The light direction is in world space already
+ s = normalize(-lights[lightIndex].direction);
+ sDotN = dot(s, n);
+ }
+
+ h = normalize(s + v);
+ sDotH = dot(s, h);
+
+ // Calculate diffuse component
+ vec3 diffuseColor = (1.0 - metalness) * baseColor * lights[lightIndex].color;
+ vec3 diffuse = diffuseColor * max(sDotN, 0.0) / 3.14159;
+
+ // Calculate specular component
+ vec3 dielectricColor = vec3(0.04);
+ vec3 F0 = mix(dielectricColor, baseColor, metalness);
+ vec3 specularFactor = vec3(0.0);
+ if (sDotN > 0.0) {
+ specularFactor = specularModel(F0, sDotH, sDotN, vDotN, n, h);
+ specularFactor *= normalDistribution(n, h, alpha);
+ }
+ vec3 specularColor = lights[lightIndex].color;
+ vec3 specular = specularColor * specularFactor;
+
+ // Blend between diffuse and specular to conserver energy
+ vec3 color = att * lights[lightIndex].intensity * (specular + diffuse * (vec3(1.0) - specular));
+
+ // Reduce by ambient occlusion amount
+ color *= ambientOcclusion;
+
+ return color;
+}
+
+vec3 pbrIblModel(const in vec3 wNormal,
+ const in vec3 wView,
+ const in vec3 baseColor,
+ const in float metalness,
+ const in float alpha,
+ const in float ambientOcclusion)
+{
+ // Calculate reflection direction of view vector about surface normal
+ // vector in world space. This is used in the fragment shader to sample
+ // from the environment textures for a light source. This is equivalent
+ // to the l vector for punctual light sources. Armed with this, calculate
+ // the usual factors needed
+ vec3 n = wNormal;
+ vec3 l = reflect(-wView, n);
+ vec3 v = wView;
+ vec3 h = normalize(l + v);
+ float vDotN = dot(v, n);
+ float lDotN = dot(l, n);
+ float lDotH = dot(l, h);
+
+ // Calculate diffuse component
+ vec3 diffuseColor = (1.0 - metalness) * baseColor;
+ vec3 diffuse = diffuseColor * texture(envLight_irradiance, l).rgb;
+
+ // Calculate specular component
+ vec3 dielectricColor = vec3(0.04);
+ vec3 F0 = mix(dielectricColor, baseColor, metalness);
+ vec3 specularFactor = specularModel(F0, lDotH, lDotN, vDotN, n, h);
+
+ float lod = alphaToMipLevel(alpha);
+//#define DEBUG_SPECULAR_LODS
+#ifdef DEBUG_SPECULAR_LODS
+ if (lod > 7.0)
+ return vec3(1.0, 0.0, 0.0);
+ else if (lod > 6.0)
+ return vec3(1.0, 0.333, 0.0);
+ else if (lod > 5.0)
+ return vec3(1.0, 1.0, 0.0);
+ else if (lod > 4.0)
+ return vec3(0.666, 1.0, 0.0);
+ else if (lod > 3.0)
+ return vec3(0.0, 1.0, 0.666);
+ else if (lod > 2.0)
+ return vec3(0.0, 0.666, 1.0);
+ else if (lod > 1.0)
+ return vec3(0.0, 0.0, 1.0);
+ else if (lod > 0.0)
+ return vec3(1.0, 0.0, 1.0);
+#endif
+ vec3 specularSkyColor = textureLod(envLight_specular, l, lod).rgb;
+ vec3 specular = specularSkyColor * specularFactor;
+
+ // Blend between diffuse and specular to conserve energy
+ vec3 color = specular + diffuse * (vec3(1.0) - specularFactor);
+
+ // Reduce by ambient occlusion amount
+ color *= ambientOcclusion;
+
+ return color;
+}
+
+vec3 toneMap(const in vec3 c)
+{
+ return c / (c + vec3(1.0));
+}
+
+vec3 gammaCorrect(const in vec3 color)
+{
+ return pow(color, vec3(1.0 / gamma));
+}
+
+vec4 metalRoughFunction(const in vec4 baseColor,
+ const in float metalness,
+ const in float roughness,
+ const in float ambientOcclusion,
+ const in vec3 worldPosition,
+ const in vec3 worldView,
+ const in vec3 worldNormal)
+{
+ vec3 cLinear = vec3(0.0);
+
+ // Remap roughness for a perceptually more linear correspondence
+ float alpha = remapRoughness(roughness);
+
+ for (int i = 0; i < envLightCount; ++i) {
+ cLinear += pbrIblModel(worldNormal,
+ worldView,
+ baseColor.rgb,
+ metalness,
+ alpha,
+ ambientOcclusion);
+ }
+
+ for (int i = 0; i < lightCount; ++i) {
+ cLinear += pbrModel(i,
+ worldPosition,
+ worldNormal,
+ worldView,
+ baseColor.rgb,
+ metalness,
+ alpha,
+ ambientOcclusion);
+ }
+
+ // Apply exposure correction
+ cLinear *= pow(2.0, exposure);
+
+ // Apply simple (Reinhard) tonemap transform to get into LDR range [0, 1]
+ vec3 cToneMapped = toneMap(cLinear);
+
+ // Apply gamma correction prior to display
+ vec3 cGamma = gammaCorrect(cToneMapped);
+
+ return vec4(cGamma, 1.0);
+}
diff --git a/src/extras/shaders/rhi/morphphong.vert b/src/extras/shaders/rhi/morphphong.vert
new file mode 100644
index 000000000..7a8bdd097
--- /dev/null
+++ b/src/extras/shaders/rhi/morphphong.vert
@@ -0,0 +1,34 @@
+#version 150 core
+
+in vec3 vertexPosition;
+in vec3 vertexNormal;
+in vec3 vertexPositionTarget;
+in vec3 vertexNormalTarget;
+
+out vec3 worldPosition;
+out vec3 worldNormal;
+
+uniform mat4 modelMatrix;
+uniform mat3 modelNormalMatrix;
+uniform mat4 modelViewProjection;
+uniform float interpolator;
+
+void main()
+{
+ vec3 morphPos;
+ vec3 morphNormal;
+ if (interpolator > 0.0) {
+ // normalized
+ morphPos = mix(vertexPosition, vertexPositionTarget, interpolator);
+ morphNormal = normalize(mix(vertexNormal, vertexNormalTarget, interpolator));
+ } else {
+ // relative
+ morphPos = vertexPosition + vertexPositionTarget * abs(interpolator);
+ morphNormal = normalize(vertexNormal + vertexNormalTarget * abs(interpolator));
+ }
+
+ worldNormal = normalize( modelNormalMatrix * morphNormal );
+ worldPosition = vec3( modelMatrix * vec4( morphPos, 1.0 ) );
+
+ gl_Position = modelViewProjection * vec4( morphPos, 1.0 );
+}
diff --git a/src/extras/shaders/rhi/pervertexcolor.frag b/src/extras/shaders/rhi/pervertexcolor.frag
new file mode 100644
index 000000000..40fc066d6
--- /dev/null
+++ b/src/extras/shaders/rhi/pervertexcolor.frag
@@ -0,0 +1,17 @@
+#version 150 core
+
+in vec3 worldPosition;
+in vec3 worldNormal;
+in vec4 color;
+
+out vec4 fragColor;
+
+uniform vec3 eyePosition;
+
+#pragma include phong.inc.frag
+
+void main()
+{
+ vec3 worldView = normalize(eyePosition - worldPosition);
+ fragColor = phongFunction(color, color, vec4(0.0), 0.0, worldPosition, worldView, worldNormal);
+}
diff --git a/src/extras/shaders/rhi/pervertexcolor.vert b/src/extras/shaders/rhi/pervertexcolor.vert
new file mode 100644
index 000000000..1d721e945
--- /dev/null
+++ b/src/extras/shaders/rhi/pervertexcolor.vert
@@ -0,0 +1,22 @@
+#version 150 core
+
+in vec3 vertexPosition;
+in vec3 vertexNormal;
+in vec4 vertexColor;
+
+out vec3 worldPosition;
+out vec3 worldNormal;
+out vec4 color;
+
+uniform mat4 modelMatrix;
+uniform mat3 modelNormalMatrix;
+uniform mat4 mvp;
+
+void main()
+{
+ worldNormal = normalize( modelNormalMatrix * vertexNormal );
+ worldPosition = vec3( modelMatrix * vec4( vertexPosition, 1.0 ) );
+ color = vertexColor;
+
+ gl_Position = mvp * vec4( vertexPosition, 1.0 );
+}
diff --git a/src/extras/shaders/rhi/phong.inc.frag b/src/extras/shaders/rhi/phong.inc.frag
new file mode 100644
index 000000000..47a6ecd4a
--- /dev/null
+++ b/src/extras/shaders/rhi/phong.inc.frag
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#pragma include light.inc.frag
+
+void adsModel(const in vec3 worldPos,
+ const in vec3 worldNormal,
+ const in vec3 worldView,
+ const in float shininess,
+ out vec3 diffuseColor,
+ out vec3 specularColor)
+{
+ diffuseColor = vec3(0.0);
+ specularColor = vec3(0.0);
+
+ // We perform all work in world space
+ vec3 n = normalize(worldNormal);
+ vec3 s = vec3(0.0);
+
+ for (int i = 0; i < lightCount; ++i) {
+ float att = 1.0;
+ float sDotN = 0.0;
+
+ if (lights[i].type != TYPE_DIRECTIONAL) {
+ // Point and Spot lights
+
+ // Light position is already in world space
+ vec3 sUnnormalized = lights[i].position - worldPos;
+ s = normalize(sUnnormalized); // Light direction
+
+ // Calculate the attenuation factor
+ sDotN = dot(s, n);
+ if (sDotN > 0.0) {
+ if (lights[i].constantAttenuation != 0.0
+ || lights[i].linearAttenuation != 0.0
+ || lights[i].quadraticAttenuation != 0.0) {
+ float dist = length(sUnnormalized);
+ att = 1.0 / (lights[i].constantAttenuation +
+ lights[i].linearAttenuation * dist +
+ lights[i].quadraticAttenuation * dist * dist);
+ }
+
+ // The light direction is in world space already
+ if (lights[i].type == TYPE_SPOT) {
+ // Check if fragment is inside or outside of the spot light cone
+ if (degrees(acos(dot(-s, lights[i].direction))) > lights[i].cutOffAngle)
+ sDotN = 0.0;
+ }
+ }
+ } else {
+ // Directional lights
+ // The light direction is in world space already
+ s = normalize(-lights[i].direction);
+ sDotN = dot(s, n);
+ }
+
+ // Calculate the diffuse factor
+ float diffuse = max(sDotN, 0.0);
+
+ // Calculate the specular factor
+ float specular = 0.0;
+ if (diffuse > 0.0 && shininess > 0.0) {
+ float normFactor = (shininess + 2.0) / 2.0;
+ vec3 r = reflect(-s, n); // Reflection direction in world space
+ specular = normFactor * pow(max(dot(r, worldView), 0.0), shininess);
+ }
+
+ // Accumulate the diffuse and specular contributions
+ diffuseColor += att * lights[i].intensity * diffuse * lights[i].color;
+ specularColor += att * lights[i].intensity * specular * lights[i].color;
+ }
+}
+
+vec4 phongFunction(const in vec4 ambient,
+ const in vec4 diffuse,
+ const in vec4 specular,
+ const in float shininess,
+ const in vec3 worldPosition,
+ const in vec3 worldView,
+ const in vec3 worldNormal)
+{
+ // Calculate the lighting model, keeping the specular component separate
+ vec3 diffuseColor, specularColor;
+ adsModel(worldPosition, worldNormal, worldView, shininess, diffuseColor, specularColor);
+
+ // Combine spec with ambient+diffuse for final fragment color
+ vec3 color = (ambient.rgb + diffuseColor) * diffuse.rgb
+ + specularColor * specular.rgb;
+
+ return vec4(color, diffuse.a);
+}
diff --git a/src/extras/shaders/rhi/skybox.frag b/src/extras/shaders/rhi/skybox.frag
new file mode 100644
index 000000000..ceb13b628
--- /dev/null
+++ b/src/extras/shaders/rhi/skybox.frag
@@ -0,0 +1,24 @@
+#version 330
+
+in vec3 texCoord0;
+out vec4 fragColor;
+uniform samplerCube skyboxTexture;
+
+// Gamma correction
+uniform float gamma = 2.2;
+
+uniform float gammaStrength;
+
+vec3 gammaCorrect(const in vec3 color)
+{
+ return pow(color, vec3(1.0 / gamma));
+}
+
+void main()
+{
+ vec4 baseColor = texture(skyboxTexture, texCoord0);
+ vec4 gammaColor = vec4(gammaCorrect(baseColor.rgb), 1.0);
+ // This is an odd way to enable or not gamma correction,
+ // but this is a way to avoid branching until we can generate shaders
+ fragColor = mix(baseColor, gammaColor, gammaStrength);
+}
diff --git a/src/extras/shaders/rhi/skybox.vert b/src/extras/shaders/rhi/skybox.vert
new file mode 100644
index 000000000..cac49893a
--- /dev/null
+++ b/src/extras/shaders/rhi/skybox.vert
@@ -0,0 +1,16 @@
+#version 330
+
+in vec3 vertexPosition;
+out vec3 texCoord0;
+
+uniform mat4 modelMatrix;
+uniform mat4 viewMatrix;
+uniform mat4 projectionMatrix;
+
+void main()
+{
+ texCoord0 = vertexPosition.xyz;
+ // Converting the viewMatrix to a mat3, then back to a mat4
+ // removes the translation component from it
+ gl_Position = vec4(projectionMatrix * mat4(mat3(viewMatrix)) * modelMatrix * vec4(vertexPosition, 1.0)).xyww;
+}
diff --git a/src/extras/shaders/rhi/unlittexture.frag b/src/extras/shaders/rhi/unlittexture.frag
new file mode 100644
index 000000000..8abbeee8f
--- /dev/null
+++ b/src/extras/shaders/rhi/unlittexture.frag
@@ -0,0 +1,13 @@
+#version 150 core
+
+uniform sampler2D diffuseTexture;
+
+in vec3 position;
+in vec2 texCoord;
+
+out vec4 fragColor;
+
+void main()
+{
+ fragColor = texture( diffuseTexture, texCoord );
+}
diff --git a/src/extras/shaders/rhi/unlittexture.vert b/src/extras/shaders/rhi/unlittexture.vert
new file mode 100644
index 000000000..7e245bd7f
--- /dev/null
+++ b/src/extras/shaders/rhi/unlittexture.vert
@@ -0,0 +1,20 @@
+#version 150 core
+
+in vec3 vertexPosition;
+in vec2 vertexTexCoord;
+
+out vec3 position;
+out vec2 texCoord;
+
+uniform mat4 modelView;
+uniform mat4 mvp;
+uniform mat3 texCoordTransform;
+
+void main()
+{
+ vec3 tt = texCoordTransform * vec3(vertexTexCoord, 1.0);
+ texCoord = (tt / tt.z).xy;
+ position = vec3( modelView * vec4( vertexPosition, 1.0 ) );
+
+ gl_Position = mvp * vec4( vertexPosition, 1.0 );
+}
diff --git a/src/plugins/renderers/opengl/graphicshelpers/submissioncontext.cpp b/src/plugins/renderers/opengl/graphicshelpers/submissioncontext.cpp
index 1e2aba0fc..7c1467f6e 100644
--- a/src/plugins/renderers/opengl/graphicshelpers/submissioncontext.cpp
+++ b/src/plugins/renderers/opengl/graphicshelpers/submissioncontext.cpp
@@ -1160,7 +1160,7 @@ void SubmissionContext::setUpdatedTexture(const Qt3DCore::QNodeIdVector &updated
// It will be easier if the QGraphicContext applies the QUniformPack
// than the other way around
-bool SubmissionContext::setParameters(ShaderParameterPack &parameterPack)
+bool SubmissionContext::setParameters(ShaderParameterPack &parameterPack, GLShader *shader)
{
static const int irradianceId = StringToInt::lookupId(QLatin1String("envLight.irradiance"));
static const int specularId = StringToInt::lookupId(QLatin1String("envLight.specular"));
@@ -1225,7 +1225,7 @@ bool SubmissionContext::setParameters(ShaderParameterPack &parameterPack)
}
}
- QOpenGLShaderProgram *shader = activeShader();
+ QOpenGLShaderProgram *glShader = activeShader();
// TO DO: We could cache the binding points somehow and only do the binding when necessary
// for SSBO and UBO
@@ -1239,7 +1239,7 @@ bool SubmissionContext::setParameters(ShaderParameterPack &parameterPack)
// This is currently not required as we are introspecting the bindingIndex
// value from the shaders and not replacing them, making such a call useless
// bindShaderStorageBlock(shader->programId(), b.m_blockIndex, b.m_bindingIndex);
- bindShaderStorageBlock(shader->programId(), b.m_blockIndex, b.m_bindingIndex);
+ bindShaderStorageBlock(glShader->programId(), b.m_blockIndex, b.m_bindingIndex);
// Needed to avoid conflict where the buffer would already
// be bound as a VertexArray
bindGLBuffer(ssbo, GLBuffer::ShaderStorageBuffer);
@@ -1254,7 +1254,7 @@ bool SubmissionContext::setParameters(ShaderParameterPack &parameterPack)
for (const BlockToUBO &b : blockToUBOs) {
Buffer *cpuBuffer = m_renderer->nodeManagers()->bufferManager()->lookupResource(b.m_bufferID);
GLBuffer *ubo = glBufferForRenderBuffer(cpuBuffer);
- bindUniformBlock(shader->programId(), b.m_blockIndex, uboIndex);
+ bindUniformBlock(glShader->programId(), b.m_blockIndex, uboIndex);
// Needed to avoid conflict where the buffer would already
// be bound as a VertexArray
bindGLBuffer(ubo, GLBuffer::UniformBuffer);
@@ -1264,11 +1264,11 @@ bool SubmissionContext::setParameters(ShaderParameterPack &parameterPack)
// Update uniforms in the Default Uniform Block
const PackUniformHash values = parameterPack.uniforms();
- const QVector<ShaderUniform> activeUniforms = parameterPack.submissionUniforms();
+ const QVector<int> &activeUniformsIndices = parameterPack.submissionUniformIndices();
+ const QVector<ShaderUniform> &shaderUniforms = shader->uniforms();
- for (const ShaderUniform &uniform : activeUniforms) {
- // We can use [] as we are sure the the uniform wouldn't
- // be un activeUniforms if there wasn't a matching value
+ for (const int shaderUniformIndex : activeUniformsIndices) {
+ const ShaderUniform &uniform = shaderUniforms[shaderUniformIndex];
const UniformValue &v = values.value(uniform.m_nameId);
// skip invalid textures/images
diff --git a/src/plugins/renderers/opengl/graphicshelpers/submissioncontext_p.h b/src/plugins/renderers/opengl/graphicshelpers/submissioncontext_p.h
index d43cae4f8..6e2ac4e18 100644
--- a/src/plugins/renderers/opengl/graphicshelpers/submissioncontext_p.h
+++ b/src/plugins/renderers/opengl/graphicshelpers/submissioncontext_p.h
@@ -138,7 +138,7 @@ public:
GLBuffer *glBufferForRenderBuffer(Buffer *buf);
// Parameters
- bool setParameters(ShaderParameterPack &parameterPack);
+ bool setParameters(ShaderParameterPack &parameterPack, GLShader *shader);
// RenderState
void setCurrentStateSet(RenderStateSet* ss);
diff --git a/src/plugins/renderers/opengl/jobs/renderviewjobutils.cpp b/src/plugins/renderers/opengl/jobs/renderviewjobutils.cpp
index d4835054b..8774ac368 100644
--- a/src/plugins/renderers/opengl/jobs/renderviewjobutils.cpp
+++ b/src/plugins/renderers/opengl/jobs/renderviewjobutils.cpp
@@ -473,7 +473,10 @@ UniformBlockValueBuilder::~UniformBlockValueBuilder()
{
}
-void UniformBlockValueBuilder::buildActiveUniformNameValueMapHelper(ShaderData *currentShaderData, const QString &blockName, const QString &qmlPropertyName, const QVariant &value)
+void UniformBlockValueBuilder::buildActiveUniformNameValueMapHelper(const ShaderData *currentShaderData,
+ const QString &blockName,
+ const QString &qmlPropertyName,
+ const QVariant &value)
{
// In the end, values are either scalar or a scalar array
// Composed elements (structs, structs array) are simplified into simple scalars
@@ -534,7 +537,9 @@ void UniformBlockValueBuilder::buildActiveUniformNameValueMapHelper(ShaderData *
}
}
-void UniformBlockValueBuilder::buildActiveUniformNameValueMapStructHelper(ShaderData *rShaderData, const QString &blockName, const QString &qmlPropertyName)
+void UniformBlockValueBuilder::buildActiveUniformNameValueMapStructHelper(const ShaderData *rShaderData,
+ const QString &blockName,
+ const QString &qmlPropertyName)
{
const QHash<QString, ShaderData::PropertyValue> &properties = rShaderData->properties();
auto it = properties.begin();
diff --git a/src/plugins/renderers/opengl/jobs/renderviewjobutils_p.h b/src/plugins/renderers/opengl/jobs/renderviewjobutils_p.h
index 5b1413108..f9fab6185 100644
--- a/src/plugins/renderers/opengl/jobs/renderviewjobutils_p.h
+++ b/src/plugins/renderers/opengl/jobs/renderviewjobutils_p.h
@@ -166,11 +166,11 @@ struct Q_AUTOTEST_EXPORT UniformBlockValueBuilder
QT3D_ALIGNED_MALLOC_AND_FREE()
- void buildActiveUniformNameValueMapHelper(ShaderData *currentShaderData,
+ void buildActiveUniformNameValueMapHelper(const ShaderData *currentShaderData,
const QString &blockName,
const QString &qmlPropertyName,
const QVariant &value);
- void buildActiveUniformNameValueMapStructHelper(ShaderData *rShaderData,
+ void buildActiveUniformNameValueMapStructHelper(const ShaderData *rShaderData,
const QString &blockName,
const QString &qmlPropertyName = QString());
diff --git a/src/plugins/renderers/opengl/renderer/glshader.cpp b/src/plugins/renderers/opengl/renderer/glshader.cpp
index 2bc861928..564e78a8e 100644
--- a/src/plugins/renderers/opengl/renderer/glshader.cpp
+++ b/src/plugins/renderers/opengl/renderer/glshader.cpp
@@ -84,11 +84,19 @@ QVector<int> getLightUniformNameIds()
return names;
}
+template<typename Vector>
+bool fastContains(const Vector &v, int value)
+{
+ return std::binary_search(v.cbegin(), v.cend(), value);
+}
+
}
GLShader::GLShader()
: m_isLoaded(false)
, m_graphicsContext(nullptr)
+ , m_parameterPackSize(0)
+ , m_hasActiveVariables(false)
{
m_shaderCode.resize(static_cast<int>(QShaderProgram::Compute) + 1);
}
@@ -141,7 +149,7 @@ QHash<QString, ShaderUniform> GLShader::activeUniformsForUniformBlock(int blockI
return m_uniformBlockIndexToShaderUniforms.value(blockIndex);
}
-ShaderUniformBlock GLShader::uniformBlockForBlockIndex(int blockIndex)
+ShaderUniformBlock GLShader::uniformBlockForBlockIndex(int blockIndex) const noexcept
{
for (int i = 0, m = m_uniformBlocks.size(); i < m; ++i) {
if (m_uniformBlocks[i].m_index == blockIndex) {
@@ -151,7 +159,7 @@ ShaderUniformBlock GLShader::uniformBlockForBlockIndex(int blockIndex)
return ShaderUniformBlock();
}
-ShaderUniformBlock GLShader::uniformBlockForBlockNameId(int blockNameId)
+ShaderUniformBlock GLShader::uniformBlockForBlockNameId(int blockNameId) const noexcept
{
for (int i = 0, m = m_uniformBlocks.size(); i < m; ++i) {
if (m_uniformBlocks[i].m_nameId == blockNameId) {
@@ -161,7 +169,7 @@ ShaderUniformBlock GLShader::uniformBlockForBlockNameId(int blockNameId)
return ShaderUniformBlock();
}
-ShaderUniformBlock GLShader::uniformBlockForBlockName(const QString &blockName)
+ShaderUniformBlock GLShader::uniformBlockForBlockName(const QString &blockName) const noexcept
{
for (int i = 0, m = m_uniformBlocks.size(); i < m; ++i) {
if (m_uniformBlocks[i].m_name == blockName) {
@@ -171,7 +179,7 @@ ShaderUniformBlock GLShader::uniformBlockForBlockName(const QString &blockName)
return ShaderUniformBlock();
}
-ShaderStorageBlock GLShader::storageBlockForBlockIndex(int blockIndex)
+ShaderStorageBlock GLShader::storageBlockForBlockIndex(int blockIndex) const noexcept
{
for (int i = 0, m = m_shaderStorageBlockNames.size(); i < m; ++i) {
if (m_shaderStorageBlocks[i].m_index == blockIndex)
@@ -180,7 +188,7 @@ ShaderStorageBlock GLShader::storageBlockForBlockIndex(int blockIndex)
return ShaderStorageBlock();
}
-ShaderStorageBlock GLShader::storageBlockForBlockNameId(int blockNameId)
+ShaderStorageBlock GLShader::storageBlockForBlockNameId(int blockNameId) const noexcept
{
for (int i = 0, m = m_shaderStorageBlockNames.size(); i < m; ++i) {
if (m_shaderStorageBlocks[i].m_nameId == blockNameId)
@@ -189,7 +197,7 @@ ShaderStorageBlock GLShader::storageBlockForBlockNameId(int blockNameId)
return ShaderStorageBlock();
}
-ShaderStorageBlock GLShader::storageBlockForBlockName(const QString &blockName)
+ShaderStorageBlock GLShader::storageBlockForBlockName(const QString &blockName) const noexcept
{
for (int i = 0, m = m_shaderStorageBlockNames.size(); i < m; ++i) {
if (m_shaderStorageBlocks[i].m_name == blockName)
@@ -198,6 +206,22 @@ ShaderStorageBlock GLShader::storageBlockForBlockName(const QString &blockName)
return ShaderStorageBlock();
}
+GLShader::ParameterKind GLShader::categorizeVariable(int nameId) const noexcept
+{
+ if (fastContains(m_uniformsNamesIds, nameId))
+ return ParameterKind::Uniform;
+ if (fastContains(m_uniformBlockNamesIds, nameId))
+ return ParameterKind::UBO;
+ if (fastContains(m_shaderStorageBlockNamesIds, nameId))
+ return ParameterKind::SSBO;
+ return ParameterKind::Struct;
+}
+
+bool GLShader::hasUniform(int nameId) const noexcept
+{
+ return m_uniformsNamesIds.contains(nameId);
+}
+
void GLShader::prepareUniforms(ShaderParameterPack &pack)
{
const PackUniformHash &values = pack.uniforms();
@@ -205,14 +229,20 @@ void GLShader::prepareUniforms(ShaderParameterPack &pack)
auto it = values.keys.cbegin();
const auto end = values.keys.cend();
+ const int shaderUniformsCount = m_uniforms.size();
+ const auto uIt = m_uniforms.cbegin();
+
while (it != end) {
// Find if there's a uniform with the same name id
- for (const ShaderUniform &uniform : qAsConst(m_uniforms)) {
- if (uniform.m_nameId == *it) {
- pack.setSubmissionUniform(uniform);
- break;
- }
- }
+
+ int i = 0;
+ const int targetNameId = *it;
+ while (i < shaderUniformsCount && (uIt + i)->m_nameId < targetNameId)
+ ++i;
+
+ if (i < shaderUniformsCount && (uIt + i)->m_nameId == targetNameId)
+ pack.setSubmissionUniformIndex(i);
+
++it;
}
}
@@ -223,7 +253,6 @@ void GLShader::setFragOutputs(const QHash<QString, int> &fragOutputs)
QMutexLocker lock(&m_mutex);
m_fragOutputs = fragOutputs;
}
-// updateDNA();
}
const QHash<QString, int> GLShader::fragOutputs() const
@@ -288,6 +317,18 @@ void GLShader::initializeUniforms(const QVector<ShaderUniform> &uniformsDescript
}
}
m_uniformBlockIndexToShaderUniforms.insert(-1, activeUniformsInDefaultBlock);
+
+ m_parameterPackSize += m_standardUniformNamesIds.size() + m_lightUniformsNamesIds.size() + m_uniformsNamesIds.size();
+ m_hasActiveVariables |= (m_parameterPackSize > 0);
+
+ // Sort by ascending order to make contains check faster
+ std::sort(m_uniformsNamesIds.begin(), m_uniformsNamesIds.end());
+ std::sort(m_lightUniformsNamesIds.begin(), m_lightUniformsNamesIds.end());
+ std::sort(m_standardUniformNamesIds.begin(), m_standardUniformNamesIds.end());
+ std::sort(m_uniforms.begin(), m_uniforms.end(),
+ [] (const ShaderUniform &a, const ShaderUniform &b) {
+ return a.m_nameId < b.m_nameId;
+ });
}
void GLShader::initializeAttributes(const QVector<ShaderAttribute> &attributesDescription)
@@ -301,6 +342,7 @@ void GLShader::initializeAttributes(const QVector<ShaderAttribute> &attributesDe
m_attributeNamesIds[i] = m_attributes[i].m_nameId;
qCDebug(Shaders) << "Active Attribute " << attributesDescription[i].m_name;
}
+ m_hasActiveVariables |= (m_attributeNamesIds.size() > 0);
}
void GLShader::initializeUniformBlocks(const QVector<ShaderUniformBlock> &uniformBlockDescription)
@@ -336,6 +378,12 @@ void GLShader::initializeUniformBlocks(const QVector<ShaderUniformBlock> &unifor
}
m_uniformBlockIndexToShaderUniforms.insert(uniformBlockDescription[i].m_index, activeUniformsInBlock);
}
+
+ m_parameterPackSize += m_uniformsNamesIds.size();
+ m_hasActiveVariables |= (m_parameterPackSize > 0);
+
+ // Sort by ascending order to make contains check faster
+ std::sort(m_uniformBlockNamesIds.begin(), m_uniformBlockNamesIds.end());
}
void GLShader::initializeShaderStorageBlocks(const QVector<ShaderStorageBlock> &shaderStorageBlockDescription)
@@ -350,6 +398,12 @@ void GLShader::initializeShaderStorageBlocks(const QVector<ShaderStorageBlock> &
m_shaderStorageBlocks[i].m_nameId =m_shaderStorageBlockNamesIds[i];
qCDebug(Shaders) << "Initializing Shader Storage Block {" << m_shaderStorageBlockNames[i] << "}";
}
+
+ m_parameterPackSize += m_shaderStorageBlockNamesIds.size();
+ m_hasActiveVariables |= (m_parameterPackSize > 0);
+
+ // Sort by ascending order to make contains check faster
+ std::sort(m_shaderStorageBlockNamesIds.begin(), m_shaderStorageBlockNamesIds.end());
}
} // OpenGL
diff --git a/src/plugins/renderers/opengl/renderer/glshader_p.h b/src/plugins/renderers/opengl/renderer/glshader_p.h
index 07d40c724..ae447cd18 100644
--- a/src/plugins/renderers/opengl/renderer/glshader_p.h
+++ b/src/plugins/renderers/opengl/renderer/glshader_p.h
@@ -99,20 +99,32 @@ public:
QVector<QString> uniformBlockNames() const;
QVector<QString> storageBlockNames() const;
- inline QVector<ShaderUniform> uniforms() const { return m_uniforms; }
- inline QVector<ShaderAttribute> attributes() const { return m_attributes; }
- inline QVector<ShaderUniformBlock> uniformBlocks() const { return m_uniformBlocks; }
- inline QVector<ShaderStorageBlock> storageBlocks() const { return m_shaderStorageBlocks; }
+ inline const QVector<ShaderUniform> &uniforms() const { return m_uniforms; }
+ inline const QVector<ShaderAttribute> &attributes() const { return m_attributes; }
+ inline const QVector<ShaderUniformBlock> &uniformBlocks() const { return m_uniformBlocks; }
+ inline const QVector<ShaderStorageBlock> &storageBlocks() const { return m_shaderStorageBlocks; }
QHash<QString, ShaderUniform> activeUniformsForUniformBlock(int blockIndex) const;
- ShaderUniformBlock uniformBlockForBlockIndex(int blockNameId);
- ShaderUniformBlock uniformBlockForBlockNameId(int blockIndex);
- ShaderUniformBlock uniformBlockForBlockName(const QString &blockName);
+ ShaderUniformBlock uniformBlockForBlockIndex(int blockNameId) const noexcept;
+ ShaderUniformBlock uniformBlockForBlockNameId(int blockIndex) const noexcept;
+ ShaderUniformBlock uniformBlockForBlockName(const QString &blockName) const noexcept;
- ShaderStorageBlock storageBlockForBlockIndex(int blockIndex);
- ShaderStorageBlock storageBlockForBlockNameId(int blockNameId);
- ShaderStorageBlock storageBlockForBlockName(const QString &blockName);
+ ShaderStorageBlock storageBlockForBlockIndex(int blockIndex) const noexcept;
+ ShaderStorageBlock storageBlockForBlockNameId(int blockNameId) const noexcept;
+ ShaderStorageBlock storageBlockForBlockName(const QString &blockName) const noexcept;
+
+ enum ParameterKind {
+ Uniform,
+ UBO,
+ SSBO,
+ Struct
+ };
+ ParameterKind categorizeVariable(int nameId) const noexcept;
+
+ bool hasUniform(int nameId) const noexcept;
+ inline bool hasActiveVariables() const noexcept { return m_hasActiveVariables; }
+ inline int parameterPackSize() const noexcept { return m_parameterPackSize; }
QOpenGLShaderProgram *shaderProgram() { return &m_shader; }
@@ -146,6 +158,9 @@ private:
QHash<QString, int> m_fragOutputs;
QVector<QByteArray> m_shaderCode;
+ int m_parameterPackSize;
+ int m_hasActiveVariables;
+
// Private so that only GraphicContext can call it
void initializeUniforms(const QVector<ShaderUniform> &uniformsDescription);
void initializeAttributes(const QVector<ShaderAttribute> &attributesDescription);
diff --git a/src/plugins/renderers/opengl/renderer/renderer.cpp b/src/plugins/renderers/opengl/renderer/renderer.cpp
index 35f1d6bf4..fdcc9fd09 100644
--- a/src/plugins/renderers/opengl/renderer/renderer.cpp
+++ b/src/plugins/renderers/opengl/renderer/renderer.cpp
@@ -995,16 +995,9 @@ void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderView
// so we cannot unset its dirtiness at this point
if (rGeometryRenderer->isDirty())
rGeometryRenderer->unsetDirty();
-
- // Prepare the ShaderParameterPack based on the active uniforms of the shader
- shader->prepareUniforms(command.m_parameterPack);
-
} else if (command.m_type == RenderCommand::Compute) {
GLShader *shader = command.m_glShader;
Q_ASSERT(shader);
-
- // Prepare the ShaderParameterPack based on the active uniforms of the shader
- shader->prepareUniforms(command.m_parameterPack);
}
}
}
@@ -2075,7 +2068,7 @@ void Renderer::performCompute(const RenderView *, RenderCommand *command)
}
{
Profiling::GLTimeRecorder recorder(Profiling::UniformUpdate, activeProfiler());
- m_submissionContext->setParameters(command->m_parameterPack);
+ m_submissionContext->setParameters(command->m_parameterPack, command->m_glShader);
}
{
Profiling::GLTimeRecorder recorder(Profiling::DispatchCompute, activeProfiler());
@@ -2169,7 +2162,7 @@ bool Renderer::executeCommandsSubmission(const RenderView *rv)
{
Profiling::GLTimeRecorder recorder(Profiling::UniformUpdate, activeProfiler());
//// Update program uniforms
- if (!m_submissionContext->setParameters(command.m_parameterPack)) {
+ if (!m_submissionContext->setParameters(command.m_parameterPack, command.m_glShader)) {
allCommandsIssued = false;
// If we have failed to set uniform (e.g unable to bind a texture)
// we won't perform the draw call which could show invalid content
diff --git a/src/plugins/renderers/opengl/renderer/renderview.cpp b/src/plugins/renderers/opengl/renderer/renderview.cpp
index 5757c7851..6707c6c2f 100644
--- a/src/plugins/renderers/opengl/renderer/renderview.cpp
+++ b/src/plugins/renderers/opengl/renderer/renderview.cpp
@@ -148,9 +148,10 @@ static Matrix4x4 getProjectionMatrix(const CameraLens *lens)
}
UniformValue RenderView::standardUniformValue(RenderView::StandardUniform standardUniformType,
- Entity *entity,
- const Matrix4x4 &model) const
+ const Entity *entity) const
{
+ const Matrix4x4 &model = *(entity->worldTransform());
+
switch (standardUniformType) {
case ModelMatrix:
return UniformValue(model);
@@ -925,21 +926,16 @@ void RenderView::setUniformValue(ShaderParameterPack &uniformPack, int nameId, c
}
void RenderView::setStandardUniformValue(ShaderParameterPack &uniformPack,
- int glslNameId,
int nameId,
- Entity *entity,
- const Matrix4x4 &worldTransform) const
+ const Entity *entity) const
{
- uniformPack.setUniform(glslNameId, standardUniformValue(ms_standardUniformSetters[nameId], entity, worldTransform));
+ uniformPack.setUniform(nameId, standardUniformValue(ms_standardUniformSetters[nameId], entity));
}
void RenderView::setUniformBlockValue(ShaderParameterPack &uniformPack,
- GLShader *shader,
const ShaderUniformBlock &block,
const UniformValue &value) const
{
- Q_UNUSED(shader)
-
if (value.valueType() == UniformValue::NodeId) {
Buffer *buffer = nullptr;
@@ -955,11 +951,9 @@ void RenderView::setUniformBlockValue(ShaderParameterPack &uniformPack,
}
void RenderView::setShaderStorageValue(ShaderParameterPack &uniformPack,
- GLShader *shader,
const ShaderStorageBlock &block,
const UniformValue &value) const
{
- Q_UNUSED(shader)
if (value.valueType() == UniformValue::NodeId) {
Buffer *buffer = nullptr;
if ((buffer = m_manager->bufferManager()->lookupResource(*value.constData<Qt3DCore::QNodeId>())) != nullptr) {
@@ -973,7 +967,10 @@ void RenderView::setShaderStorageValue(ShaderParameterPack &uniformPack,
}
}
-void RenderView::setDefaultUniformBlockShaderDataValue(ShaderParameterPack &uniformPack, GLShader *shader, ShaderData *shaderData, const QString &structName) const
+void RenderView::setDefaultUniformBlockShaderDataValue(ShaderParameterPack &uniformPack,
+ const GLShader *shader,
+ const ShaderData *shaderData,
+ const QString &structName) const
{
UniformBlockValueBuilder *builder = m_localData.localData();
builder->activeUniformNamesToValue.clear();
@@ -997,6 +994,42 @@ void RenderView::setDefaultUniformBlockShaderDataValue(ShaderParameterPack &unif
}
}
+void RenderView::applyParameter(const Parameter *param,
+ RenderCommand *command,
+ const GLShader *shader) const noexcept
+{
+ const int nameId = param->nameId();
+ const UniformValue &uniformValue = param->uniformValue();
+ const GLShader::ParameterKind kind = shader->categorizeVariable(nameId);
+
+ switch (kind) {
+ case GLShader::Uniform: {
+ setUniformValue(command->m_parameterPack, nameId, uniformValue);
+ break;
+ }
+ case GLShader::UBO: {
+ setUniformBlockValue(command->m_parameterPack, shader->uniformBlockForBlockNameId(nameId), uniformValue);
+ break;
+ }
+ case GLShader::SSBO: {
+ setShaderStorageValue(command->m_parameterPack, shader->storageBlockForBlockNameId(nameId), uniformValue);
+ break;
+ }
+ case GLShader::Struct: {
+ ShaderData *shaderData = nullptr;
+ if (uniformValue.valueType() == UniformValue::NodeId &&
+ (shaderData = m_manager->shaderDataManager()->lookupResource(*uniformValue.constData<Qt3DCore::QNodeId>())) != nullptr) {
+ // Try to check if we have a struct or array matching a QShaderData parameter
+ setDefaultUniformBlockShaderDataValue(command->m_parameterPack, shader, shaderData, StringToInt::lookupString(nameId));
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+
void RenderView::setShaderAndUniforms(RenderCommand *command,
ParameterInfoList &parameters,
Entity *entity,
@@ -1019,12 +1052,6 @@ void RenderView::setShaderAndUniforms(RenderCommand *command,
// Builds the QUniformPack, sets shader standard uniforms and store attributes name / glname bindings
// If a parameter is defined and not found in the bindings it is assumed to be a binding of Uniform type with the glsl name
// equals to the parameter name
- const QVector<int> &uniformNamesIds = shader->uniformsNamesIds();
- const QVector<int> &standardUniformNamesIds = shader->standardUniformNameIds();
- const QVector<int> &lightUniformNamesIds = shader->lightUniformsNamesIds();
- const QVector<int> &uniformBlockNamesIds = shader->uniformBlockNamesIds();
- const QVector<int> &shaderStorageBlockNamesIds = shader->storageBlockNamesIds();
- const QVector<int> &attributeNamesIds = shader->attributeNamesIds();
// Set fragData Name and index
// Later on we might want to relink the shader if attachments have changed
@@ -1042,56 +1069,32 @@ void RenderView::setShaderAndUniforms(RenderCommand *command,
}
// Set default attributes
- command->m_activeAttributes = attributeNamesIds;
+ command->m_activeAttributes = shader->attributeNamesIds();
// At this point we know whether the command is a valid draw command or not
// We still need to process the uniforms as the command could be a compute command
command->m_isValid = !command->m_activeAttributes.empty();
- if (!uniformNamesIds.isEmpty() || !standardUniformNamesIds.isEmpty() ||
- !attributeNamesIds.isEmpty() || !lightUniformNamesIds.isEmpty() ||
- !shaderStorageBlockNamesIds.isEmpty() || command->m_isValid) {
-
- // Set default standard uniforms without bindings
- const Matrix4x4 worldTransform = *(entity->worldTransform());
+ if (shader->hasActiveVariables()) {
// Reserve amount of uniforms we are going to need
- command->m_parameterPack.reserve(uniformNamesIds.size() + standardUniformNamesIds.size() + lightUniformNamesIds.size() + uniformBlockNamesIds.size() + shaderStorageBlockNamesIds.size());
+ command->m_parameterPack.reserve(shader->parameterPackSize());
+ const QVector<int> &standardUniformNamesIds = shader->standardUniformNameIds();
for (const int uniformNameId : standardUniformNamesIds)
- setStandardUniformValue(command->m_parameterPack, uniformNameId, uniformNameId, entity, worldTransform);
-
- // Parameters remaining could be
- // -> uniform scalar / vector
- // -> uniform struct / arrays
- // -> uniform block / array (4.3)
- // -> ssbo block / array (4.3)
+ setStandardUniformValue(command->m_parameterPack, uniformNameId, entity);
ParameterInfoList::const_iterator it = parameters.cbegin();
const ParameterInfoList::const_iterator parametersEnd = parameters.cend();
while (it != parametersEnd) {
- Parameter *param = m_manager->data<Parameter, ParameterManager>(it->handle);
- const UniformValue &uniformValue = param->uniformValue();
- if (uniformNamesIds.contains(it->nameId)) { // Parameter is a regular uniform
- setUniformValue(command->m_parameterPack, it->nameId, uniformValue);
- } else if (uniformBlockNamesIds.indexOf(it->nameId) != -1) { // Parameter is a uniform block
- setUniformBlockValue(command->m_parameterPack, shader, shader->uniformBlockForBlockNameId(it->nameId), uniformValue);
- } else if (shaderStorageBlockNamesIds.indexOf(it->nameId) != -1) { // Parameters is a SSBO
- setShaderStorageValue(command->m_parameterPack, shader, shader->storageBlockForBlockNameId(it->nameId), uniformValue);
- } else { // Parameter is a struct
- ShaderData *shaderData = nullptr;
- if (uniformValue.valueType() == UniformValue::NodeId &&
- (shaderData = m_manager->shaderDataManager()->lookupResource(*uniformValue.constData<Qt3DCore::QNodeId>())) != nullptr) {
- // Try to check if we have a struct or array matching a QShaderData parameter
- setDefaultUniformBlockShaderDataValue(command->m_parameterPack, shader, shaderData, StringToInt::lookupString(it->nameId));
- }
- // Otherwise: param unused by current shader
- }
+ const Parameter *param = m_manager->data<Parameter, ParameterManager>(it->handle);
+ applyParameter(param, command, shader);
++it;
}
// Lights
+ const QVector<int> &lightUniformNamesIds = shader->lightUniformsNamesIds();
if (!lightUniformNamesIds.empty()) {
int lightIdx = 0;
for (const LightSource &lightSource : activeLightSources) {
@@ -1174,6 +1177,9 @@ void RenderView::setShaderAndUniforms(RenderCommand *command,
}
setUniformValue(command->m_parameterPack, StringToInt::lookupId(QStringLiteral("envLightCount")), envLightCount);
}
+
+ // Prepare the ShaderParameterPack based on the active uniforms of the shader
+ shader->prepareUniforms(command->m_parameterPack);
}
}
diff --git a/src/plugins/renderers/opengl/renderer/renderview_p.h b/src/plugins/renderers/opengl/renderer/renderview_p.h
index c9e69d507..85dafe3fd 100644
--- a/src/plugins/renderers/opengl/renderer/renderview_p.h
+++ b/src/plugins/renderers/opengl/renderer/renderview_p.h
@@ -371,27 +371,25 @@ private:
static StandardUniformsNameToTypeHash initializeStandardUniformSetters();
UniformValue standardUniformValue(StandardUniform standardUniformType,
- Entity *entity,
- const Matrix4x4 &model) const;
+ const Entity *entity) const;
void setUniformValue(ShaderParameterPack &uniformPack, int nameId, const UniformValue &value) const;
void setStandardUniformValue(ShaderParameterPack &uniformPack,
- int glslNameId,
int nameId,
- Entity *entity,
- const Matrix4x4 &worldTransform) const;
+ const Entity *entity) const;
void setUniformBlockValue(ShaderParameterPack &uniformPack,
- GLShader *shader,
const ShaderUniformBlock &block,
const UniformValue &value) const;
void setShaderStorageValue(ShaderParameterPack &uniformPack,
- GLShader *shader,
const ShaderStorageBlock &block,
const UniformValue &value) const;
void setDefaultUniformBlockShaderDataValue(ShaderParameterPack &uniformPack,
- GLShader *shader,
- ShaderData *shaderData,
+ const GLShader *shader,
+ const ShaderData *shaderData,
const QString &structName) const;
+ void applyParameter(const Parameter *param,
+ RenderCommand *command,
+ const GLShader *shader) const noexcept;
};
} // namespace OpenGL
diff --git a/src/plugins/renderers/opengl/renderer/renderviewbuilder.cpp b/src/plugins/renderers/opengl/renderer/renderviewbuilder.cpp
index 35c200239..0667c21d3 100644
--- a/src/plugins/renderers/opengl/renderer/renderviewbuilder.cpp
+++ b/src/plugins/renderers/opengl/renderer/renderviewbuilder.cpp
@@ -350,7 +350,7 @@ public:
// Split among the number of command builders
// The idealPacketSize is at least 100 entities per worker
const int idealPacketSize = std::min(std::max(100, filteredCommandData->size() / RenderViewBuilder::defaultJobCount()), filteredCommandData->size());
- const int m = findIdealNumberOfWorkers(filteredCommandData->size(), idealPacketSize);
+ const int m = findIdealNumberOfWorkers(filteredCommandData->size(), idealPacketSize, m_renderViewCommandUpdaterJobs.size());
for (int i = 0; i < m; ++i) {
const RenderViewCommandUpdaterJobPtr renderViewCommandBuilder = m_renderViewCommandUpdaterJobs.at(i);
diff --git a/src/plugins/renderers/opengl/renderer/shaderparameterpack.cpp b/src/plugins/renderers/opengl/renderer/shaderparameterpack.cpp
index 082220349..467ac34c5 100644
--- a/src/plugins/renderers/opengl/renderer/shaderparameterpack.cpp
+++ b/src/plugins/renderers/opengl/renderer/shaderparameterpack.cpp
@@ -63,6 +63,7 @@ ShaderParameterPack::~ShaderParameterPack()
void ShaderParameterPack::reserve(int uniformCount)
{
m_uniforms.reserve(uniformCount);
+ m_submissionUniformIndices.reserve(uniformCount);
}
void ShaderParameterPack::setUniform(const int glslNameId, const UniformValue &val)
@@ -107,9 +108,9 @@ void ShaderParameterPack::setShaderStorageBuffer(BlockToSSBO blockToSSBO)
m_shaderStorageBuffers.push_back(std::move(blockToSSBO));
}
-void ShaderParameterPack::setSubmissionUniform(const ShaderUniform &uniform)
+void ShaderParameterPack::setSubmissionUniformIndex(const int uniformIdx)
{
- m_submissionUniforms.push_back(uniform);
+ m_submissionUniformIndices.push_back(uniformIdx);
}
} // namespace OpenGL
diff --git a/src/plugins/renderers/opengl/renderer/shaderparameterpack_p.h b/src/plugins/renderers/opengl/renderer/shaderparameterpack_p.h
index 10c4da5d4..2ed80ef2a 100644
--- a/src/plugins/renderers/opengl/renderer/shaderparameterpack_p.h
+++ b/src/plugins/renderers/opengl/renderer/shaderparameterpack_p.h
@@ -157,7 +157,7 @@ public:
void setUniformBuffer(BlockToUBO blockToUBO);
void setShaderStorageBuffer(BlockToSSBO blockToSSBO);
- void setSubmissionUniform(const ShaderUniform &uniform);
+ void setSubmissionUniformIndex(const int shaderUniformIndex);
inline PackUniformHash &uniforms() { return m_uniforms; }
inline const PackUniformHash &uniforms() const { return m_uniforms; }
@@ -203,7 +203,7 @@ public:
inline QVector<NamedResource> images() const { return m_images; }
inline QVector<BlockToUBO> uniformBuffers() const { return m_uniformBuffers; }
inline QVector<BlockToSSBO> shaderStorageBuffers() const { return m_shaderStorageBuffers; }
- inline QVector<ShaderUniform> submissionUniforms() const { return m_submissionUniforms; }
+ inline QVector<int> submissionUniformIndices() const { return m_submissionUniformIndices; }
private:
PackUniformHash m_uniforms;
@@ -211,7 +211,7 @@ private:
QVector<NamedResource> m_images;
QVector<BlockToUBO> m_uniformBuffers;
QVector<BlockToSSBO> m_shaderStorageBuffers;
- QVector<ShaderUniform> m_submissionUniforms;
+ QVector<int> m_submissionUniformIndices;
friend class RenderView;
};
diff --git a/src/plugins/renderers/rhi/renderer/renderview.cpp b/src/plugins/renderers/rhi/renderer/renderview.cpp
index 1898a0346..df6345896 100644
--- a/src/plugins/renderers/rhi/renderer/renderview.cpp
+++ b/src/plugins/renderers/rhi/renderer/renderview.cpp
@@ -107,12 +107,6 @@ int LIGHT_COLOR_NAMES[MAX_LIGHTS];
int LIGHT_INTENSITY_NAMES[MAX_LIGHTS];
QString LIGHT_STRUCT_NAMES[MAX_LIGHTS];
-int LIGHT_POSITION_UNROLL_NAMES[MAX_LIGHTS];
-int LIGHT_TYPE_UNROLL_NAMES[MAX_LIGHTS];
-int LIGHT_COLOR_UNROLL_NAMES[MAX_LIGHTS];
-int LIGHT_INTENSITY_UNROLL_NAMES[MAX_LIGHTS];
-QString LIGHT_STRUCT_UNROLL_NAMES[MAX_LIGHTS];
-
std::atomic_bool wasInitialized{};
} // anonymous namespace
@@ -161,11 +155,30 @@ static QRectF resolveViewport(const QRectF &fractionalViewport, const QSize &sur
fractionalViewport.height() * surfaceSize.height());
}
-static Matrix4x4 getProjectionMatrix(const CameraLens *lens)
+static Matrix4x4 getProjectionMatrix(const CameraLens *lens, bool yIsUp)
{
if (!lens)
qWarning() << "[Qt3D Renderer] No Camera Lens found. Add a CameraSelector to your Frame Graph or make sure that no entities will be rendered.";
- return lens ? lens->projection() : Matrix4x4();
+ if (lens)
+ {
+ if (yIsUp)
+ {
+ // OpenGL
+ return lens->projection();
+ }
+ else
+ {
+ // Others. Note : this could likely be optimized...
+ auto p = lens->projection();
+ Matrix4x4 rev{0, 0, 0, 0, 0, - 2* p.m22(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ p += rev;
+ return p;
+ }
+ }
+ else
+ {
+ return Matrix4x4();
+ }
}
RenderView::RenderView()
@@ -202,12 +215,6 @@ RenderView::RenderView()
LIGHT_TYPE_NAMES[i] = StringToInt::lookupId(LIGHT_STRUCT_NAMES[i] + LIGHT_TYPE_NAME);
LIGHT_COLOR_NAMES[i] = StringToInt::lookupId(LIGHT_STRUCT_NAMES[i] + LIGHT_COLOR_NAME);
LIGHT_INTENSITY_NAMES[i] = StringToInt::lookupId(LIGHT_STRUCT_NAMES[i] + LIGHT_INTENSITY_NAME);
-
- LIGHT_STRUCT_UNROLL_NAMES[i] = QLatin1String("light_") + QLatin1Char(char('0' + i));
- LIGHT_POSITION_UNROLL_NAMES[i] = StringToInt::lookupId(LIGHT_STRUCT_UNROLL_NAMES[i] + LIGHT_POSITION_NAME);
- LIGHT_TYPE_UNROLL_NAMES[i] = StringToInt::lookupId(LIGHT_STRUCT_UNROLL_NAMES[i] + LIGHT_TYPE_NAME);
- LIGHT_COLOR_UNROLL_NAMES[i] = StringToInt::lookupId(LIGHT_STRUCT_UNROLL_NAMES[i] + LIGHT_COLOR_NAME);
- LIGHT_INTENSITY_UNROLL_NAMES[i] = StringToInt::lookupId(LIGHT_STRUCT_UNROLL_NAMES[i] + LIGHT_INTENSITY_NAME);
}
}
}
@@ -363,6 +370,7 @@ struct SubRangeSorter<QSortPolicy::Texture>
{
static void sortSubRange(CommandIt begin, const CommandIt end)
{
+#ifndef Q_OS_WIN
std::stable_sort(begin, end, [] (const RenderCommand &a, const RenderCommand &b) {
QVector<ShaderParameterPack::NamedResource> texturesA = a.m_parameterPack.textures();
QVector<ShaderParameterPack::NamedResource> texturesB = b.m_parameterPack.textures();
@@ -381,6 +389,7 @@ struct SubRangeSorter<QSortPolicy::Texture>
return identicalTextureCount < originalTextureASize;
});
+#endif
}
};
@@ -583,6 +592,9 @@ EntityRenderCommandData RenderView::buildDrawRenderCommands(const QVector<Entity
HGeometry geometryHandle = m_manager->geometryManager()->lookupHandle(geometryRenderer->geometryId());
Geometry *geometry = m_manager->geometryManager()->data(geometryHandle);
+ if (geometry == nullptr)
+ continue;
+
// 1 RenderCommand per RenderPass pass on an Entity with a Mesh
for (const RenderPassParameterData &passData : renderPassData) {
// Add the RenderPass Parameters
@@ -765,9 +777,10 @@ void RenderView::updateRenderCommand(EntityRenderCommandData *renderCommandData,
m_localData.setLocalData(builder);
// Update RenderViewUBO (Qt3D standard uniforms)
- const Matrix4x4 projectionMatrix = getProjectionMatrix(m_data.m_renderCameraLens);
+ const bool yIsUp = m_renderer->submissionContext()->rhi()->isYUpInFramebuffer();
+ const Matrix4x4 projectionMatrix = getProjectionMatrix(m_data.m_renderCameraLens, yIsUp);
const Matrix4x4 inverseViewMatrix = m_data.m_viewMatrix.inverted();
- const Matrix4x4 inversedProjectionMatrix = getProjectionMatrix(m_data.m_renderCameraLens).inverted();
+ const Matrix4x4 inversedProjectionMatrix = projectionMatrix.inverted();
const Matrix4x4 viewProjectionMatrix = (projectionMatrix * m_data.m_viewMatrix);
const Matrix4x4 inversedViewProjectionMatrix = viewProjectionMatrix.inverted();
{
@@ -1099,11 +1112,6 @@ void RenderView::setShaderAndUniforms(RenderCommand *command,
setUniformValue(command->m_parameterPack, LIGHT_COLOR_NAMES[lightIdx], Vector3D(1.0f, 1.0f, 1.0f));
setUniformValue(command->m_parameterPack, LIGHT_INTENSITY_NAMES[lightIdx], 0.5f);
- setUniformValue(command->m_parameterPack, LIGHT_POSITION_UNROLL_NAMES[lightIdx], worldPos);
- setUniformValue(command->m_parameterPack, LIGHT_TYPE_UNROLL_NAMES[lightIdx], int(QAbstractLight::PointLight));
- setUniformValue(command->m_parameterPack, LIGHT_COLOR_UNROLL_NAMES[lightIdx], Vector3D(1.0f, 1.0f, 1.0f));
- setUniformValue(command->m_parameterPack, LIGHT_INTENSITY_UNROLL_NAMES[lightIdx], 0.5f);
-
// There is no risk in doing that even if multithreaded
// since we are sure that a shaderData is unique for a given light
@@ -1113,7 +1121,6 @@ void RenderView::setShaderAndUniforms(RenderCommand *command,
shaderData->updateWorldTransform(*worldTransform);
setDefaultUniformBlockShaderDataValue(command->m_parameterPack, shader, shaderData, LIGHT_STRUCT_NAMES[lightIdx]);
- setDefaultUniformBlockShaderDataValue(command->m_parameterPack, shader, shaderData, LIGHT_STRUCT_UNROLL_NAMES[lightIdx]);
++lightIdx;
}
}
@@ -1128,11 +1135,6 @@ void RenderView::setShaderAndUniforms(RenderCommand *command,
setUniformValue(command->m_parameterPack, LIGHT_TYPE_NAMES[0], int(QAbstractLight::PointLight));
setUniformValue(command->m_parameterPack, LIGHT_COLOR_NAMES[0], Vector3D(1.0f, 1.0f, 1.0f));
setUniformValue(command->m_parameterPack, LIGHT_INTENSITY_NAMES[0], 0.5f);
-
- setUniformValue(command->m_parameterPack, LIGHT_POSITION_UNROLL_NAMES[0], Vector3D(10.0f, 10.0f, 0.0f));
- setUniformValue(command->m_parameterPack, LIGHT_TYPE_UNROLL_NAMES[0], int(QAbstractLight::PointLight));
- setUniformValue(command->m_parameterPack, LIGHT_COLOR_UNROLL_NAMES[0], Vector3D(1.0f, 1.0f, 1.0f));
- setUniformValue(command->m_parameterPack, LIGHT_INTENSITY_UNROLL_NAMES[0], 0.5f);
}
// Environment Light
diff --git a/src/quick3d/imports/scene3d/importsscene3d.pro b/src/quick3d/imports/scene3d/importsscene3d.pro
index 6bf4f5d91..969b7449b 100644
--- a/src/quick3d/imports/scene3d/importsscene3d.pro
+++ b/src/quick3d/imports/scene3d/importsscene3d.pro
@@ -14,7 +14,6 @@ HEADERS += \
qtquickscene3dplugin.h \
scene3dlogging_p.h \
scene3ditem_p.h \
- scene3dcleaner_p.h \
scene3drenderer_p.h \
scene3dsgnode_p.h \
scene3dsgmaterialshader_p.h \
@@ -25,7 +24,6 @@ SOURCES += \
qtquickscene3dplugin.cpp \
scene3ditem.cpp \
scene3dlogging.cpp \
- scene3dcleaner.cpp \
scene3drenderer.cpp \
scene3dsgnode.cpp \
scene3dsgmaterialshader.cpp \
diff --git a/src/quick3d/imports/scene3d/scene3dcleaner.cpp b/src/quick3d/imports/scene3d/scene3dcleaner.cpp
deleted file mode 100644
index ec371410d..000000000
--- a/src/quick3d/imports/scene3d/scene3dcleaner.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "scene3dcleaner_p.h"
-
-#include <Qt3DCore/qaspectengine.h>
-#include <QtCore/qthread.h>
-
-#include <scene3dlogging_p.h>
-#include <scene3drenderer_p.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace Qt3DRender {
-
-Scene3DCleaner::Scene3DCleaner(QObject *parent)
- : QObject(parent)
- , m_renderer(nullptr)
-{
-}
-
-Scene3DCleaner::~Scene3DCleaner()
-{
- qCDebug(Scene3D) << Q_FUNC_INFO << QThread::currentThread();
-}
-
-void Scene3DCleaner::cleanup()
-{
- Q_ASSERT(m_renderer);
- delete m_renderer->m_aspectEngine; // also deletes m_renderer->m_renderAspect
- m_renderer->m_aspectEngine = nullptr;
- m_renderer->m_renderAspect = nullptr;
- m_renderer->deleteLater();
- deleteLater();
-}
-
-} // namespace Qt3DRender
-
-QT_END_NAMESPACE
diff --git a/src/quick3d/imports/scene3d/scene3dcleaner_p.h b/src/quick3d/imports/scene3d/scene3dcleaner_p.h
deleted file mode 100644
index a246cbde7..000000000
--- a/src/quick3d/imports/scene3d/scene3dcleaner_p.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
-
-#ifndef QT3DRENDER_SCENE3DCLEANER_P_H
-#define QT3DRENDER_SCENE3DCLEANER_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/QObject>
-
-QT_BEGIN_NAMESPACE
-
-namespace Qt3DRender {
-
-class Scene3DRenderer;
-
-class Scene3DCleaner : public QObject
-{
- Q_OBJECT
-public:
- explicit Scene3DCleaner(QObject *parent = 0);
- ~Scene3DCleaner();
-
- void setRenderer(Scene3DRenderer *renderer) { m_renderer = renderer; }
-
-public Q_SLOTS:
- void cleanup();
-
-private:
- Scene3DRenderer *m_renderer;
-};
-
-} // namespace Qt3DRender
-
-QT_END_NAMESPACE
-
-#endif // QT3DRENDER_SCENE3DCLEANER_H
diff --git a/src/quick3d/imports/scene3d/scene3ditem.cpp b/src/quick3d/imports/scene3d/scene3ditem.cpp
index 37310a071..36569f0f7 100644
--- a/src/quick3d/imports/scene3d/scene3ditem.cpp
+++ b/src/quick3d/imports/scene3d/scene3ditem.cpp
@@ -68,7 +68,6 @@
#include <Qt3DRender/private/qrendersurfaceselector_p.h>
#include <Qt3DRender/private/qrenderaspect_p.h>
#include <Qt3DRender/private/rendersettings_p.h>
-#include <scene3dcleaner_p.h>
#include <scene3dlogging_p.h>
#include <scene3drenderer_p.h>
#include <scene3dsgnode_p.h>
@@ -150,8 +149,8 @@ Scene3DItem::Scene3DItem(QQuickItem *parent)
, m_viewHolderFG(nullptr)
, m_aspectEngine(new Qt3DCore::QAspectEngine())
, m_renderAspect(nullptr)
+ , m_aspectToDelete(nullptr)
, m_renderer(nullptr)
- , m_rendererCleaner(new Scene3DCleaner())
, m_multisample(true)
, m_dirty(true)
, m_dirtyViews(false)
@@ -180,6 +179,8 @@ Scene3DItem::~Scene3DItem()
// When the window is closed, it first destroys all of its children. At
// this point, Scene3DItem is destroyed but the Renderer, AspectEngine and
// Scene3DSGNode still exist and will perform their cleanup on their own.
+ m_aspectEngine->deleteLater();
+ m_renderer->deleteLater();
}
/*!
@@ -205,18 +206,11 @@ QStringList Scene3DItem::aspects() const
*/
Qt3DCore::QEntity *Scene3DItem::entity() const
{
- return m_entity;
+ return m_entity.data();
}
-void Scene3DItem::setAspects(const QStringList &aspects)
+void Scene3DItem::applyAspects()
{
- if (!m_aspects.isEmpty()) {
- qCWarning(Scene3D) << "Aspects already set on the Scene3D, ignoring";
- return;
- }
-
- m_aspects = aspects;
-
// Aspects are owned by the aspect engine
for (const QString &aspect : qAsConst(m_aspects)) {
if (aspect == QLatin1String("render")) // This one is hardwired anyway
@@ -247,16 +241,27 @@ void Scene3DItem::setAspects(const QStringList &aspects)
}
m_aspectEngine->registerAspect(aspect);
}
+}
+
+void Scene3DItem::setAspects(const QStringList &aspects)
+{
+ if (!m_aspects.isEmpty()) {
+ qWarning() << "Aspects already set on the Scene3D, ignoring";
+ return;
+ }
+
+ m_aspects = aspects;
+ applyAspects();
emit aspectsChanged();
}
void Scene3DItem::setEntity(Qt3DCore::QEntity *entity)
{
- if (entity == m_entity)
+ if (entity == m_entity.data())
return;
- m_entity = entity;
+ m_entity.reset(entity);
emit entityChanged();
}
@@ -397,14 +402,21 @@ void Scene3DItem::removeView(Scene3DView *view)
void Scene3DItem::applyRootEntityChange()
{
- if (m_aspectEngine->rootEntity() != m_entity) {
- m_aspectEngine->setRootEntity(Qt3DCore::QEntityPtr(m_entity));
+ if (m_aspectEngine->rootEntity() != m_entity.data()) {
+ m_aspectEngine->setRootEntity(m_entity);
+
+ /* If we changed window, the old aspect engine must be deleted only after we have set
+ the root entity for the new one so that it doesn't delete the root node. */
+ if (m_aspectToDelete) {
+ delete m_aspectToDelete;
+ m_aspectToDelete = nullptr;
+ }
// Set the render surface
if (!m_entity)
return;
- setWindowSurface(m_entity);
+ setWindowSurface(entity());
if (m_cameraAspectRatioMode == AutomaticAspectRatio) {
// Set aspect ratio of first camera to match the window
@@ -480,6 +492,8 @@ void Scene3DItem::onBeforeSync()
// if the Scene3D item is not visible
if (!isVisible() && dontRenderWhenHidden)
return;
+ if (m_renderer->m_resetRequested)
+ return;
Q_ASSERT(QThread::currentThread() == thread());
@@ -495,7 +509,7 @@ void Scene3DItem::onBeforeSync()
// Make renderer aware of any Scene3DView we are dealing with
if (m_dirtyViews) {
// Scene3DViews checks
- if (m_entity != m_viewHolderEntity) {
+ if (entity() != m_viewHolderEntity) {
qCWarning(Scene3D) << "Scene3DView is not supported if the Scene3D entity property has been set";
}
if (!usesFBO) {
@@ -543,6 +557,20 @@ void Scene3DItem::requestUpdate()
}
}
+void Scene3DItem::updateWindowSurface()
+{
+ if (!m_entity || !m_dummySurface)
+ return;
+ Qt3DRender::QRenderSurfaceSelector *surfaceSelector =
+ Qt3DRender::QRenderSurfaceSelectorPrivate::find(entity());
+ if (surfaceSelector) {
+ if (QWindow *rw = QQuickRenderControl::renderWindowFor(this->window())) {
+ m_dummySurface->deleteLater();
+ createDummySurface(rw, surfaceSelector);
+ }
+ }
+}
+
void Scene3DItem::setWindowSurface(QObject *rootObject)
{
Qt3DRender::QRenderSurfaceSelector *surfaceSelector = Qt3DRender::QRenderSurfaceSelectorPrivate::find(rootObject);
@@ -553,20 +581,25 @@ void Scene3DItem::setWindowSurface(QObject *rootObject)
// We may not have a real, exposed QQuickWindow when the Quick rendering
// is redirected via QQuickRenderControl (f.ex. QQuickWidget).
if (QWindow *rw = QQuickRenderControl::renderWindowFor(this->window())) {
- // rw is the top-level window that is backed by a native window. Do
- // not use that though since we must not clash with e.g. the widget
- // backingstore compositor in the gui thread.
- m_dummySurface = new QOffscreenSurface;
- m_dummySurface->setParent(qGuiApp); // parent to something suitably long-living
- m_dummySurface->setFormat(rw->format());
- m_dummySurface->setScreen(rw->screen());
- m_dummySurface->create();
- surfaceSelector->setSurface(m_dummySurface);
+ createDummySurface(rw, surfaceSelector);
} else {
surfaceSelector->setSurface(this->window());
}
}
}
+
+void Scene3DItem::createDummySurface(QWindow *rw, Qt3DRender::QRenderSurfaceSelector *surfaceSelector)
+{
+ // rw is the top-level window that is backed by a native window. Do
+ // not use that though since we must not clash with e.g. the widget
+ // backingstore compositor in the gui thread.
+ m_dummySurface = new QOffscreenSurface;
+ m_dummySurface->setParent(qGuiApp); // parent to something suitably long-living
+ m_dummySurface->setFormat(rw->format());
+ m_dummySurface->setScreen(rw->screen());
+ m_dummySurface->create();
+ surfaceSelector->setSurface(m_dummySurface);
+}
/*!
\qmlmethod void Scene3D::setItemAreaAndDevicePixelRatio(size area, real devicePixelRatio)
@@ -574,7 +607,8 @@ void Scene3DItem::setWindowSurface(QObject *rootObject)
*/
void Scene3DItem::setItemAreaAndDevicePixelRatio(QSize area, qreal devicePixelRatio)
{
- Qt3DRender::QRenderSurfaceSelector *surfaceSelector = Qt3DRender::QRenderSurfaceSelectorPrivate::find(m_entity);
+ Qt3DRender::QRenderSurfaceSelector *surfaceSelector
+ = Qt3DRender::QRenderSurfaceSelectorPrivate::find(entity());
if (surfaceSelector) {
surfaceSelector->setExternalRenderTargetSize(area);
surfaceSelector->setSurfacePixelRatio(devicePixelRatio);
@@ -664,6 +698,22 @@ void Scene3DItem::setMultisample(bool enable)
QSGNode *Scene3DItem::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData *)
{
+ // m_resetRequested is set to true by Scene3DRenderer::shutdown()
+ if (m_renderer && m_renderer->m_resetRequested) {
+ qCWarning(Scene3D) << "Renderer for Scene3DItem has requested a reset due to the item "
+ "moving to another window";
+ QObject::disconnect(m_windowConnection);
+ m_aspectEngine->unregisterAspect(m_renderAspect); // Deletes the renderAspect
+ m_renderAspect = nullptr;
+ m_aspectToDelete = m_aspectEngine;
+ m_aspectEngine = new Qt3DCore::QAspectEngine();
+ m_aspectEngine->setRunMode(Qt3DCore::QAspectEngine::Manual);
+ applyAspects();
+ // Needs to belong in the same thread as the item which is the same as the original
+ // QAspectEngine
+ m_aspectEngine->moveToThread(thread());
+ m_renderer->m_resetRequested = false;
+ }
// If the render aspect wasn't created yet, do so now
if (m_renderAspect == nullptr) {
m_renderAspect = new QRenderAspect(QRenderAspect::Synchronous);
@@ -674,16 +724,24 @@ QSGNode *Scene3DItem::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNode
// Before Synchronizing is in the SG Thread, we want beforeSync to be triggered
// in the context of the main thread
- QObject::connect(window(), &QQuickWindow::afterAnimating,
- this, &Scene3DItem::onBeforeSync, Qt::DirectConnection);
+ m_windowConnection = QObject::connect(window(), &QQuickWindow::afterAnimating,
+ this, &Scene3DItem::onBeforeSync, Qt::DirectConnection);
auto renderAspectPriv = static_cast<QRenderAspectPrivate*>(QRenderAspectPrivate::get(m_renderAspect));
QObject::connect(renderAspectPriv->m_aspectManager->changeArbiter(), &Qt3DCore::QChangeArbiter::receivedChange,
this, [this] { m_dirty = true; }, Qt::DirectConnection);
}
if (m_renderer == nullptr) {
- m_renderer = new Scene3DRenderer(this, m_aspectEngine, m_renderAspect);
- m_renderer->setCleanerHelper(m_rendererCleaner);
+ m_renderer = new Scene3DRenderer();
+ m_renderer->init(this, m_aspectEngine, m_renderAspect);
+ } else if (m_renderer->renderAspect() != m_renderAspect) {
+ // If the renderer's renderAspect is not equal to the aspect used
+ // by the item, then it means that we have created a new one due to
+ // the fact that shutdown() was called on the renderer previously.
+ // This is a typical situation when the window the item is in has
+ // moved from one screen to another.
+ updateWindowSurface();
+ m_renderer->init(this, m_aspectEngine, m_renderAspect);
}
const bool usesFBO = m_compositingMode == FBO;
const bool hasScene3DViews = !m_views.empty();
diff --git a/src/quick3d/imports/scene3d/scene3ditem_p.h b/src/quick3d/imports/scene3d/scene3ditem_p.h
index e46bb20af..0beaf94c0 100644
--- a/src/quick3d/imports/scene3d/scene3ditem_p.h
+++ b/src/quick3d/imports/scene3d/scene3ditem_p.h
@@ -71,6 +71,7 @@ class Scene3DRenderer;
class Scene3DCleaner;
class Scene3DView;
class QFrameGraphNode;
+class QRenderSurfaceSelector;
class Scene3DItem : public QQuickItem
{
@@ -138,16 +139,20 @@ private:
void updateCameraAspectRatio();
void mousePressEvent(QMouseEvent *event) override;
bool needsRender();
+ void updateWindowSurface();
+ void createDummySurface(QWindow *window, QRenderSurfaceSelector *surfaceSelector);
+ void applyAspects();
QStringList m_aspects;
- Qt3DCore::QEntity *m_entity;
+ // Store as shared pointer so that aspect engine doesn't delete it.
+ QSharedPointer<Qt3DCore::QEntity> m_entity;
Qt3DCore::QEntity *m_viewHolderEntity;
Qt3DRender::QFrameGraphNode *m_viewHolderFG;
Qt3DCore::QAspectEngine *m_aspectEngine;
+ Qt3DCore::QAspectEngine *m_aspectToDelete;
QRenderAspect *m_renderAspect;
Scene3DRenderer *m_renderer;
- Scene3DCleaner *m_rendererCleaner;
bool m_multisample;
bool m_dirty;
@@ -160,6 +165,7 @@ private:
CompositingMode m_compositingMode;
QOffscreenSurface *m_dummySurface;
QVector<Scene3DView *> m_views;
+ QMetaObject::Connection m_windowConnection;
};
} // Qt3DRender
diff --git a/src/quick3d/imports/scene3d/scene3drenderer.cpp b/src/quick3d/imports/scene3d/scene3drenderer.cpp
index 71cf6c240..96514b32d 100644
--- a/src/quick3d/imports/scene3d/scene3drenderer.cpp
+++ b/src/quick3d/imports/scene3d/scene3drenderer.cpp
@@ -53,7 +53,6 @@
#include <Qt3DCore/private/qchangearbiter_p.h>
#include <Qt3DCore/private/qservicelocator_p.h>
-#include <scene3dcleaner_p.h>
#include <scene3ditem_p.h>
#include <scene3dlogging_p.h>
#include <scene3dsgnode_p.h>
@@ -144,16 +143,15 @@ private:
signal of the window is not called. Therefore the cleanup method is invoked
to properly destroy the aspect engine.
*/
-Scene3DRenderer::Scene3DRenderer(Scene3DItem *item, Qt3DCore::QAspectEngine *aspectEngine, QRenderAspect *renderAspect)
+Scene3DRenderer::Scene3DRenderer()
: QObject()
- , m_item(item)
- , m_aspectEngine(aspectEngine)
- , m_renderAspect(renderAspect)
+ , m_item(nullptr)
+ , m_aspectEngine(nullptr)
+ , m_renderAspect(nullptr)
, m_multisampledFBO(nullptr)
, m_finalFBO(nullptr)
, m_texture(nullptr)
, m_node(nullptr)
- , m_cleaner(nullptr)
, m_window(nullptr)
, m_multisample(false) // this value is not used, will be synced from the Scene3DItem instead
, m_lastMultisample(false)
@@ -165,6 +163,17 @@ Scene3DRenderer::Scene3DRenderer(Scene3DItem *item, Qt3DCore::QAspectEngine *asp
, m_allowRendering(0)
, m_compositingMode(Scene3DItem::FBO)
{
+}
+
+void Scene3DRenderer::init(Scene3DItem *item, Qt3DCore::QAspectEngine *aspectEngine,
+ QRenderAspect *renderAspect)
+{
+ m_item = item;
+ m_window = m_item->window();
+ m_aspectEngine = aspectEngine;
+ m_renderAspect = renderAspect;
+ m_needsShutdown = true;
+
Q_CHECK_PTR(m_item);
Q_CHECK_PTR(m_item->window());
@@ -215,21 +224,14 @@ void Scene3DRenderer::scheduleRootEntityChange()
QMetaObject::invokeMethod(m_item, "applyRootEntityChange", Qt::QueuedConnection);
}
-void Scene3DRenderer::setCleanerHelper(Scene3DCleaner *cleaner)
-{
- m_cleaner = cleaner;
- if (m_cleaner) {
- // Window closed case
- QObject::connect(m_item->window(), &QQuickWindow::destroyed, m_cleaner, &Scene3DCleaner::cleanup);
- m_cleaner->setRenderer(this);
- }
-}
-
// Executed in the QtQuick render thread (which may even be the gui/main with QQuickWidget / RenderControl).
void Scene3DRenderer::shutdown()
{
qCDebug(Scene3D) << Q_FUNC_INFO << QThread::currentThread();
+ // In case the same item is rendered on another window reset it
+ m_resetRequested = true;
+
// Set to null so that subsequent calls to render
// would return early
m_item = nullptr;
@@ -243,8 +245,13 @@ void Scene3DRenderer::shutdown()
// Shutdown the Renderer Aspect while the OpenGL context
// is still valid
- if (m_renderAspect)
+ if (m_renderAspect) {
static_cast<QRenderAspectPrivate*>(QRenderAspectPrivate::get(m_renderAspect))->renderShutdown();
+ m_renderAspect = nullptr;
+ }
+ m_aspectEngine = nullptr;
+ m_finalFBO.reset();
+ m_multisampledFBO.reset();
}
// QtQuick render thread (which may also be the gui/main thread with QQuickWidget / RenderControl)
@@ -254,7 +261,6 @@ void Scene3DRenderer::onSceneGraphInvalidated()
if (m_needsShutdown) {
m_needsShutdown = false;
shutdown();
- QMetaObject::invokeMethod(m_cleaner, "cleanup");
}
}
@@ -265,7 +271,6 @@ void Scene3DRenderer::onWindowChanged(QQuickWindow *w)
if (m_needsShutdown) {
m_needsShutdown = false;
shutdown();
- QMetaObject::invokeMethod(m_cleaner, "cleanup");
}
}
}
@@ -288,6 +293,7 @@ void Scene3DRenderer::beforeSynchronize()
// SceneGraph update for nothing
if (m_skipFrame) {
m_skipFrame = false;
+ ContextSaver saver;
static_cast<QRenderAspectPrivate*>(QRenderAspectPrivate::get(m_renderAspect))->renderSynchronous(false);
return;
}
diff --git a/src/quick3d/imports/scene3d/scene3drenderer_p.h b/src/quick3d/imports/scene3d/scene3drenderer_p.h
index 08a2c60a3..5674f21c2 100644
--- a/src/quick3d/imports/scene3d/scene3drenderer_p.h
+++ b/src/quick3d/imports/scene3d/scene3drenderer_p.h
@@ -78,9 +78,7 @@ class Scene3DRenderer : public QObject
{
Q_OBJECT
public:
- Scene3DRenderer(Scene3DItem *item,
- Qt3DCore::QAspectEngine *aspectEngine,
- QRenderAspect *renderAspect);
+ Scene3DRenderer();
~Scene3DRenderer();
void setSGNode(Scene3DSGNode *node);
@@ -89,7 +87,12 @@ public:
void setCompositingMode(Scene3DItem::CompositingMode mode);
void setSkipFrame(bool skip);
void setScene3DViews(const QVector<Scene3DView *> views);
+ void init(Scene3DItem *item, Qt3DCore::QAspectEngine *aspectEngine, QRenderAspect *renderAspect);
+ QRenderAspect *renderAspect() const
+ {
+ return m_renderAspect;
+ }
public Q_SLOTS:
void render();
void shutdown();
@@ -103,13 +106,12 @@ private:
void scheduleRootEntityChange();
Scene3DItem *m_item; // Will be released by the QQuickWindow/QML Engine
- Qt3DCore::QAspectEngine *m_aspectEngine; // Will be released by the Scene3DRendererCleaner
+ Qt3DCore::QAspectEngine *m_aspectEngine; // Will be released by the Scene3DItem
QRenderAspect *m_renderAspect; // Will be released by the aspectEngine
QScopedPointer<QOpenGLFramebufferObject> m_multisampledFBO;
QScopedPointer<QOpenGLFramebufferObject> m_finalFBO;
QScopedPointer<QSGTexture> m_texture;
Scene3DSGNode *m_node; // Will be released by the QtQuick SceneGraph
- Scene3DCleaner *m_cleaner;
QQuickWindow *m_window;
QMutex m_windowMutex;
QSize m_lastSize;
@@ -123,8 +125,9 @@ private:
QSemaphore m_allowRendering;
Scene3DItem::CompositingMode m_compositingMode;
QVector<Scene3DView *> m_views;
+ bool m_resetRequested = false;
- friend class Scene3DCleaner;
+ friend class Scene3DItem;
};
} // namespace Qt3DRender
diff --git a/src/render/framegraph/qlayerfilter.cpp b/src/render/framegraph/qlayerfilter.cpp
index 8bad46f5d..5557687ce 100644
--- a/src/render/framegraph/qlayerfilter.cpp
+++ b/src/render/framegraph/qlayerfilter.cpp
@@ -214,8 +214,9 @@ void QLayerFilter::removeLayer(QLayer *layer)
{
Q_ASSERT(layer);
Q_D(QLayerFilter);
+ if (!d->m_layers.removeOne(layer))
+ return;
d->updateNode(layer, "layer", Qt3DCore::PropertyValueRemoved);
- d->m_layers.removeOne(layer);
// Remove bookkeeping connection
d->unregisterDestructionHelper(layer);
}
diff --git a/src/render/framegraph/qrenderpassfilter.cpp b/src/render/framegraph/qrenderpassfilter.cpp
index 952657eb6..34462ebdf 100644
--- a/src/render/framegraph/qrenderpassfilter.cpp
+++ b/src/render/framegraph/qrenderpassfilter.cpp
@@ -151,8 +151,9 @@ void QRenderPassFilter::removeMatch(QFilterKey *filterKey)
Q_ASSERT(filterKey);
Q_D(QRenderPassFilter);
+ if (!d->m_matchList.removeOne(filterKey))
+ return;
d->updateNode(filterKey, "match", Qt3DCore::PropertyValueRemoved);
- d->m_matchList.removeOne(filterKey);
// Remove bookkeeping connection
d->unregisterDestructionHelper(filterKey);
}
@@ -189,8 +190,9 @@ void QRenderPassFilter::removeParameter(QParameter *parameter)
Q_ASSERT(parameter);
Q_D(QRenderPassFilter);
+ if (!d->m_parameters.removeOne(parameter))
+ return;
d->updateNode(parameter, "parameter", Qt3DCore::PropertyValueRemoved);
- d->m_parameters.removeOne(parameter);
// Remove bookkeeping connection
d->unregisterDestructionHelper(parameter);
}
diff --git a/src/render/framegraph/qrenderstateset.cpp b/src/render/framegraph/qrenderstateset.cpp
index 5341b3c7d..ac82954c8 100644
--- a/src/render/framegraph/qrenderstateset.cpp
+++ b/src/render/framegraph/qrenderstateset.cpp
@@ -203,8 +203,9 @@ void QRenderStateSet::removeRenderState(QRenderState *state)
Q_ASSERT(state);
Q_D(QRenderStateSet);
+ if (!d->m_renderStates.removeOne(state))
+ return;
d->updateNode(state, "renderState", Qt3DCore::PropertyValueRemoved);
- d->m_renderStates.removeOne(state);
// Remove bookkeeping connection
d->unregisterDestructionHelper(state);
}
diff --git a/src/render/framegraph/qtechniquefilter.cpp b/src/render/framegraph/qtechniquefilter.cpp
index c22e83381..5377e1297 100644
--- a/src/render/framegraph/qtechniquefilter.cpp
+++ b/src/render/framegraph/qtechniquefilter.cpp
@@ -155,8 +155,9 @@ void QTechniqueFilter::removeMatch(QFilterKey *filterKey)
{
Q_ASSERT(filterKey);
Q_D(QTechniqueFilter);
+ if (!d->m_matchList.removeOne(filterKey))
+ return;
d->updateNode(filterKey, "matchAll", Qt3DCore::PropertyValueRemoved);
- d->m_matchList.removeOne(filterKey);
// Remove bookkeeping connection
d->unregisterDestructionHelper(filterKey);
}
@@ -192,8 +193,9 @@ void QTechniqueFilter::removeParameter(QParameter *parameter)
{
Q_ASSERT(parameter);
Q_D(QTechniqueFilter);
+ if (!d->m_parameters.removeOne(parameter))
+ return;
d->updateNode(parameter, "parameter", Qt3DCore::PropertyValueRemoved);
- d->m_parameters.removeOne(parameter);
// Remove bookkeeping connection
d->unregisterDestructionHelper(parameter);
}
diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp
index ec9417c00..d9b53cb8d 100644
--- a/src/render/frontend/qrenderaspect.cpp
+++ b/src/render/frontend/qrenderaspect.cpp
@@ -763,9 +763,10 @@ QVariant QRenderAspect::executeCommand(const QStringList &args)
if (args.front() == QLatin1String("framepaths"))
return Qt3DRender::QFrameGraphNodePrivate::get(fg)->dumpFrameGraphPaths().join(QLatin1String("\n"));
if (args.front() == QLatin1String("filterstates")) {
- auto res = Qt3DRender::QFrameGraphNodePrivate::get(fg)->dumpFrameGraphFilterState().join(QLatin1String("\n"));
- res += dumpSGFilterState(d->m_nodeManagers->techniqueManager(),
- d->m_renderer->contextInfo(), d->m_root).join(QLatin1String("\n"));
+ const auto activeContextInfo = d->m_renderer->contextInfo();
+ QString res = QLatin1String("Active Graphics API: ") + activeContextInfo->toString() + QLatin1String("\n");
+ res += QLatin1String("Render Views:\n ") + Qt3DRender::QFrameGraphNodePrivate::get(fg)->dumpFrameGraphFilterState().join(QLatin1String("\n ")) + QLatin1String("\n");
+ res += QLatin1String("Scene Graph:\n ") + dumpSGFilterState(d->m_nodeManagers->techniqueManager(), activeContextInfo, d->m_root).join(QLatin1String("\n "));
return res;
}
}
diff --git a/src/render/frontend/qrendertarget.cpp b/src/render/frontend/qrendertarget.cpp
index 57eecd795..7e0403c13 100644
--- a/src/render/frontend/qrendertarget.cpp
+++ b/src/render/frontend/qrendertarget.cpp
@@ -134,8 +134,9 @@ void QRenderTarget::removeOutput(QRenderTargetOutput *output)
{
Q_D(QRenderTarget);
+ if (!d->m_outputs.removeOne(output))
+ return;
d->updateNode(output, "output", Qt3DCore::PropertyValueRemoved);
- d->m_outputs.removeOne(output);
// Remove bookkeeping connection
d->unregisterDestructionHelper(output);
}
diff --git a/src/render/geometry/qgeometry.cpp b/src/render/geometry/qgeometry.cpp
index 48f054bce..ac22f2db1 100644
--- a/src/render/geometry/qgeometry.cpp
+++ b/src/render/geometry/qgeometry.cpp
@@ -206,7 +206,8 @@ void QGeometry::removeAttribute(QAttribute *attribute)
{
Q_ASSERT(attribute);
Q_D(QGeometry);
- d->m_attributes.removeOne(attribute);
+ if (!d->m_attributes.removeOne(attribute))
+ return;
// Remove bookkeeping connection
d->unregisterDestructionHelper(attribute);
d->updateNode(attribute, "attribute", Qt3DCore::PropertyValueRemoved);
diff --git a/src/render/materialsystem/prototypes/default.json b/src/render/materialsystem/prototypes/default.json
index 597de41c3..6a25477e0 100644
--- a/src/render/materialsystem/prototypes/default.json
+++ b/src/render/materialsystem/prototypes/default.json
@@ -32,6 +32,15 @@
},
"substitution": "$type $value = $name;",
"headerSnippets": [ "$qualifier $type $name;" ]
+ },
+ {
+ "format": {
+ "api": "RHI",
+ "major": 4,
+ "minor": 5
+ },
+ "substitution": "$type $value = $name;",
+ "headerSnippets": [ "add-input $qualifier $type $name" ]
}
]
},
@@ -102,6 +111,15 @@
},
"substitution": "vec4 $color = texture($name, $coord);",
"headerSnippets": [ "uniform sampler2D $name;" ]
+ },
+ {
+ "format": {
+ "api": "RHI",
+ "major": 4,
+ "minor": 5
+ },
+ "substitution": "vec4 $color = texture($name, $coord);",
+ "headerSnippets": [ "add-sampler sampler2D $name" ]
}
]
},
@@ -135,6 +153,15 @@
},
"substitution": "fragColor = $fragColor;",
"headerSnippets": [ "out vec4 fragColor;" ]
+ },
+ {
+ "format": {
+ "api": "RHI",
+ "major": 4,
+ "minor": 5
+ },
+ "substitution": "fragColor = $fragColor;",
+ "headerSnippets": [ "layout(location = 0) out vec4 fragColor;" ]
}
]
},
@@ -160,6 +187,15 @@
},
"substitution": "vec3 $eyePosition = eyePosition;",
"headerSnippets": [ "uniform vec3 eyePosition;" ]
+ },
+ {
+ "format": {
+ "api": "RHI",
+ "major": 4,
+ "minor": 5
+ },
+ "substitution": "vec3 $eyePosition = eyePosition;",
+ "headerSnippets": [ "add-uniform vec3 eyePosition" ]
}
]
},
@@ -185,6 +221,15 @@
},
"substitution": "float $time = time;",
"headerSnippets": [ "uniform float time;" ]
+ },
+ {
+ "format": {
+ "api": "RHI",
+ "major": 4,
+ "minor": 5
+ },
+ "substitution": "float $time = time;",
+ "headerSnippets": [ "add-uniform float time" ]
}
]
},
@@ -419,6 +464,15 @@
},
"substitution": "mat3 $matrix = calcWorldSpaceToTangentSpaceMatrix($worldNormal, $worldTangent);",
"headerSnippets": [ "#pragma include :/shaders/gl3/coordinatesystems.inc" ]
+ },
+ {
+ "format": {
+ "api": "RHI",
+ "major": 4,
+ "minor": 5
+ },
+ "substitution": "mat3 $matrix = calcWorldSpaceToTangentSpaceMatrix($worldNormal, $worldTangent);",
+ "headerSnippets": [ "#pragma include :/shaders/rhi/coordinatesystems.inc" ]
}
]
},
@@ -453,6 +507,15 @@
},
"substitution": "vec4 $outputColor = phongFunction($ambient, $diffuse, $specular, $shininess, $worldPosition, $worldView, $worldNormal);",
"headerSnippets": [ "#pragma include :/shaders/gl3/phong.inc.frag" ]
+ },
+ {
+ "format": {
+ "api": "RHI",
+ "major": 4,
+ "minor": 5
+ },
+ "substitution": "vec4 $outputColor = phongFunction($ambient, $diffuse, $specular, $shininess, $worldPosition, $worldView, $worldNormal);",
+ "headerSnippets": [ "#pragma include :/shaders/rhi/phong.inc.frag" ]
}
]
},
@@ -487,6 +550,15 @@
},
"substitution": "vec4 $outputColor = metalRoughFunction($baseColor, $metalness, $roughness, $ambientOcclusion, $worldPosition, $worldView, $worldNormal);",
"headerSnippets": [ "#pragma include :/shaders/gl3/metalrough.inc.frag" ]
+ },
+ {
+ "format": {
+ "api": "RHI",
+ "major": 4,
+ "minor": 5
+ },
+ "substitution": "vec4 $outputColor = metalRoughFunction($baseColor, $metalness, $roughness, $ambientOcclusion, $worldPosition, $worldView, $worldNormal);",
+ "headerSnippets": [ "#pragma include :/shaders/rhi/metalrough.inc.frag" ]
}
]
},
diff --git a/src/render/materialsystem/qeffect.cpp b/src/render/materialsystem/qeffect.cpp
index 8637a92d4..9f4b3db94 100644
--- a/src/render/materialsystem/qeffect.cpp
+++ b/src/render/materialsystem/qeffect.cpp
@@ -203,7 +203,8 @@ void QEffect::removeParameter(QParameter *parameter)
{
Q_D(QEffect);
- d->m_parameters.removeOne(parameter);
+ if (!d->m_parameters.removeOne(parameter))
+ return;
// Remove bookkeeping connection
d->unregisterDestructionHelper(parameter);
d->updateNode(parameter, "parameter", Qt3DCore::PropertyValueRemoved);
@@ -248,9 +249,9 @@ void QEffect::addTechnique(QTechnique *t)
void QEffect::removeTechnique(QTechnique *t)
{
Q_D(QEffect);
- if (t)
- d->updateNode(t, "technique", Qt3DCore::PropertyValueRemoved);
- d->m_techniques.removeOne(t);
+ if (!d->m_techniques.removeOne(t))
+ return;
+ d->updateNode(t, "technique", Qt3DCore::PropertyValueRemoved);
// Remove bookkeeping connection
d->unregisterDestructionHelper(t);
}
diff --git a/src/render/materialsystem/qgraphicsapifilter.cpp b/src/render/materialsystem/qgraphicsapifilter.cpp
index 9b5557930..e8b93de6e 100644
--- a/src/render/materialsystem/qgraphicsapifilter.cpp
+++ b/src/render/materialsystem/qgraphicsapifilter.cpp
@@ -53,6 +53,28 @@ GraphicsApiFilterData::GraphicsApiFilterData()
, m_major(0)
{}
+QString GraphicsApiFilterData::toString() const
+{
+ QLatin1String api;
+ switch (m_api) {
+ case QGraphicsApiFilter::OpenGL: api = QLatin1String("OpenGL"); break;
+ case QGraphicsApiFilter::OpenGLES: api = QLatin1String("OpenGL"); break;
+ case QGraphicsApiFilter::Vulkan: api = QLatin1String("Vulkan"); break;
+ case QGraphicsApiFilter::DirectX: api = QLatin1String("DirectX"); break;
+ case QGraphicsApiFilter::RHI: api = QLatin1String("RHI"); break;
+ default: Q_UNREACHABLE();
+ }
+
+ QLatin1String profile;
+ switch (m_profile) {
+ case QGraphicsApiFilter::CoreProfile: profile = QLatin1String(" (Core Profile)"); break;
+ case QGraphicsApiFilter::CompatibilityProfile: profile = QLatin1String(" (Compatibility Profile)"); break;
+ default: break;
+ }
+
+ return QString(QLatin1String("%1 %2.%3%4 (%5)").arg(api, QString::number(m_major), QString::number(m_minor), profile, m_vendor));
+}
+
bool GraphicsApiFilterData::operator ==(const GraphicsApiFilterData &other) const
{
// Check API
diff --git a/src/render/materialsystem/qgraphicsapifilter_p.h b/src/render/materialsystem/qgraphicsapifilter_p.h
index 435451c27..52c489785 100644
--- a/src/render/materialsystem/qgraphicsapifilter_p.h
+++ b/src/render/materialsystem/qgraphicsapifilter_p.h
@@ -70,6 +70,8 @@ struct Q_3DRENDERSHARED_PRIVATE_EXPORT GraphicsApiFilterData
QStringList m_extensions;
QString m_vendor;
+ QString toString() const;
+
bool operator ==(const GraphicsApiFilterData &other) const;
bool operator !=(const GraphicsApiFilterData &other) const;
bool operator <(const GraphicsApiFilterData &other) const;
diff --git a/src/render/materialsystem/qmaterial.cpp b/src/render/materialsystem/qmaterial.cpp
index edd227500..a1bec183b 100644
--- a/src/render/materialsystem/qmaterial.cpp
+++ b/src/render/materialsystem/qmaterial.cpp
@@ -283,8 +283,10 @@ void QMaterial::removeParameter(QParameter *parameter)
{
Q_ASSERT(parameter);
Q_D(QMaterial);
+ if (!d->m_parameters.removeOne(parameter))
+ return;
+ d->unregisterDestructionHelper(parameter);
d->updateNode(parameter, "parameter", Qt3DCore::PropertyValueRemoved);
- d->m_parameters.removeOne(parameter);
}
/*!
diff --git a/src/render/materialsystem/qrenderpass.cpp b/src/render/materialsystem/qrenderpass.cpp
index dcb831b13..33181f4fe 100644
--- a/src/render/materialsystem/qrenderpass.cpp
+++ b/src/render/materialsystem/qrenderpass.cpp
@@ -285,8 +285,9 @@ void QRenderPass::removeFilterKey(QFilterKey *filterKey)
{
Q_ASSERT(filterKey);
Q_D(QRenderPass);
+ if (!d->m_filterKeyList.removeOne(filterKey))
+ return;
d->updateNode(filterKey, "filterKeys", Qt3DCore::PropertyValueRemoved);
- d->m_filterKeyList.removeOne(filterKey);
// Remove bookkeeping connection
d->unregisterDestructionHelper(filterKey);
}
@@ -333,8 +334,9 @@ void QRenderPass::removeRenderState(QRenderState *state)
{
Q_ASSERT(state);
Q_D(QRenderPass);
+ if (!d->m_renderStates.removeOne(state))
+ return;
d->updateNode(state, "renderState", Qt3DCore::PropertyValueRemoved);
- d->m_renderStates.removeOne(state);
// Remove bookkeeping connection
d->unregisterDestructionHelper(state);
}
@@ -380,8 +382,9 @@ void QRenderPass::removeParameter(QParameter *parameter)
{
Q_ASSERT(parameter);
Q_D(QRenderPass);
+ if (!d->m_parameters.removeOne(parameter))
+ return;
d->updateNode(parameter, "parameter", Qt3DCore::PropertyValueRemoved);
- d->m_parameters.removeOne(parameter);
// Remove bookkeeping connection
d->unregisterDestructionHelper(parameter);
}
diff --git a/src/render/materialsystem/qtechnique.cpp b/src/render/materialsystem/qtechnique.cpp
index a9b7ca82b..0e1787938 100644
--- a/src/render/materialsystem/qtechnique.cpp
+++ b/src/render/materialsystem/qtechnique.cpp
@@ -269,8 +269,9 @@ void QTechnique::removeFilterKey(QFilterKey *filterKey)
{
Q_ASSERT(filterKey);
Q_D(QTechnique);
+ if (!d->m_filterKeys.removeOne(filterKey))
+ return;
d->updateNode(filterKey, "filterKeys", Qt3DCore::PropertyValueRemoved);
- d->m_filterKeys.removeOne(filterKey);
// Remove bookkeeping connection
d->unregisterDestructionHelper(filterKey);
}
@@ -316,8 +317,9 @@ void QTechnique::removeParameter(QParameter *parameter)
{
Q_ASSERT(parameter);
Q_D(QTechnique);
+ if (!d->m_parameters.removeOne(parameter))
+ return;
d->updateNode(parameter, "parameter", Qt3DCore::PropertyValueRemoved);
- d->m_parameters.removeOne(parameter);
// Remove bookkeeping connection
d->unregisterDestructionHelper(parameter);
}
@@ -353,8 +355,9 @@ void QTechnique::removeRenderPass(QRenderPass *pass)
{
Q_ASSERT(pass);
Q_D(QTechnique);
+ if (!d->m_renderPasses.removeOne(pass))
+ return;
d->updateNode(pass, "pass", Qt3DCore::PropertyValueAdded);
- d->m_renderPasses.removeOne(pass);
// Remove bookkeeping connection
d->unregisterDestructionHelper(pass);
}
diff --git a/src/render/materialsystem/shaderbuilder.cpp b/src/render/materialsystem/shaderbuilder.cpp
index b902e3d8c..996270b9e 100644
--- a/src/render/materialsystem/shaderbuilder.cpp
+++ b/src/render/materialsystem/shaderbuilder.cpp
@@ -246,7 +246,8 @@ void ShaderBuilder::generateCode(QShaderProgram::ShaderType type)
generator.graph = graph;
const auto code = generator.createShaderCode(m_enabledLayers);
- m_codes.insert(type, QShaderProgramPrivate::deincludify(code, graphPath + QStringLiteral(".glsl")));
+ const auto deincludified = QShaderProgramPrivate::deincludify(code, graphPath + QStringLiteral(".glsl"));
+ m_codes.insert(type, deincludified);
m_dirtyTypes.remove(type);
m_pendingUpdates.push_back({ peerId(),
@@ -278,7 +279,7 @@ void ShaderBuilder::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
markDirty(AbstractRenderer::ShadersDirty);
}
- static const QVector<std::pair<QShaderProgram::ShaderType, QUrl (QShaderProgramBuilder::*)() const>> shaderTypesToGetters = {
+ static const QVarLengthArray<std::pair<QShaderProgram::ShaderType, QUrl (QShaderProgramBuilder::*)() const>, 6> shaderTypesToGetters {
{QShaderProgram::Vertex, &QShaderProgramBuilder::vertexShaderGraph},
{QShaderProgram::TessellationControl, &QShaderProgramBuilder::tessellationControlShaderGraph},
{QShaderProgram::TessellationEvaluation, &QShaderProgramBuilder::tessellationEvaluationShaderGraph},
diff --git a/src/render/materialsystem/shaderdata.cpp b/src/render/materialsystem/shaderdata.cpp
index 67c8f35f7..97db303c2 100644
--- a/src/render/materialsystem/shaderdata.cpp
+++ b/src/render/materialsystem/shaderdata.cpp
@@ -162,7 +162,7 @@ ShaderData *ShaderData::lookupResource(QNodeId id)
}
// RenderCommand updater jobs
-QVariant ShaderData::getTransformedProperty(const QString &name, const Matrix4x4 &viewMatrix)
+QVariant ShaderData::getTransformedProperty(const QString &name, const Matrix4x4 &viewMatrix) const
{
// Note protecting m_worldMatrix at this point as we assume all world updates
// have been performed when reaching this point
diff --git a/src/render/materialsystem/shaderdata_p.h b/src/render/materialsystem/shaderdata_p.h
index 5c6352eba..080d2c85e 100644
--- a/src/render/materialsystem/shaderdata_p.h
+++ b/src/render/materialsystem/shaderdata_p.h
@@ -89,7 +89,7 @@ public:
// Called by FramePreparationJob
void updateWorldTransform(const Matrix4x4 &worldMatrix);
- QVariant getTransformedProperty(const QString &name, const Matrix4x4 &viewMatrix);
+ QVariant getTransformedProperty(const QString &name, const Matrix4x4 &viewMatrix) const;
// Unit tests purposes only
TransformType propertyTransformType(const QString &name) const;
diff --git a/src/render/picking/qabstractraycaster.cpp b/src/render/picking/qabstractraycaster.cpp
index f26c67e99..42c7bc1e5 100644
--- a/src/render/picking/qabstractraycaster.cpp
+++ b/src/render/picking/qabstractraycaster.cpp
@@ -348,8 +348,9 @@ void QAbstractRayCaster::removeLayer(QLayer *layer)
{
Q_ASSERT(layer);
Q_D(QAbstractRayCaster);
+ if (!d->m_layers.removeOne(layer))
+ return;
d->updateNode(layer, "layer", Qt3DCore::PropertyValueRemoved);
- d->m_layers.removeOne(layer);
// Remove bookkeeping connection
d->unregisterDestructionHelper(layer);
}
diff --git a/src/render/shadergraph/qshadergenerator.cpp b/src/render/shadergraph/qshadergenerator.cpp
index 4f37cfef1..15178fc71 100644
--- a/src/render/shadergraph/qshadergenerator.cpp
+++ b/src/render/shadergraph/qshadergenerator.cpp
@@ -43,17 +43,17 @@
#include <QRegularExpression>
#include <cctype>
+#include <qshaderprogram_p.h>
QT_BEGIN_NAMESPACE
-namespace Qt3DRender
-{
+namespace Qt3DRender {
Q_LOGGING_CATEGORY(ShaderGenerator, "ShaderGenerator", QtWarningMsg)
namespace
{
- QByteArray toGlsl(QShaderLanguage::StorageQualifier qualifier, const QShaderFormat &format)
+ QByteArray toGlsl(QShaderLanguage::StorageQualifier qualifier, const QShaderFormat &format) noexcept
{
- if (format.version().majorVersion() <= 2) {
+ if (format.version().majorVersion() <= 2 && format.api() != QShaderFormat::RHI) {
// Note we're assuming fragment shader only here, it'd be different
// values for vertex shader, will need to be fixed properly at some
// point but isn't necessary yet (this problem already exists in past
@@ -91,7 +91,7 @@ namespace
Q_UNREACHABLE();
}
- QByteArray toGlsl(QShaderLanguage::VariableType type)
+ QByteArray toGlsl(QShaderLanguage::VariableType type) noexcept
{
switch (type) {
case QShaderLanguage::Bool:
@@ -267,7 +267,8 @@ namespace
Q_UNREACHABLE();
}
- QByteArray replaceParameters(const QByteArray &original, const QShaderNode &node, const QShaderFormat &format)
+ QByteArray replaceParameters(const QByteArray &original, const QShaderNode &node,
+ const QShaderFormat &format) noexcept
{
QByteArray result = original;
@@ -276,11 +277,13 @@ namespace
const QByteArray placeholder = QByteArray(QByteArrayLiteral("$") + parameterName.toUtf8());
const QVariant parameter = node.parameter(parameterName);
if (parameter.userType() == qMetaTypeId<QShaderLanguage::StorageQualifier>()) {
- const QShaderLanguage::StorageQualifier qualifier = qvariant_cast<QShaderLanguage::StorageQualifier>(parameter);
+ const QShaderLanguage::StorageQualifier qualifier =
+ qvariant_cast<QShaderLanguage::StorageQualifier>(parameter);
const QByteArray value = toGlsl(qualifier, format);
result.replace(placeholder, value);
} else if (parameter.userType() == qMetaTypeId<QShaderLanguage::VariableType>()) {
- const QShaderLanguage::VariableType type = qvariant_cast<QShaderLanguage::VariableType>(parameter);
+ const QShaderLanguage::VariableType type =
+ qvariant_cast<QShaderLanguage::VariableType>(parameter);
const QByteArray value = toGlsl(type);
result.replace(placeholder, value);
} else {
@@ -291,64 +294,275 @@ namespace
return result;
}
-}
-QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) const
-{
- auto code = QByteArrayList();
-
- if (format.isValid()) {
- const bool isGLES = format.api() == QShaderFormat::OpenGLES;
- const int major = format.version().majorVersion();
- const int minor = format.version().minorVersion();
-
- const int version = major == 2 && isGLES ? 100
- : major == 3 && isGLES ? 300
- : major == 2 ? 100 + 10 * (minor + 1)
- : major == 3 && minor <= 2 ? 100 + 10 * (minor + 3)
- : major * 100 + minor * 10
- ;
-
- const QByteArray profile = isGLES && version > 100 ? QByteArrayLiteral(" es")
- : version >= 150 && format.api() == QShaderFormat::OpenGLCoreProfile ? QByteArrayLiteral(" core")
- : version >= 150 && format.api() == QShaderFormat::OpenGLCompatibilityProfile ? QByteArrayLiteral(" compatibility")
- : QByteArray();
-
- code << (QByteArrayLiteral("#version ") + QByteArray::number(version) + profile);
- code << QByteArray();
+ bool intersectsEnabledLayers(const QStringList &enabledLayers, const QStringList &layers) noexcept
+ {
+ return layers.isEmpty()
+ || std::any_of(layers.cbegin(), layers.cend(),
+ [enabledLayers](const QString &s) { return enabledLayers.contains(s); });
}
- const auto intersectsEnabledLayers = [enabledLayers] (const QStringList &layers) {
- return layers.isEmpty()
- || std::any_of(layers.cbegin(), layers.cend(),
- [enabledLayers] (const QString &s) { return enabledLayers.contains(s); });
+ struct ShaderGenerationState
+ {
+ ShaderGenerationState(const QShaderGenerator & gen, QStringList layers, QVector<QShaderNode> nodes)
+ : generator{gen}
+ , enabledLayers{layers}
+ , nodes{nodes}
+ {
+
+ }
+
+ const QShaderGenerator &generator;
+ QStringList enabledLayers;
+ QVector<QShaderNode> nodes;
+ QByteArrayList code;
+
+ QVector<QString> globalInputVariables;
+ const QRegularExpression globalInputExtractRegExp { QStringLiteral("^.*\\s+(\\w+).*;$") };
};
- QVector<QString> globalInputVariables;
- const QRegularExpression globalInputExtractRegExp(QStringLiteral("^.*\\s+(\\w+).*;$"));
+ class GLSL45HeaderWriter
+ {
+ public:
+ void writeHeader(ShaderGenerationState &state)
+ {
+ const auto &format = state.generator.format;
+ auto &code = state.code;
+ for (const QShaderNode &node : state.nodes) {
+ if (intersectsEnabledLayers(state.enabledLayers, node.layers())) {
+ const QByteArrayList& headerSnippets = node.rule(format).headerSnippets;
+ for (const QByteArray &snippet : headerSnippets) {
+ auto replacedSnippet = replaceParameters(snippet, node, format).trimmed();
+
+ if (replacedSnippet.startsWith(QByteArrayLiteral("add-input"))) {
+ onInOut(code, replacedSnippet);
+ } else if (replacedSnippet.startsWith(QByteArrayLiteral("add-uniform"))) {
+ onNamedUniform(ubo, replacedSnippet);
+ } else if (replacedSnippet.startsWith(QByteArrayLiteral("add-sampler"))) {
+ onNamedSampler(code, replacedSnippet);
+ } else if (replacedSnippet.startsWith(QByteArrayLiteral("#pragma include "))) {
+ onInclude(code, replacedSnippet);
+ } else {
+ code << replacedSnippet;
+ }
+ // If node is an input, record the variable name into the globalInputVariables
+ // vector
+ if (node.type() == QShaderNode::Input) {
+ const QRegularExpressionMatch match = state.globalInputExtractRegExp.match(
+ QString::fromUtf8(code.last()));
+ if (match.hasMatch())
+ state.globalInputVariables.push_back(match.captured(1));
+ }
+ }
+ }
+ }
- const QVector<QShaderNode> nodes = graph.nodes();
- for (const QShaderNode &node : nodes) {
- if (intersectsEnabledLayers(node.layers())) {
- const QByteArrayList headerSnippets = node.rule(format).headerSnippets;
- for (const QByteArray &snippet : headerSnippets) {
- code << replaceParameters(snippet, node, format);
-
- // If node is an input, record the variable name into the globalInputVariables vector
- if (node.type() == QShaderNode::Input) {
- const QRegularExpressionMatch match = globalInputExtractRegExp.match(QString::fromUtf8(code.last()));
- if (match.hasMatch())
- globalInputVariables.push_back(match.captured(1));
+ if (!ubo.isEmpty()) {
+ code << QByteArrayLiteral("layout(std140, binding = ")
+ + QByteArray::number(currentBinding++)
+ + QByteArrayLiteral(") uniform qt3d_shadergraph_generated_uniforms {");
+ code << ubo;
+ code << "};";
+ }
+ }
+
+ private:
+ void onInOut(QByteArrayList &code, const QByteArray &snippet) noexcept
+ {
+ const auto split = snippet.split(' ');
+ if (split.size() < 4) {
+ qDebug() << "Invalid header snippet: " << snippet;
+ return;
+ }
+ const auto &qualifier = split[1];
+ const auto &type = split[2];
+ const auto &name = split[3];
+
+ if (qualifier == QByteArrayLiteral("in")) {
+ code << (QByteArrayLiteral("layout(location = ")
+ + QByteArray::number(currentInputLocation++) + QByteArrayLiteral(") in ")
+ + type + ' ' + name + QByteArrayLiteral(";"));
+ } else if (qualifier == QByteArrayLiteral("out")) {
+ code << (QByteArrayLiteral("layout(location = ")
+ + QByteArray::number(currentOutputLocation++) + QByteArrayLiteral(") out ")
+ + type + ' ' + name + QByteArrayLiteral(";"));
+ } else if (qualifier == QByteArrayLiteral("uniform")) {
+ ubo << (type + ' ' + name + ';');
+ }
+ }
+
+ void onNamedUniform(QByteArrayList &ubo, const QByteArray &snippet) noexcept
+ {
+ const auto split = snippet.split(' ');
+ if (split.size() < 3) {
+ qDebug() << "Invalid header snippet: " << snippet;
+ return;
+ }
+
+ const auto &type = split[1];
+ const auto &name = split[2];
+
+ ubo << (type + ' ' + name + ';');
+ }
+
+ void onNamedSampler(QByteArrayList &code, const QByteArray &snippet) noexcept
+ {
+ const auto split = snippet.split(' ');
+ if (split.size() < 3) {
+ qDebug() << "Invalid header snippet: " << snippet;
+ return;
+ }
+ const auto binding = QByteArray::number(currentBinding++);
+ const auto &type = split[1];
+ const auto &name = split[2];
+
+ code << (QByteArrayLiteral("layout(binding = ") + binding + QByteArrayLiteral(") uniform ")
+ + type + ' ' + name + QByteArrayLiteral(";"));
+ }
+
+ void onInclude(QByteArrayList &code, const QByteArray &snippet) noexcept
+ {
+ const auto filepath = QString::fromUtf8(snippet.mid(strlen("#pragma include ")));
+ QString deincluded = QString::fromUtf8(QShaderProgramPrivate::deincludify(filepath));
+
+ // This lambda will replace all occurrences of a string (e.g. "binding = auto") by another,
+ // with the incremented int passed as argument (e.g. "binding = 1", "binding = 2" ...)
+ const auto replaceAndIncrement = [&deincluded](const QRegularExpression &regexp,
+ int &variable,
+ const QString &replacement) noexcept {
+ int matchStart = 0;
+ do {
+ matchStart = deincluded.indexOf(regexp, matchStart);
+ if (matchStart != -1) {
+ const auto match = regexp.match(deincluded.midRef(matchStart));
+ const auto length = match.capturedLength(0);
+
+ deincluded.replace(matchStart, length, replacement.arg(variable++));
+ }
+ } while (matchStart != -1);
+ };
+
+ // 1. Handle uniforms
+ {
+ thread_local const QRegularExpression bindings(
+ QStringLiteral("binding\\s?+=\\s?+auto"));
+
+ replaceAndIncrement(bindings, currentBinding, QStringLiteral("binding = %1"));
+ }
+
+ // 2. Handle inputs
+ {
+ thread_local const QRegularExpression inLocations(
+ QStringLiteral("location\\s?+=\\s?+auto\\s?+\\)\\s?+in\\s+"));
+
+ replaceAndIncrement(inLocations, currentInputLocation,
+ QStringLiteral("location = %1) in "));
+ }
+
+ // 3. Handle outputs
+ {
+ thread_local const QRegularExpression outLocations(
+ QStringLiteral("location\\s?+=\\s?+auto\\s?+\\)\\s?+out\\s+"));
+
+ replaceAndIncrement(outLocations, currentOutputLocation,
+ QStringLiteral("location = %1) out "));
+ }
+
+ code << deincluded.toUtf8();
+ }
+
+ int currentInputLocation { 0 };
+ int currentOutputLocation { 0 };
+ int currentBinding { 0 };
+ QByteArrayList ubo;
+ };
+
+ struct GLSLHeaderWriter
+ {
+ void writeHeader(ShaderGenerationState &state)
+ {
+ const auto &format = state.generator.format;
+ auto &code = state.code;
+ for (const QShaderNode &node : state.nodes) {
+ if (intersectsEnabledLayers(state.enabledLayers, node.layers())) {
+ const QByteArrayList& headerSnippets = node.rule(format).headerSnippets;
+ for (const QByteArray &snippet : headerSnippets) {
+ code << replaceParameters(snippet, node, format);
+
+ // If node is an input, record the variable name into the globalInputVariables
+ // vector
+ if (node.type() == QShaderNode::Input) {
+ const QRegularExpressionMatch match = state.globalInputExtractRegExp.match(
+ QString::fromUtf8(code.last()));
+ if (match.hasMatch())
+ state.globalInputVariables.push_back(match.captured(1));
+ }
+ }
}
}
}
+ };
+
+ QByteArray versionString(const QShaderFormat &format) noexcept
+ {
+ if (!format.isValid())
+ return {};
+
+ switch (format.api()) {
+ case QShaderFormat::RHI: {
+ return QByteArrayLiteral("#version 450");
+ }
+ case QShaderFormat::VulkanFlavoredGLSL: {
+ const int major = format.version().majorVersion();
+ const int minor = format.version().minorVersion();
+ return (QByteArrayLiteral("#version ") + QByteArray::number(major * 100 + minor * 10));
+ }
+ default: {
+ const bool isGLES = format.api() == QShaderFormat::OpenGLES;
+ const int major = format.version().majorVersion();
+ const int minor = format.version().minorVersion();
+
+ const int version = major == 2 && isGLES ? 100
+ : major == 3 && isGLES ? 300
+ : major == 2 ? 100 + 10 * (minor + 1)
+ : major == 3 && minor <= 2 ? 100 + 10 * (minor + 3)
+ : major * 100 + minor * 10;
+
+ const QByteArray profile =
+ isGLES && version > 100 ? QByteArrayLiteral(" es")
+ : version >= 150 && format.api() == QShaderFormat::OpenGLCoreProfile ? QByteArrayLiteral(" core")
+ : version >= 150 && format.api() == QShaderFormat::OpenGLCompatibilityProfile ? QByteArrayLiteral(" compatibility")
+ : QByteArray();
+
+ return (QByteArrayLiteral("#version ") + QByteArray::number(version) + profile);
+ }
+ }
+ }
+}
+
+QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) const
+{
+ const QVector<QShaderNode> nodes = graph.nodes();
+ ShaderGenerationState state(*this, enabledLayers, nodes);
+ QByteArrayList &code = state.code;
+
+ code << versionString(format);
+ code << QByteArray();
+
+ if (format.api() == QShaderFormat::VulkanFlavoredGLSL || format.api() == QShaderFormat::RHI) {
+ GLSL45HeaderWriter builder;
+ builder.writeHeader(state);
+ } else {
+ GLSLHeaderWriter builder;
+ builder.writeHeader(state);
}
code << QByteArray();
code << QByteArrayLiteral("void main()");
code << QByteArrayLiteral("{");
- const QRegularExpression temporaryVariableToAssignmentRegExp(QStringLiteral("([^;]*\\s+(v\\d+))\\s*=\\s*([^;]*);"));
+ const QRegularExpression temporaryVariableToAssignmentRegExp(
+ QStringLiteral("([^;]*\\s+(v\\d+))\\s*=\\s*([^;]*);"));
const QRegularExpression temporaryVariableInAssignmentRegExp(QStringLiteral("\\W*(v\\d+)\\W*"));
const QRegularExpression statementRegExp(QStringLiteral("\\s*(\\w+)\\s*=\\s*([^;]*);"));
@@ -362,11 +576,7 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers)
struct Variable
{
- enum Type {
- GlobalInput,
- TemporaryAssignment,
- Output
- };
+ enum Type { GlobalInput, TemporaryAssignment, Output };
QString name;
QString declaration;
@@ -380,7 +590,8 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers)
if (v->substituted)
return;
- qCDebug(ShaderGenerator) << "Begin Substituting " << v->name << " = " << v->assignment.expression;
+ qCDebug(ShaderGenerator)
+ << "Begin Substituting " << v->name << " = " << v->assignment.expression;
for (Variable *ref : qAsConst(v->assignment.referencedVariables)) {
// Recursively substitute
Variable::substitute(ref);
@@ -390,14 +601,15 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers)
if (ref->referenceCount == 1 || ref->type == Variable::GlobalInput) {
const QRegularExpression r(QStringLiteral("(.*\\b)(%1)(\\b.*)").arg(ref->name));
if (v->assignment.referencedVariables.size() == 1)
- v->assignment.expression.replace(r,
- QStringLiteral("\\1%2\\3").arg(ref->assignment.expression));
+ v->assignment.expression.replace(
+ r, QStringLiteral("\\1%2\\3").arg(ref->assignment.expression));
else
- v->assignment.expression.replace(r,
- QStringLiteral("(\\1%2\\3)").arg(ref->assignment.expression));
+ v->assignment.expression.replace(
+ r, QStringLiteral("(\\1%2\\3)").arg(ref->assignment.expression));
}
}
- qCDebug(ShaderGenerator) << "Done Substituting " << v->name << " = " << v->assignment.expression;
+ qCDebug(ShaderGenerator)
+ << "Done Substituting " << v->name << " = " << v->assignment.expression;
v->substituted = true;
}
};
@@ -438,13 +650,16 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers)
return nullptr;
};
- auto gatherTemporaryVariablesFromAssignment = [&] (Variable *v, const QString &assignmentContent) {
- QRegularExpressionMatchIterator subMatchIt = temporaryVariableInAssignmentRegExp.globalMatch(assignmentContent);
+ auto gatherTemporaryVariablesFromAssignment = [&](Variable *v,
+ const QString &assignmentContent) {
+ QRegularExpressionMatchIterator subMatchIt =
+ temporaryVariableInAssignmentRegExp.globalMatch(assignmentContent);
while (subMatchIt.hasNext()) {
const QRegularExpressionMatch subMatch = subMatchIt.next();
const QString variableName = subMatch.captured(1);
- // Variable we care about should already exists -> an expression cannot reference a variable that hasn't been defined
+ // Variable we care about should already exists -> an expression cannot reference a
+ // variable that hasn't been defined
Variable *u = findVariable(variableName);
Q_ASSERT(u);
@@ -460,7 +675,8 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers)
QByteArray line = node.rule(format).substitution;
const QVector<QShaderNodePort> ports = node.ports();
- struct VariableReplacement {
+ struct VariableReplacement
+ {
QByteArray placeholder;
QByteArray variable;
};
@@ -477,8 +693,8 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers)
Q_ASSERT(portIndex >= 0);
- const int variableIndex = isInput ? statement.inputs.at(portIndex)
- : statement.outputs.at(portIndex);
+ const int variableIndex =
+ isInput ? statement.inputs.at(portIndex) : statement.outputs.at(portIndex);
if (variableIndex < 0)
continue;
@@ -502,10 +718,11 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers)
const int placeholderLength = end - begin;
const QByteArray variableName = line.mid(begin, placeholderLength);
- const auto replacementIt = std::find_if(variableReplacements.cbegin(), variableReplacements.cend(),
- [&variableName](const VariableReplacement &replacement) {
- return variableName == replacement.placeholder;
- });
+ const auto replacementIt =
+ std::find_if(variableReplacements.cbegin(), variableReplacements.cend(),
+ [&variableName](const VariableReplacement &replacement) {
+ return variableName == replacement.placeholder;
+ });
if (replacementIt != variableReplacements.cend()) {
line.replace(begin, placeholderLength, replacementIt->variable);
@@ -526,7 +743,8 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers)
matches = statementRegExp.globalMatch(QString::fromUtf8(substitutionedLine));
break;
case QShaderNode::Function:
- matches = temporaryVariableToAssignmentRegExp.globalMatch(QString::fromUtf8(substitutionedLine));
+ matches = temporaryVariableToAssignmentRegExp.globalMatch(
+ QString::fromUtf8(substitutionedLine));
break;
case QShaderNode::Invalid:
break;
@@ -606,7 +824,8 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers)
if (v != nullptr) {
Variable::substitute(v);
- qCDebug(ShaderGenerator) << "Line " << lineContent.rawContent << "is assigned to temporary" << v->name;
+ qCDebug(ShaderGenerator)
+ << "Line " << lineContent.rawContent << "is assigned to temporary" << v->name;
// Check number of occurrences a temporary variable is referenced
if (v->referenceCount == 1 || v->type == Variable::GlobalInput) {
@@ -615,9 +834,10 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers)
lineContent.rawContent.clear();
// We assume expression that were referencing vN will have vN properly substituted
} else {
- lineContent.rawContent = QStringLiteral(" %1 = %2;").arg(v->declaration)
- .arg(v->assignment.expression)
- .toUtf8();
+ lineContent.rawContent = QStringLiteral(" %1 = %2;")
+ .arg(v->declaration)
+ .arg(v->assignment.expression)
+ .toUtf8();
}
qCDebug(ShaderGenerator) << "Updated Line is " << lineContent.rawContent;
@@ -636,5 +856,6 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers)
return code.join('\n');
}
+
}
QT_END_NAMESPACE
diff --git a/src/render/shadergraph/qshadernodesloader.cpp b/src/render/shadergraph/qshadernodesloader.cpp
index 8346ed3d5..df34fd1f7 100644
--- a/src/render/shadergraph/qshadernodesloader.cpp
+++ b/src/render/shadergraph/qshadernodesloader.cpp
@@ -220,9 +220,10 @@ void QShaderNodesLoader::load(const QJsonObject &prototypesObject)
: api == QStringLiteral("OpenGLCoreProfile") ? QShaderFormat::OpenGLCoreProfile
: api == QStringLiteral("OpenGLCompatibilityProfile") ? QShaderFormat::OpenGLCompatibilityProfile
: api == QStringLiteral("VulkanFlavoredGLSL") ? QShaderFormat::VulkanFlavoredGLSL
+ : api == QStringLiteral("RHI") ? QShaderFormat::RHI
: QShaderFormat::NoApi);
if (format.api() == QShaderFormat::NoApi) {
- qWarning() << "Format API must be one of: OpenGLES, OpenGLNoProfile, OpenGLCoreProfile or OpenGLCompatibilityProfile, VulkanFlavoredGLSL";
+ qWarning() << "Format API must be one of: OpenGLES, OpenGLNoProfile, OpenGLCoreProfile OpenGLCompatibilityProfile, VulkanFlavoredGLSL or RHI";
hasError = true;
break;
}
diff --git a/src/render/texture/qabstracttexture.cpp b/src/render/texture/qabstracttexture.cpp
index 2e7fd0f63..2a955c5d8 100644
--- a/src/render/texture/qabstracttexture.cpp
+++ b/src/render/texture/qabstracttexture.cpp
@@ -791,8 +791,9 @@ void QAbstractTexture::removeTextureImage(QAbstractTextureImage *textureImage)
{
Q_ASSERT(textureImage);
Q_D(QAbstractTexture);
+ if (!d->m_textureImages.removeOne(textureImage))
+ return;
d->updateNode(textureImage, "textureImage", PropertyValueRemoved);
- d->m_textureImages.removeOne(textureImage);
// Remove bookkeeping connection
d->unregisterDestructionHelper(textureImage);
}
diff --git a/tests/auto/render/shadergraph/qshadergenerator/tst_qshadergenerator.cpp b/tests/auto/render/shadergraph/qshadergenerator/tst_qshadergenerator.cpp
index 780038976..90906f4e9 100644
--- a/tests/auto/render/shadergraph/qshadergenerator/tst_qshadergenerator.cpp
+++ b/tests/auto/render/shadergraph/qshadergenerator/tst_qshadergenerator.cpp
@@ -260,7 +260,7 @@ void tst_QShaderGenerator::shouldGenerateShaderCode_data()
<< "}"
<< "";
- QTest::newRow("EmptyGraphAndFormat") << QShaderGraph() << QShaderFormat() << QByteArrayLiteral("\nvoid main()\n{\n}\n");
+ QTest::newRow("EmptyGraphAndFormat") << QShaderGraph() << QShaderFormat() << QByteArrayLiteral("\n\n\nvoid main()\n{\n}\n");
QTest::newRow("LightExposureGraphAndES2") << graph << openGLES2 << (versionGLES2 + es2Code).join('\n');
QTest::newRow("LightExposureGraphAndGL3") << graph << openGL3 << (versionGL3 + gl3Code).join('\n');
QTest::newRow("LightExposureGraphAndGL32") << graph << openGL32 << (versionGL32 + gl3Code).join('\n');
diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro
index 633c18006..38805c37a 100644
--- a/tests/manual/manual.pro
+++ b/tests/manual/manual.pro
@@ -97,3 +97,5 @@ qtHaveModule(quick) {
scene3d-in-sync \
compressed_textures \
}
+
+qtHaveModule(quickwidgets): SUBDIRS += quickwidget-switch
diff --git a/tests/manual/quickwidget-switch/main.cpp b/tests/manual/quickwidget-switch/main.cpp
new file mode 100644
index 000000000..ebadc458d
--- /dev/null
+++ b/tests/manual/quickwidget-switch/main.cpp
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QDesktopWidget>
+#include <QScreen>
+#include <QApplication>
+#include <QMainWindow>
+#include <QMdiArea>
+#include <QMdiSubWindow>
+#include <QQuickWidget>
+#include <QVBoxLayout>
+#include <QPushButton>
+
+void configureMainWindow(QMainWindow *w, QMdiArea *mdiArea, QPushButton *button)
+{
+ auto widget = new QWidget;
+ auto layout = new QVBoxLayout;
+ layout->addWidget(mdiArea);
+ layout->addWidget(button);
+ widget->setLayout(layout);
+ w->setCentralWidget(widget);
+}
+
+int main(int argc, char* argv[])
+{
+ QApplication app(argc, argv);
+
+ QMainWindow w1;
+ w1.winId();
+ w1.windowHandle()->setScreen(QGuiApplication::screens().at(0));
+ auto mdiArea1 = new QMdiArea;
+ auto button1 = new QPushButton("Switch to this window");
+ configureMainWindow(&w1, mdiArea1, button1);
+ w1.setGeometry(0, 0, 800, 800);
+ w1.show();
+
+ QMainWindow w2;
+ w2.winId();
+ w2.windowHandle()->setScreen(QGuiApplication::screens().at(1));
+ auto mdiArea2 = new QMdiArea;
+ auto button2 = new QPushButton("Switch to this window");
+ configureMainWindow(&w2, mdiArea2, button2);
+ w2.setGeometry(0, 0, 800, 800);
+ w2.show();
+
+ QMdiSubWindow* subWindow = new QMdiSubWindow();
+
+ QQuickWidget *quickWidget = new QQuickWidget();
+ quickWidget->resize(QSize(400, 400));
+ quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
+ quickWidget->setSource(QUrl("qrc:/main.qml"));
+
+ subWindow->setWidget(quickWidget);
+
+ QObject::connect(button1, &QPushButton::clicked,
+ [mdiArea1, mdiArea2, subWindow, button1, button2]() {
+ mdiArea2->removeSubWindow(subWindow);
+ mdiArea1->addSubWindow(subWindow);
+ subWindow->show();
+ button1->setEnabled(false);
+ button2->setEnabled(true);
+ });
+
+ QObject::connect(button2, &QPushButton::clicked,
+ [mdiArea1, mdiArea2, subWindow, button1, button2]() {
+ mdiArea1->removeSubWindow(subWindow);
+ mdiArea2->addSubWindow(subWindow);
+ subWindow->show();
+ button1->setEnabled(true);
+ button2->setEnabled(false);
+ });
+
+ mdiArea2->addSubWindow(subWindow);
+ button2->setEnabled(false);
+ subWindow->show();
+
+ return app.exec();
+}
diff --git a/tests/manual/quickwidget-switch/main.qml b/tests/manual/quickwidget-switch/main.qml
new file mode 100644
index 000000000..d4bce020c
--- /dev/null
+++ b/tests/manual/quickwidget-switch/main.qml
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.2 as QQ2
+import Qt3D.Core 2.0
+import Qt3D.Render 2.0
+import Qt3D.Input 2.0
+import Qt3D.Extras 2.0
+
+import QtQuick.Scene3D 2.0
+
+QQ2.Item {
+ id: mioitem
+ width: 300
+ height: 300
+ Scene3D {
+ id: scene3d
+ anchors.fill: parent
+ Entity {
+ id: sceneRoot
+
+ Camera {
+ id: camera
+ projectionType: CameraLens.PerspectiveProjection
+ fieldOfView: 45
+ aspectRatio: 16/9
+ nearPlane : 0.1
+ farPlane : 1000.0
+ position: Qt.vector3d( 0.0, 0.0, -40.0 )
+ upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
+ viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
+ }
+
+ OrbitCameraController {
+ camera: camera
+ }
+
+ components: [
+ RenderSettings {
+ activeFrameGraph: ForwardRenderer {
+ clearColor: Qt.rgba(0, 0.5, 1, 1)
+ camera: camera
+ }
+ },
+ // Event Source will be set by the Qt3DQuickWindow
+ InputSettings { }
+ ]
+
+ PhongMaterial {
+ id: material
+ }
+
+ TorusMesh {
+ id: torusMesh
+ radius: 5
+ minorRadius: 1
+ rings: 100
+ slices: 20
+ }
+
+ Transform {
+ id: torusTransform
+ scale3D: Qt.vector3d(1.5, 1, 0.5)
+ rotation: fromAxisAndAngle(Qt.vector3d(1, 0, 0), 45)
+ }
+
+ Entity {
+ id: torusEntity
+ components: [ torusMesh, material, torusTransform ]
+ }
+
+ SphereMesh {
+ id: sphereMesh
+ radius: 3
+ }
+
+ Transform {
+ id: sphereTransform
+ property real userAngle: 0.0
+ matrix: {
+ var m = Qt.matrix4x4();
+ m.rotate(userAngle, Qt.vector3d(0, 1, 0));
+ m.translate(Qt.vector3d(20, 0, 0));
+ return m;
+ }
+ }
+
+ QQ2.NumberAnimation {
+ target: sphereTransform
+ property: "userAngle"
+ duration: 10000
+ from: 0
+ to: 360
+
+ loops: QQ2.Animation.Infinite
+ running: true
+ }
+
+ Entity {
+ id: sphereEntity
+ components: [ sphereMesh, material, sphereTransform ]
+ }
+ }
+ }
+}
diff --git a/tests/manual/quickwidget-switch/quickwidget-switch.pro b/tests/manual/quickwidget-switch/quickwidget-switch.pro
new file mode 100644
index 000000000..2f1cb98f5
--- /dev/null
+++ b/tests/manual/quickwidget-switch/quickwidget-switch.pro
@@ -0,0 +1,13 @@
+TEMPLATE = app
+
+QT += 3dextras
+CONFIG += resources_big
+
+QT += 3dcore 3drender 3dinput 3dquick 3dlogic qml quick 3dquickextras widgets quickwidgets
+
+SOURCES += \
+ main.cpp
+
+RESOURCES += \
+ quickwidget-switch.qrc
+
diff --git a/tests/manual/quickwidget-switch/quickwidget-switch.qrc b/tests/manual/quickwidget-switch/quickwidget-switch.qrc
new file mode 100644
index 000000000..5f6483ac3
--- /dev/null
+++ b/tests/manual/quickwidget-switch/quickwidget-switch.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/">
+ <file>main.qml</file>
+ </qresource>
+</RCC>
diff --git a/tests/manual/quickwindow-switch/main.cpp b/tests/manual/quickwindow-switch/main.cpp
new file mode 100644
index 000000000..7bebe0c75
--- /dev/null
+++ b/tests/manual/quickwindow-switch/main.cpp
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QGuiApplication>
+#include <QQmlApplicationEngine>
+
+int main(int argc, char* argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ QQmlApplicationEngine engine;
+ const QUrl url(QStringLiteral("qrc:/main.qml"));
+ QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
+ &app, [url](QObject *obj, const QUrl &objUrl) {
+ if (!obj && url == objUrl)
+ QCoreApplication::exit(-1);
+ }, Qt::QueuedConnection);
+ engine.load(url);
+
+ return app.exec();
+}
diff --git a/tests/manual/quickwindow-switch/main.qml b/tests/manual/quickwindow-switch/main.qml
new file mode 100644
index 000000000..4b474bd11
--- /dev/null
+++ b/tests/manual/quickwindow-switch/main.qml
@@ -0,0 +1,181 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.2
+import QtQuick.Window 2.12 as Win
+import Qt3D.Core 2.0
+import Qt3D.Render 2.0
+import Qt3D.Input 2.0
+import Qt3D.Extras 2.0
+
+import QtQuick.Scene3D 2.0
+
+Win.Window {
+ id: win
+ width: 300
+ height: 350
+ visible: true
+ x: Win.Screen.width / 2 - width / 2
+ y: Win.Screen.height / 2 - height / 2
+ Item {
+ id: mioitem
+ width: 300
+ height: 300
+ Scene3D {
+ id: scene3d
+ anchors.fill: parent
+ Entity {
+ id: sceneRoot
+
+ Camera {
+ id: camera
+ projectionType: CameraLens.PerspectiveProjection
+ fieldOfView: 45
+ aspectRatio: 16/9
+ nearPlane : 0.1
+ farPlane : 1000.0
+ position: Qt.vector3d( 0.0, 0.0, -40.0 )
+ upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
+ viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
+ }
+
+ OrbitCameraController {
+ camera: camera
+ }
+
+ components: [
+ RenderSettings {
+ activeFrameGraph: ForwardRenderer {
+ clearColor: Qt.rgba(0, 0.5, 1, 1)
+ camera: camera
+ }
+ },
+ // Event Source will be set by the Qt3DQuickWindow
+ InputSettings { }
+ ]
+
+ PhongMaterial {
+ id: material
+ }
+
+ TorusMesh {
+ id: torusMesh
+ radius: 5
+ minorRadius: 1
+ rings: 100
+ slices: 20
+ }
+
+ Transform {
+ id: torusTransform
+ scale3D: Qt.vector3d(1.5, 1, 0.5)
+ rotation: fromAxisAndAngle(Qt.vector3d(1, 0, 0), 45)
+ }
+
+ Entity {
+ id: torusEntity
+ components: [ torusMesh, material, torusTransform ]
+ }
+
+ SphereMesh {
+ id: sphereMesh
+ radius: 3
+ }
+
+ Transform {
+ id: sphereTransform
+ property real userAngle: 0.0
+ matrix: {
+ var m = Qt.matrix4x4();
+ m.rotate(userAngle, Qt.vector3d(0, 1, 0));
+ m.translate(Qt.vector3d(20, 0, 0));
+ return m;
+ }
+ }
+
+ NumberAnimation {
+ target: sphereTransform
+ property: "userAngle"
+ duration: 10000
+ from: 0
+ to: 360
+
+ loops: Animation.Infinite
+ running: true
+ }
+
+ Entity {
+ id: sphereEntity
+ components: [ sphereMesh, material, sphereTransform ]
+ }
+ }
+ }
+ }
+ Rectangle {
+ height: 50
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ color: "yellow"
+ MouseArea {
+ anchors.fill: parent
+ z: 5
+ onClicked: {
+ win.screen = (win.screen === Qt.application.screens[0] ? Qt.application.screens[1] : Qt.application.screens[0])
+ }
+ }
+ Text {
+ anchors.centerIn: parent
+ minimumPointSize: 12
+ fontSizeMode: Text.Fit
+ text: "Move to the other screen"
+ }
+ }
+}
diff --git a/tests/manual/quickwindow-switch/quickwindow-switch.pro b/tests/manual/quickwindow-switch/quickwindow-switch.pro
new file mode 100644
index 000000000..2f338d36d
--- /dev/null
+++ b/tests/manual/quickwindow-switch/quickwindow-switch.pro
@@ -0,0 +1,13 @@
+TEMPLATE = app
+
+QT += 3dextras
+CONFIG += resources_big
+
+QT += 3dcore 3drender 3dinput 3dquick 3dlogic qml quick 3dquickextras
+
+SOURCES += \
+ main.cpp
+
+RESOURCES += \
+ quickwindow-switch.qrc
+
diff --git a/tests/manual/quickwindow-switch/quickwindow-switch.qrc b/tests/manual/quickwindow-switch/quickwindow-switch.qrc
new file mode 100644
index 000000000..5f6483ac3
--- /dev/null
+++ b/tests/manual/quickwindow-switch/quickwindow-switch.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/">
+ <file>main.qml</file>
+ </qresource>
+</RCC>
diff --git a/tools/qgltf/qgltf.cpp b/tools/qgltf/qgltf.cpp
index 91ecd5ba2..6e1761a33 100644
--- a/tools/qgltf/qgltf.cpp
+++ b/tools/qgltf/qgltf.cpp
@@ -151,7 +151,7 @@ static QIODevice::OpenMode openModeFromText(const char *name) noexcept
{
static const struct OpenModeMapping {
char name[2];
- ushort mode;
+ int mode;
} openModeMapping[] = {
{ { 'r', 0 }, QIODevice::ReadOnly },
{ { 'r', '+' }, QIODevice::ReadWrite },