summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2016-10-11 07:49:54 +0200
committerLiang Qi <liang.qi@qt.io>2016-10-11 07:50:07 +0200
commit8be45352146be822e45e9d563d8e74687fa0fd0e (patch)
tree1fe74c32f641480a93eb3ecba35d27196adc2629
parentd967f59602217923886478140149de8a9cad34ba (diff)
parent410e2f52e0041e695c5d5814bf67bb078b608ce3 (diff)
Merge remote-tracking branch 'origin/5.8' into dev
-rw-r--r--examples/qt3d/audio-visualizer-qml/images/demotitle.pngbin20912 -> 7449 bytes
-rw-r--r--examples/qt3d/audio-visualizer-qml/images/songtitle.pngbin5764 -> 6181 bytes
-rw-r--r--examples/qt3d/basicshapes-cpp/main.cpp10
-rw-r--r--src/core/changes/qnodecreatedchange.cpp47
-rw-r--r--src/core/nodes/qentity.cpp4
-rw-r--r--src/core/nodes/qnode.cpp43
-rw-r--r--src/core/nodes/qnode_p.h2
-rw-r--r--src/extras/geometries/qtorusgeometry.cpp127
-rw-r--r--src/extras/geometries/qtorusgeometry_p.h1
-rw-r--r--src/extras/shaders/es2/light.inc.frag9
-rw-r--r--src/extras/shaders/gl3/gooch.frag3
-rw-r--r--src/input/backend/axissetting_p.h2
-rw-r--r--src/input/backend/qabstractphysicaldevicebackendnode.cpp5
-rw-r--r--src/input/frontend/qbuttonaxisinput.cpp4
-rw-r--r--src/input/frontend/qbuttonaxisinput_p.h2
-rw-r--r--src/quick3d/imports/core/plugins.qmltypes145
-rw-r--r--src/quick3d/imports/extras/defaults/qml/SkyboxEntity.qml12
-rw-r--r--src/quick3d/imports/extras/plugins.qmltypes90
-rw-r--r--src/quick3d/imports/input/plugins.qmltypes42
-rw-r--r--src/quick3d/imports/logic/plugins.qmltypes3
-rw-r--r--src/quick3d/imports/render/plugins.qmltypes1246
-rw-r--r--src/quick3d/imports/scene3d/plugins.qmltypes2
-rw-r--r--src/render/backend/renderer.cpp163
-rw-r--r--src/render/backend/renderer_p.h15
-rw-r--r--src/render/backend/renderview.cpp52
-rw-r--r--src/render/backend/uniform.cpp67
-rw-r--r--src/render/backend/uniform_p.h53
-rw-r--r--src/render/framegraph/framegraphnode.cpp33
-rw-r--r--src/render/framegraph/framegraphnode_p.h2
-rw-r--r--src/render/framegraph/framegraphvisitor.cpp42
-rw-r--r--src/render/frontend/qrendersettings.h2
-rw-r--r--src/render/graphicshelpers/graphicscontext.cpp5
-rw-r--r--src/render/graphicshelpers/graphicshelpergl3_2.cpp (renamed from src/render/graphicshelpers/graphicshelpergl3.cpp)173
-rw-r--r--src/render/graphicshelpers/graphicshelpergl3_2_p.h (renamed from src/render/graphicshelpers/graphicshelpergl3_p.h)5
-rw-r--r--src/render/graphicshelpers/graphicshelpergl4_p.h2
-rw-r--r--src/render/graphicshelpers/graphicshelpers.pri8
-rw-r--r--src/render/jobs/genericlambdajob_p.h4
-rw-r--r--src/render/jobs/job_common_p.h8
-rw-r--r--src/render/jobs/renderviewjobutils_p.h1
-rw-r--r--src/render/materialsystem/shaderdata.cpp2
-rw-r--r--src/render/texture/qtexture.cpp68
-rw-r--r--src/render/texture/qtexture.h5
-rw-r--r--src/render/texture/qtexture_p.h6
-rw-r--r--src/render/texture/qtextureimage.cpp87
-rw-r--r--src/render/texture/qtextureimage.h4
-rw-r--r--src/render/texture/qtextureimage_p.h5
-rw-r--r--src/render/texture/texture_p.h2
-rw-r--r--tests/auto/core/handlemanager/tst_handlemanager.cpp14
-rw-r--r--tests/auto/core/nodes/tst_nodes.cpp2
-rw-r--r--tests/auto/core/qframeallocator/tst_qframeallocator.cpp6
-rw-r--r--tests/auto/core/qtransform/tst_qtransform.cpp8
-rw-r--r--tests/auto/extras/common/common.pri6
-rw-r--r--tests/auto/extras/common/geometrytesthelper.h105
-rw-r--r--tests/auto/extras/extras.pro3
-rw-r--r--tests/auto/extras/qcuboidgeometry/qcuboidgeometry.pro2
-rw-r--r--tests/auto/extras/qcuboidgeometry/tst_qcuboidgeometry.cpp72
-rw-r--r--tests/auto/extras/qtorusgeometry/qtorusgeometry.pro12
-rw-r--r--tests/auto/extras/qtorusgeometry/tst_qtorusgeometry.cpp366
-rw-r--r--tests/auto/input/input.pro3
-rw-r--r--tests/auto/input/qabstractphysicaldevicebackendnode/qabstractphysicaldevicebackendnode.pro11
-rw-r--r--tests/auto/input/qabstractphysicaldevicebackendnode/tst_qabstractphysicaldevicebackendnode.cpp246
-rw-r--r--tests/auto/input/qbuttonaxisinput/tst_qbuttonaxisinput.cpp12
-rw-r--r--tests/auto/render/ddstextures/tst_ddstextures.cpp2
-rw-r--r--tests/auto/render/framegraphnode/tst_framegraphnode.cpp125
-rw-r--r--tests/auto/render/graphicshelpergl2/graphicshelpergl2.pro13
-rw-r--r--tests/auto/render/graphicshelpergl2/tst_graphicshelpergl2.cpp1435
-rw-r--r--tests/auto/render/graphicshelpergl3_2/graphicshelpergl3_2.pro13
-rw-r--r--tests/auto/render/graphicshelpergl3_2/tst_graphicshelpergl3_2.cpp1969
-rw-r--r--tests/auto/render/graphicshelpergl3_3/graphicshelpergl3_3.pro13
-rw-r--r--tests/auto/render/graphicshelpergl3_3/tst_graphicshelpergl3_3.cpp1973
-rw-r--r--tests/auto/render/graphicshelpergl4/graphicshelpergl4.pro13
-rw-r--r--tests/auto/render/graphicshelpergl4/tst_graphicshelpergl4.cpp2047
-rw-r--r--tests/auto/render/qray3d/tst_qray3d.cpp8
-rw-r--r--tests/auto/render/raycasting/tst_raycasting.cpp2
-rw-r--r--tests/auto/render/render.pro7
-rw-r--r--tests/auto/render/triangleboundingvolume/tst_triangleboundingvolume.cpp2
-rw-r--r--tests/auto/render/uniform/tst_uniform.cpp24
-rw-r--r--tests/manual/dynamicscene-cpp/examplescene.cpp2
-rw-r--r--tests/manual/skybox/Skybox.qml12
-rw-r--r--tools/qgltf/qgltf.cpp118
-rw-r--r--tools/qgltf/qgltf.pro3
81 files changed, 10593 insertions, 669 deletions
diff --git a/examples/qt3d/audio-visualizer-qml/images/demotitle.png b/examples/qt3d/audio-visualizer-qml/images/demotitle.png
index 58816784e..75c6c42bd 100644
--- a/examples/qt3d/audio-visualizer-qml/images/demotitle.png
+++ b/examples/qt3d/audio-visualizer-qml/images/demotitle.png
Binary files differ
diff --git a/examples/qt3d/audio-visualizer-qml/images/songtitle.png b/examples/qt3d/audio-visualizer-qml/images/songtitle.png
index 2a9961093..84efe533a 100644
--- a/examples/qt3d/audio-visualizer-qml/images/songtitle.png
+++ b/examples/qt3d/audio-visualizer-qml/images/songtitle.png
Binary files differ
diff --git a/examples/qt3d/basicshapes-cpp/main.cpp b/examples/qt3d/basicshapes-cpp/main.cpp
index b4b01ff30..fffb83a20 100644
--- a/examples/qt3d/basicshapes-cpp/main.cpp
+++ b/examples/qt3d/basicshapes-cpp/main.cpp
@@ -73,6 +73,7 @@
#include <Qt3DRender/qtexture.h>
#include <Qt3DRender/qrenderpass.h>
#include <Qt3DRender/qsceneloader.h>
+#include <Qt3DRender/qpointlight.h>
#include <Qt3DCore/qtransform.h>
#include <Qt3DCore/qaspectengine.h>
@@ -116,6 +117,15 @@ int main(int argc, char **argv)
cameraEntity->setUpVector(QVector3D(0, 1, 0));
cameraEntity->setViewCenter(QVector3D(0, 0, 0));
+ Qt3DCore::QEntity *lightEntity = new Qt3DCore::QEntity(rootEntity);
+ Qt3DRender::QPointLight *light = new Qt3DRender::QPointLight(lightEntity);
+ light->setColor("white");
+ light->setIntensity(1);
+ lightEntity->addComponent(light);
+ Qt3DCore::QTransform *lightTransform = new Qt3DCore::QTransform(lightEntity);
+ lightTransform->setTranslation(cameraEntity->position());
+ lightEntity->addComponent(lightTransform);
+
// For camera controls
Qt3DExtras::QFirstPersonCameraController *camController = new Qt3DExtras::QFirstPersonCameraController(rootEntity);
camController->setCamera(cameraEntity);
diff --git a/src/core/changes/qnodecreatedchange.cpp b/src/core/changes/qnodecreatedchange.cpp
index 891d21986..06e85fbfc 100644
--- a/src/core/changes/qnodecreatedchange.cpp
+++ b/src/core/changes/qnodecreatedchange.cpp
@@ -37,59 +37,16 @@
#include "qnodecreatedchange.h"
#include "qnodecreatedchange_p.h"
#include <Qt3DCore/qnode.h>
-#include <QtCore/qmetaobject.h>
-#include <QtCore/private/qmetaobject_p.h>
+#include <Qt3DCore/private/qnode_p.h>
QT_BEGIN_NAMESPACE
-namespace {
-
-/*! \internal */
-inline const QMetaObjectPrivate *priv(const uint* data)
-{
- return reinterpret_cast<const QMetaObjectPrivate*>(data);
-}
-
-/*! \internal */
-inline bool isDynamicMetaObject(const QMetaObject *mo)
-{
- return (priv(mo->d.data)->flags & DynamicMetaObject);
-}
-
-/*!
- * \internal
- *
- * Find the most derived metaobject that doesn't have a dynamic
- * metaobject farther up the chain.
- * TODO: Add support to QMetaObject to explicitly say if it's a dynamic
- * or static metaobject so we don't need this logic
- */
-const QMetaObject *findStaticMetaObject(const QMetaObject *metaObject)
-{
- const QMetaObject *lastStaticMetaobject = nullptr;
- auto mo = metaObject;
- while (mo) {
- const bool dynamicMetaObject = isDynamicMetaObject(mo);
- if (dynamicMetaObject)
- lastStaticMetaobject = nullptr;
-
- if (!dynamicMetaObject && !lastStaticMetaobject)
- lastStaticMetaobject = mo;
-
- mo = mo->superClass();
- }
- Q_ASSERT(lastStaticMetaobject);
- return lastStaticMetaobject;
-}
-
-}
-
namespace Qt3DCore {
QNodeCreatedChangeBasePrivate::QNodeCreatedChangeBasePrivate(const QNode *node)
: QSceneChangePrivate()
, m_parentId(node->parentNode() ? node->parentNode()->id() : QNodeId())
- , m_metaObject(findStaticMetaObject(node->metaObject()))
+ , m_metaObject(QNodePrivate::findStaticMetaObject(node->metaObject()))
, m_nodeEnabled(node->isEnabled())
{
}
diff --git a/src/core/nodes/qentity.cpp b/src/core/nodes/qentity.cpp
index ea3523c0c..b28898c60 100644
--- a/src/core/nodes/qentity.cpp
+++ b/src/core/nodes/qentity.cpp
@@ -232,8 +232,8 @@ QNodeCreatedChangeBasePtr QEntity::createNodeCreationChange() const
data.parentEntityId = parentEntity() ? parentEntity()->id() : Qt3DCore::QNodeId();
data.componentIdsAndTypes.reserve(d->m_components.size());
const QComponentVector &components = d->m_components;
- for (const auto &c : components) {
- const auto idAndType = QNodeIdTypePair(c->id(), c->metaObject());
+ for (QComponent *c : components) {
+ const auto idAndType = QNodeIdTypePair(c->id(), QNodePrivate::findStaticMetaObject(c->metaObject()));
data.componentIdsAndTypes.push_back(idAndType);
}
diff --git a/src/core/nodes/qnode.cpp b/src/core/nodes/qnode.cpp
index f0df147ab..8dbcb295a 100644
--- a/src/core/nodes/qnode.cpp
+++ b/src/core/nodes/qnode.cpp
@@ -54,6 +54,7 @@
#include <QChildEvent>
#include <QMetaObject>
#include <QMetaProperty>
+#include <QtCore/private/qmetaobject_p.h>
#include <Qt3DCore/QComponent>
#include <Qt3DCore/private/corelogging_p.h>
#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
@@ -793,6 +794,48 @@ QNodeCreatedChangeBasePtr QNode::createNodeCreationChange() const
return QNodeCreatedChangeBasePtr::create(this);
}
+namespace {
+
+/*! \internal */
+inline const QMetaObjectPrivate *priv(const uint* data)
+{
+ return reinterpret_cast<const QMetaObjectPrivate*>(data);
+}
+
+/*! \internal */
+inline bool isDynamicMetaObject(const QMetaObject *mo)
+{
+ return (priv(mo->d.data)->flags & DynamicMetaObject);
+}
+
+} // anonymous
+
+/*!
+ * \internal
+ *
+ * Find the most derived metaobject that doesn't have a dynamic
+ * metaobject farther up the chain.
+ * TODO: Add support to QMetaObject to explicitly say if it's a dynamic
+ * or static metaobject so we don't need this logic
+ */
+const QMetaObject *QNodePrivate::findStaticMetaObject(const QMetaObject *metaObject)
+{
+ const QMetaObject *lastStaticMetaobject = nullptr;
+ auto mo = metaObject;
+ while (mo) {
+ const bool dynamicMetaObject = isDynamicMetaObject(mo);
+ if (dynamicMetaObject)
+ lastStaticMetaobject = nullptr;
+
+ if (!dynamicMetaObject && !lastStaticMetaobject)
+ lastStaticMetaobject = mo;
+
+ mo = mo->superClass();
+ }
+ Q_ASSERT(lastStaticMetaobject);
+ return lastStaticMetaobject;
+}
+
} // namespace Qt3DCore
QT_END_NAMESPACE
diff --git a/src/core/nodes/qnode_p.h b/src/core/nodes/qnode_p.h
index 56a54a8ae..dec114084 100644
--- a/src/core/nodes/qnode_p.h
+++ b/src/core/nodes/qnode_p.h
@@ -130,6 +130,8 @@ public:
QObject::disconnect(m_destructionConnections.take(node));
}
+ static const QMetaObject *findStaticMetaObject(const QMetaObject *metaObject);
+
private:
void notifyCreationChange();
void notifyDestructionChangesAndRemoveFromScene();
diff --git a/src/extras/geometries/qtorusgeometry.cpp b/src/extras/geometries/qtorusgeometry.cpp
index 801281110..ebc944e72 100644
--- a/src/extras/geometries/qtorusgeometry.cpp
+++ b/src/extras/geometries/qtorusgeometry.cpp
@@ -44,6 +44,7 @@
#include <Qt3DRender/qattribute.h>
#include <qmath.h>
#include <QVector3D>
+#include <QVector4D>
QT_BEGIN_NAMESPACE
@@ -53,30 +54,47 @@ namespace Qt3DExtras {
namespace {
+int vertexCount(int requestedRings, int requestedSlices)
+{
+ return (requestedRings + 1) * (requestedSlices + 1);
+}
+
+int triangleCount(int requestedRings, int requestedSlices)
+{
+ return 2 * requestedRings * requestedSlices;
+}
+
QByteArray createTorusVertexData(double radius, double minorRadius,
- int rings, int sides)
+ int rings, int slices)
{
- const int nVerts = sides * (rings + 1);
+ // The additional side and ring compared to what the user asked
+ // for is because we also need to ensure proper texture coordinate
+ // wrapping at the seams. Without this the last ring and side would
+ // interpolate the texture coordinates from ~0.9x back down to 0
+ // (the starting value at the first ring). So we insert an extra
+ // ring and side with the same positions as the first ring and side
+ // but with texture coordinates of 1 (compared to 0).
+ const int nVerts = vertexCount(rings, slices);
QByteArray bufferBytes;
- // vec3 pos, vec2 texCoord, vec3 normal
- const quint32 elementSize = 3 + 2 + 3;
+ // vec3 pos, vec2 texCoord, vec3 normal, vec4 tangent
+ const quint32 elementSize = 3 + 2 + 3 + 4;
const quint32 stride = elementSize * sizeof(float);
bufferBytes.resize(stride * nVerts);
float* fptr = reinterpret_cast<float*>(bufferBytes.data());
- const float ringFactor = (M_PI * 2) / static_cast<float>( rings );
- const float sideFactor = (M_PI * 2) / static_cast<float>( sides );
+ const float ringFactor = (M_PI * 2) / static_cast<float>(rings);
+ const float sliceFactor = (M_PI * 2) / static_cast<float>(slices);
for (int ring = 0; ring <= rings; ++ring) {
const float u = ring * ringFactor;
- const float cu = qCos( u );
- const float su = qSin( u );
+ const float cu = qCos(u);
+ const float su = qSin(u);
- for (int side = 0; side < sides; ++side) {
- const float v = side * sideFactor;
- const float cv = qCos( v );
- const float sv = qSin( v );
+ for (int slice = 0; slice <= slices; ++slice) {
+ const float v = slice * sliceFactor;
+ const float cv = qCos(v + M_PI);
+ const float sv = qSin(v);
const float r = (radius + minorRadius * cv);
*fptr++ = r * cu;
@@ -86,37 +104,45 @@ QByteArray createTorusVertexData(double radius, double minorRadius,
*fptr++ = u / (M_PI * 2);
*fptr++ = v / (M_PI * 2);
- QVector3D n(cv * cu * r, cv * su * r, sv * r);
+ QVector3D n(cv * cu, cv * su, sv);
n.normalize();
*fptr++ = n.x();
*fptr++ = n.y();
*fptr++ = n.z();
+
+ QVector4D t(-su, cu, 0.0f, 1.0f);
+ t.normalize();
+ *fptr++ = t.x();
+ *fptr++ = t.y();
+ *fptr++ = t.z();
+ *fptr++ = t.w();
}
}
return bufferBytes;
}
-QByteArray createTorusIndexData(int rings, int sides)
+QByteArray createTorusIndexData(int requestedRings, int requestedSlices)
{
- QByteArray indexBytes;
- int faces = (sides * 2) * rings; // two tris per side, for all rings
- int indices = faces * 3;
+ const int slices = requestedSlices + 1;
+ int triangles = triangleCount(requestedRings, requestedSlices);
+ int indices = triangles * 3;
Q_ASSERT(indices < 65536);
+ QByteArray indexBytes;
indexBytes.resize(indices * sizeof(quint16));
quint16* indexPtr = reinterpret_cast<quint16*>(indexBytes.data());
- for (int ring = 0; ring < rings; ++ring) {
- const int ringStart = ring * sides;
- const int nextRingStart = (ring + 1) * sides;
- for (int side = 0; side < sides; ++side) {
- const int nextSide = (side + 1) % sides;
- *indexPtr++ = (ringStart + side);
- *indexPtr++ = (nextRingStart + side);
- *indexPtr++ = (nextRingStart + nextSide);
- *indexPtr++ = ringStart + side;
- *indexPtr++ = nextRingStart + nextSide;
- *indexPtr++ = (ringStart + nextSide);
+ for (int ring = 0; ring < requestedRings; ++ring) {
+ const int ringStart = ring * slices;
+ const int nextRingStart = (ring + 1) * slices;
+ for (int slice = 0; slice < requestedSlices; ++slice) {
+ const int nextSlice = (slice + 1) % slices;
+ *indexPtr++ = ringStart + slice;
+ *indexPtr++ = ringStart + nextSlice;
+ *indexPtr++ = nextRingStart + slice;
+ *indexPtr++ = ringStart + nextSlice;
+ *indexPtr++ = nextRingStart + nextSlice;
+ *indexPtr++ = nextRingStart + slice;
}
}
@@ -130,7 +156,7 @@ class TorusVertexDataFunctor : public QBufferDataGenerator
public:
TorusVertexDataFunctor(int rings, int slices, float radius, float minorRadius)
: m_rings(rings)
- , m_sides(slices)
+ , m_slices(slices)
, m_radius(radius)
, m_minorRadius(minorRadius)
{
@@ -138,7 +164,7 @@ public:
QByteArray operator ()() Q_DECL_OVERRIDE
{
- return createTorusVertexData(m_radius, m_minorRadius, m_rings, m_sides);
+ return createTorusVertexData(m_radius, m_minorRadius, m_rings, m_slices);
}
bool operator ==(const QBufferDataGenerator &other) const Q_DECL_OVERRIDE
@@ -146,7 +172,7 @@ public:
const TorusVertexDataFunctor *otherFunctor = functor_cast<TorusVertexDataFunctor>(&other);
if (otherFunctor != nullptr)
return (otherFunctor->m_rings == m_rings &&
- otherFunctor->m_sides == m_sides &&
+ otherFunctor->m_slices == m_slices &&
otherFunctor->m_radius == m_radius &&
otherFunctor->m_minorRadius == m_minorRadius);
return false;
@@ -156,7 +182,7 @@ public:
private:
int m_rings;
- int m_sides;
+ int m_slices;
float m_radius;
float m_minorRadius;
};
@@ -166,13 +192,13 @@ class TorusIndexDataFunctor : public QBufferDataGenerator
public:
TorusIndexDataFunctor(int rings, int slices)
: m_rings(rings)
- , m_sides(slices)
+ , m_slices(slices)
{
}
QByteArray operator ()() Q_DECL_OVERRIDE
{
- return createTorusIndexData(m_rings, m_sides);
+ return createTorusIndexData(m_rings, m_slices);
}
bool operator ==(const QBufferDataGenerator &other) const Q_DECL_OVERRIDE
@@ -180,7 +206,7 @@ public:
const TorusIndexDataFunctor *otherFunctor = functor_cast<TorusIndexDataFunctor>(&other);
if (otherFunctor != nullptr)
return (otherFunctor->m_rings == m_rings &&
- otherFunctor->m_sides == m_sides);
+ otherFunctor->m_slices == m_slices);
return false;
}
@@ -188,7 +214,7 @@ public:
private:
int m_rings;
- int m_sides;
+ int m_slices;
};
QTorusGeometryPrivate::QTorusGeometryPrivate()
@@ -200,6 +226,7 @@ QTorusGeometryPrivate::QTorusGeometryPrivate()
, m_positionAttribute(nullptr)
, m_normalAttribute(nullptr)
, m_texCoordAttribute(nullptr)
+ , m_tangentAttribute(nullptr)
, m_indexAttribute(nullptr)
, m_vertexBuffer(nullptr)
, m_indexBuffer(nullptr)
@@ -212,14 +239,15 @@ void QTorusGeometryPrivate::init()
m_positionAttribute = new QAttribute(q);
m_normalAttribute = new QAttribute(q);
m_texCoordAttribute = new QAttribute(q);
+ m_tangentAttribute = new QAttribute(q);
m_indexAttribute = new QAttribute(q);
m_vertexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer, q);
m_indexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::IndexBuffer, q);
- // vec3 pos, vec2 tex, vec3 normal
- const quint32 elementSize = 3 + 2 + 3;
+ // vec3 pos, vec2 tex, vec3 normal, vec4 tangent
+ const quint32 elementSize = 3 + 2 + 3 + 4;
const quint32 stride = elementSize * sizeof(float);
- const int nVerts = (m_slices + 1) * (m_rings + 1);
- const int faces = (m_slices * 2) * m_rings;
+ const int nVerts = vertexCount(m_rings, m_slices);
+ const int triangles = triangleCount(m_rings, m_slices);
m_positionAttribute->setName(QAttribute::defaultPositionAttributeName());
m_positionAttribute->setVertexBaseType(QAttribute::Float);
@@ -247,11 +275,20 @@ void QTorusGeometryPrivate::init()
m_normalAttribute->setByteOffset(5 * sizeof(float));
m_normalAttribute->setCount(nVerts);
+ m_tangentAttribute->setName(QAttribute::defaultTangentAttributeName());
+ m_tangentAttribute->setDataType(QAttribute::Float);
+ m_tangentAttribute->setDataSize(4);
+ m_tangentAttribute->setAttributeType(QAttribute::VertexAttribute);
+ m_tangentAttribute->setBuffer(m_vertexBuffer);
+ m_tangentAttribute->setByteStride(stride);
+ m_tangentAttribute->setByteOffset(8 * sizeof(float));
+ m_tangentAttribute->setCount(nVerts);
+
m_indexAttribute->setAttributeType(QAttribute::IndexAttribute);
m_indexAttribute->setVertexBaseType(QAttribute::UnsignedShort);
m_indexAttribute->setBuffer(m_indexBuffer);
- m_indexAttribute->setCount(faces * 3);
+ m_indexAttribute->setCount(triangles * 3);
m_vertexBuffer->setDataGenerator(QSharedPointer<TorusVertexDataFunctor>::create(m_rings, m_slices, m_radius, m_minorRadius));
m_indexBuffer->setDataGenerator(QSharedPointer<TorusIndexDataFunctor>::create(m_rings, m_slices));
@@ -259,6 +296,7 @@ void QTorusGeometryPrivate::init()
q->addAttribute(m_positionAttribute);
q->addAttribute(m_texCoordAttribute);
q->addAttribute(m_normalAttribute);
+ q->addAttribute(m_tangentAttribute);
q->addAttribute(m_indexAttribute);
}
@@ -365,7 +403,7 @@ QTorusGeometry::~QTorusGeometry()
void QTorusGeometry::updateVertices()
{
Q_D(QTorusGeometry);
- const int nVerts = d->m_slices * (d->m_rings + 1);
+ const int nVerts = vertexCount(d->m_rings, d->m_slices);
d->m_positionAttribute->setCount(nVerts);
d->m_texCoordAttribute->setCount(nVerts);
d->m_normalAttribute->setCount(nVerts);
@@ -378,10 +416,9 @@ void QTorusGeometry::updateVertices()
void QTorusGeometry::updateIndices()
{
Q_D(QTorusGeometry);
- const int faces = (d->m_slices * 2) * d->m_rings;
- d->m_indexAttribute->setCount(faces * 3);
+ const int triangles = triangleCount(d->m_rings, d->m_slices);
+ d->m_indexAttribute->setCount(triangles * 3);
d->m_indexBuffer->setDataGenerator(QSharedPointer<TorusIndexDataFunctor>::create(d->m_rings, d->m_slices));
-
}
void QTorusGeometry::setRings(int rings)
diff --git a/src/extras/geometries/qtorusgeometry_p.h b/src/extras/geometries/qtorusgeometry_p.h
index b4bcbde9f..7506a95ac 100644
--- a/src/extras/geometries/qtorusgeometry_p.h
+++ b/src/extras/geometries/qtorusgeometry_p.h
@@ -77,6 +77,7 @@ public:
Qt3DRender::QAttribute *m_positionAttribute;
Qt3DRender::QAttribute *m_normalAttribute;
Qt3DRender::QAttribute *m_texCoordAttribute;
+ Qt3DRender::QAttribute *m_tangentAttribute;
Qt3DRender::QAttribute *m_indexAttribute;
Qt3DRender::QBuffer *m_vertexBuffer;
Qt3DRender::QBuffer *m_indexBuffer;
diff --git a/src/extras/shaders/es2/light.inc.frag b/src/extras/shaders/es2/light.inc.frag
index 42a25003d..02660f008 100644
--- a/src/extras/shaders/es2/light.inc.frag
+++ b/src/extras/shaders/es2/light.inc.frag
@@ -25,9 +25,8 @@ void adsModelNormalMapped(const in FP vec3 vpos, const in FP vec3 vnormal, const
FP vec3 n = normalize( vnormal );
- int i;
FP vec3 s, ts;
- for (i = 0; i < lightCount; ++i) {
+ for (int i = 0; i < lightCount; ++i) {
FP float att = 1.0;
if ( lights[i].type != TYPE_DIRECTIONAL ) {
s = lights[i].position - vpos;
@@ -75,9 +74,8 @@ void adsModel(const in FP vec3 vpos, const in FP vec3 vnormal, const in FP vec3
FP vec3 n = normalize( vnormal );
- int i;
FP vec3 s;
- for (i = 0; i < lightCount; ++i) {
+ for (int i = 0; i < lightCount; ++i) {
FP float att = 1.0;
if ( lights[i].type != TYPE_DIRECTIONAL ) {
s = lights[i].position - vpos;
@@ -115,9 +113,8 @@ void adModel(const in FP vec3 vpos, const in FP vec3 vnormal, out FP vec3 diffus
FP vec3 n = normalize( vnormal );
- int i;
FP vec3 s;
- for (i = 0; i < lightCount; ++i) {
+ for (int i = 0; i < lightCount; ++i) {
FP float att = 1.0;
if ( lights[i].type != TYPE_DIRECTIONAL ) {
s = lights[i].position - vpos;
diff --git a/src/extras/shaders/gl3/gooch.frag b/src/extras/shaders/gl3/gooch.frag
index 1beab1c01..168a862f8 100644
--- a/src/extras/shaders/gl3/gooch.frag
+++ b/src/extras/shaders/gl3/gooch.frag
@@ -28,8 +28,7 @@ vec3 goochModel( const in vec3 pos, const in vec3 n )
vec3 kwarm = clamp(kyellow + beta * kd, 0.0, 1.0);
vec3 result = vec3(0.0);
- int i;
- for (i = 0; i < lightCount; ++i) {
+ for (int i = 0; i < lightCount; ++i) {
// Calculate the vector from the light to the fragment
vec3 s = normalize( vec3( lights[i].position ) - pos );
diff --git a/src/input/backend/axissetting_p.h b/src/input/backend/axissetting_p.h
index cd4959d69..190312bd8 100644
--- a/src/input/backend/axissetting_p.h
+++ b/src/input/backend/axissetting_p.h
@@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE
namespace Qt3DInput {
namespace Input {
-class AxisSetting : public Qt3DCore::QBackendNode
+class Q_AUTOTEST_EXPORT AxisSetting : public Qt3DCore::QBackendNode
{
public:
AxisSetting();
diff --git a/src/input/backend/qabstractphysicaldevicebackendnode.cpp b/src/input/backend/qabstractphysicaldevicebackendnode.cpp
index 86e55ec04..45f228e1a 100644
--- a/src/input/backend/qabstractphysicaldevicebackendnode.cpp
+++ b/src/input/backend/qabstractphysicaldevicebackendnode.cpp
@@ -101,8 +101,10 @@ void QAbstractPhysicalDeviceBackendNodePrivate::removeAxisSetting(Qt3DCore::QNod
{
QVector<Input::AxisIdSetting>::iterator it;
for (it = m_axisSettings.begin(); it != m_axisSettings.end(); ++it) {
- if (it->m_axisSettingsId == axisSettingsId)
+ if (it->m_axisSettingsId == axisSettingsId) {
m_axisSettings.erase(it);
+ break;
+ }
}
}
@@ -224,7 +226,6 @@ void QAbstractPhysicalDeviceBackendNode::setInputAspect(QInputAspect *aspect)
QInputAspect *QAbstractPhysicalDeviceBackendNode::inputAspect() const
{
Q_D(const QAbstractPhysicalDeviceBackendNode);
- Q_ASSERT_X(d->m_inputAspect, "QAbstractPhysicalDeviceBackendNode::inputAspect()" , "No input aspect set");
return d->m_inputAspect;
}
diff --git a/src/input/frontend/qbuttonaxisinput.cpp b/src/input/frontend/qbuttonaxisinput.cpp
index 6d95ad187..aaf1b6a1c 100644
--- a/src/input/frontend/qbuttonaxisinput.cpp
+++ b/src/input/frontend/qbuttonaxisinput.cpp
@@ -65,6 +65,8 @@ namespace Qt3DInput {
*/
/*!
\qmlproperty real ButtonAxisInput::scale
+ Specifies how the axis output value is scaled. No scaling is applied by default
+ so it defaults to 1.
*/
/*!
@@ -97,6 +99,8 @@ QButtonAxisInput::~QButtonAxisInput()
/*!
\property QButtonAxisInput::scale
+ Specifies how the axis output value is scaled. No scaling is applied by default
+ so it defaults to 1.
*/
void QButtonAxisInput::setScale(float scale)
{
diff --git a/src/input/frontend/qbuttonaxisinput_p.h b/src/input/frontend/qbuttonaxisinput_p.h
index e56e58575..849498f06 100644
--- a/src/input/frontend/qbuttonaxisinput_p.h
+++ b/src/input/frontend/qbuttonaxisinput_p.h
@@ -62,7 +62,7 @@ class QButtonAxisInputPrivate : public QAbstractAxisInputPrivate
public:
QButtonAxisInputPrivate()
: QAbstractAxisInputPrivate()
- , m_scale(0.0f)
+ , m_scale(1.0f)
, m_acceleration(-1.0f)
, m_deceleration(-1.0f)
{}
diff --git a/src/quick3d/imports/core/plugins.qmltypes b/src/quick3d/imports/core/plugins.qmltypes
index 310bfe93e..ed06f8e0c 100644
--- a/src/quick3d/imports/core/plugins.qmltypes
+++ b/src/quick3d/imports/core/plugins.qmltypes
@@ -7,7 +7,7 @@ import QtQuick.tooling 1.2
// 'qmlplugindump -nonrelocatable Qt3D.Core 2.0'
Module {
- dependencies: ["QtQuick 2.0"]
+ dependencies: ["QtQuick 2.7"]
Component {
name: "Qt3DCore::QComponent"
prototype: "Qt3DCore::QNode"
@@ -35,6 +35,7 @@ Module {
name: "enabledChanged"
Parameter { name: "enabled"; type: "bool" }
}
+ Signal { name: "nodeDestroyed" }
Method {
name: "setParent"
Parameter { name: "parent"; type: "QNode"; isPointer: true }
@@ -46,10 +47,127 @@ Module {
}
Component {
name: "Qt3DCore::QTransform"
- defaultProperty: "data"
- prototype: "Qt3DCore::QTransform"
- Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
- Property { name: "childNodes"; type: "Qt3DCore::QNode"; isList: true; isReadonly: true }
+ prototype: "Qt3DCore::QComponent"
+ exports: ["Qt3D.Core/Transform 2.0"]
+ Property { name: "matrix"; type: "QMatrix4x4" }
+ Property { name: "scale"; type: "float" }
+ Property { name: "scale3D"; type: "QVector3D" }
+ Property { name: "rotation"; type: "QQuaternion" }
+ Property { name: "translation"; type: "QVector3D" }
+ Property { name: "rotationX"; type: "float" }
+ Property { name: "rotationY"; type: "float" }
+ Property { name: "rotationZ"; type: "float" }
+ Signal {
+ name: "scaleChanged"
+ Parameter { name: "scale"; type: "float" }
+ }
+ Signal {
+ name: "scale3DChanged"
+ Parameter { name: "scale"; type: "QVector3D" }
+ }
+ Signal {
+ name: "rotationChanged"
+ Parameter { name: "rotation"; type: "QQuaternion" }
+ }
+ Signal {
+ name: "translationChanged"
+ Parameter { name: "translation"; type: "QVector3D" }
+ }
+ Signal {
+ name: "rotationXChanged"
+ Parameter { name: "rotationX"; type: "float" }
+ }
+ Signal {
+ name: "rotationYChanged"
+ Parameter { name: "rotationY"; type: "float" }
+ }
+ Signal {
+ name: "rotationZChanged"
+ Parameter { name: "rotationZ"; type: "float" }
+ }
+ Method {
+ name: "setScale"
+ Parameter { name: "scale"; type: "float" }
+ }
+ Method {
+ name: "setScale3D"
+ Parameter { name: "scale"; type: "QVector3D" }
+ }
+ Method {
+ name: "setRotation"
+ Parameter { name: "rotation"; type: "QQuaternion" }
+ }
+ Method {
+ name: "setTranslation"
+ Parameter { name: "translation"; type: "QVector3D" }
+ }
+ Method {
+ name: "setMatrix"
+ Parameter { name: "matrix"; type: "QMatrix4x4" }
+ }
+ Method {
+ name: "setRotationX"
+ Parameter { name: "rotationX"; type: "float" }
+ }
+ Method {
+ name: "setRotationY"
+ Parameter { name: "rotationY"; type: "float" }
+ }
+ Method {
+ name: "setRotationZ"
+ Parameter { name: "rotationZ"; type: "float" }
+ }
+ Method {
+ name: "fromAxisAndAngle"
+ type: "QQuaternion"
+ Parameter { name: "axis"; type: "QVector3D" }
+ Parameter { name: "angle"; type: "float" }
+ }
+ Method {
+ name: "fromAxisAndAngle"
+ type: "QQuaternion"
+ Parameter { name: "x"; type: "float" }
+ Parameter { name: "y"; type: "float" }
+ Parameter { name: "z"; type: "float" }
+ Parameter { name: "angle"; type: "float" }
+ }
+ Method {
+ name: "fromAxesAndAngles"
+ type: "QQuaternion"
+ Parameter { name: "axis1"; type: "QVector3D" }
+ Parameter { name: "angle1"; type: "float" }
+ Parameter { name: "axis2"; type: "QVector3D" }
+ Parameter { name: "angle2"; type: "float" }
+ }
+ Method {
+ name: "fromAxesAndAngles"
+ type: "QQuaternion"
+ Parameter { name: "axis1"; type: "QVector3D" }
+ Parameter { name: "angle1"; type: "float" }
+ Parameter { name: "axis2"; type: "QVector3D" }
+ Parameter { name: "angle2"; type: "float" }
+ Parameter { name: "axis3"; type: "QVector3D" }
+ Parameter { name: "angle3"; type: "float" }
+ }
+ Method {
+ name: "fromEulerAngles"
+ type: "QQuaternion"
+ Parameter { name: "eulerAngles"; type: "QVector3D" }
+ }
+ Method {
+ name: "fromEulerAngles"
+ type: "QQuaternion"
+ Parameter { name: "pitch"; type: "float" }
+ Parameter { name: "yaw"; type: "float" }
+ Parameter { name: "roll"; type: "float" }
+ }
+ Method {
+ name: "rotateAround"
+ type: "QMatrix4x4"
+ Parameter { name: "point"; type: "QVector3D" }
+ Parameter { name: "angle"; type: "float" }
+ Parameter { name: "axis"; type: "QVector3D" }
+ }
}
Component {
name: "Qt3DCore::Quick::QQuaternionAnimation"
@@ -112,8 +230,10 @@ Module {
Component {
name: "Qt3DCore::Quick::Quick3DEntityLoader"
defaultProperty: "data"
- prototype: "Qt3DCore::Quick::Quick3DEntityLoader"
- Property { name: "components"; type: "Qt3DCore::QComponent"; isList: true; isReadonly: true }
+ prototype: "Qt3DCore::QEntity"
+ exports: ["Qt3D.Core/EntityLoader 2.0"]
+ Property { name: "entity"; type: "Qt3DCore::QEntity"; isPointer: true; isReadonly: true }
+ Property { name: "source"; type: "QUrl" }
}
Component {
name: "Qt3DCore::Quick::Quick3DNode"
@@ -128,8 +248,13 @@ Module {
Component {
name: "Qt3DCore::Quick::Quick3DNodeInstantiator"
defaultProperty: "delegate"
- prototype: "Qt3DCore::Quick::Quick3DNodeInstantiator"
- Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
- Property { name: "childNodes"; type: "Qt3DCore::QNode"; isList: true; isReadonly: true }
+ prototype: "Qt3DCore::QNode"
+ exports: ["Qt3D.Core/NodeInstantiator 2.0"]
+ Property { name: "active"; type: "bool" }
+ Property { name: "asynchronous"; type: "bool" }
+ Property { name: "model"; type: "QVariant" }
+ Property { name: "count"; type: "int"; isReadonly: true }
+ Property { name: "delegate"; type: "QQmlComponent" }
+ Property { name: "object"; type: "QObject"; isReadonly: true }
}
}
diff --git a/src/quick3d/imports/extras/defaults/qml/SkyboxEntity.qml b/src/quick3d/imports/extras/defaults/qml/SkyboxEntity.qml
index 45cef47b7..00bff6f10 100644
--- a/src/quick3d/imports/extras/defaults/qml/SkyboxEntity.qml
+++ b/src/quick3d/imports/extras/defaults/qml/SkyboxEntity.qml
@@ -53,12 +53,12 @@ Entity {
x: WrapMode.ClampToEdge
y: WrapMode.ClampToEdge
}
- TextureImage { face: Texture.CubeMapPositiveX; source: baseName + "_posx" + extension }
- TextureImage { face: Texture.CubeMapPositiveY; source: baseName + "_posy" + extension }
- TextureImage { face: Texture.CubeMapPositiveZ; source: baseName + "_posz" + extension }
- TextureImage { face: Texture.CubeMapNegativeX; source: baseName + "_negx" + extension }
- TextureImage { face: Texture.CubeMapNegativeY; source: baseName + "_negy" + extension }
- TextureImage { face: Texture.CubeMapNegativeZ; source: baseName + "_negz" + extension }
+ TextureImage { mirrored: false; face: Texture.CubeMapPositiveX; source: baseName + "_posx" + extension }
+ TextureImage { mirrored: false; face: Texture.CubeMapPositiveY; source: baseName + "_posy" + extension }
+ TextureImage { mirrored: false; face: Texture.CubeMapPositiveZ; source: baseName + "_posz" + extension }
+ TextureImage { mirrored: false; face: Texture.CubeMapNegativeX; source: baseName + "_negx" + extension }
+ TextureImage { mirrored: false; face: Texture.CubeMapNegativeY; source: baseName + "_negy" + extension }
+ TextureImage { mirrored: false; face: Texture.CubeMapNegativeZ; source: baseName + "_negz" + extension }
}
ShaderProgram {
diff --git a/src/quick3d/imports/extras/plugins.qmltypes b/src/quick3d/imports/extras/plugins.qmltypes
index d30b2591a..6a7e1203d 100644
--- a/src/quick3d/imports/extras/plugins.qmltypes
+++ b/src/quick3d/imports/extras/plugins.qmltypes
@@ -762,6 +762,14 @@ Module {
name: "setBoundingVolumePositionAttribute"
Parameter { name: "boundingVolumePositionAttribute"; type: "QAttribute"; isPointer: true }
}
+ Method {
+ name: "addAttribute"
+ Parameter { name: "attribute"; type: "Qt3DRender::QAttribute"; isPointer: true }
+ }
+ Method {
+ name: "removeAttribute"
+ Parameter { name: "attribute"; type: "Qt3DRender::QAttribute"; isPointer: true }
+ }
}
Component {
name: "Qt3DRender::QGeometryRenderer"
@@ -787,6 +795,7 @@ Module {
Property { name: "vertexCount"; type: "int" }
Property { name: "indexOffset"; type: "int" }
Property { name: "firstInstance"; type: "int" }
+ Property { name: "firstVertex"; type: "int" }
Property { name: "restartIndexValue"; type: "int" }
Property { name: "verticesPerPatch"; type: "int" }
Property { name: "primitiveRestartEnabled"; type: "bool" }
@@ -809,6 +818,10 @@ Module {
Parameter { name: "firstInstance"; type: "int" }
}
Signal {
+ name: "firstVertexChanged"
+ Parameter { name: "firstVertex"; type: "int" }
+ }
+ Signal {
name: "restartIndexValueChanged"
Parameter { name: "restartIndexValue"; type: "int" }
}
@@ -845,6 +858,10 @@ Module {
Parameter { name: "firstInstance"; type: "int" }
}
Method {
+ name: "setFirstVertex"
+ Parameter { name: "firstVertex"; type: "int" }
+ }
+ Method {
name: "setRestartIndexValue"
Parameter { name: "index"; type: "int" }
}
@@ -866,6 +883,35 @@ Module {
}
}
Component {
+ prototype: "Qt3DCore::QNode"
+ name: "Qt3D.Extras/DefaultAlphaEffect 2.0"
+ exports: ["Qt3D.Extras/DefaultAlphaEffect 2.0"]
+ exportMetaObjectRevisions: [0]
+ isComposite: true
+ defaultProperty: "data"
+ Property { name: "vertexES"; type: "string" }
+ Property { name: "fragmentES"; type: "string" }
+ Property { name: "vertex"; type: "string" }
+ Property { name: "fragment"; type: "string" }
+ Property { name: "sourceRgbArg"; type: "int" }
+ Property { name: "destinationRgbArg"; type: "int" }
+ Property { name: "sourceAlphaArg"; type: "int" }
+ Property { name: "destinationAlphaArg"; type: "int" }
+ Property { name: "blendFunctionArg"; type: "int" }
+ }
+ Component {
+ prototype: "Qt3DCore::QNode"
+ name: "Qt3D.Extras/DefaultEffect 2.0"
+ exports: ["Qt3D.Extras/DefaultEffect 2.0"]
+ exportMetaObjectRevisions: [0]
+ isComposite: true
+ defaultProperty: "data"
+ Property { name: "vertexES"; type: "string" }
+ Property { name: "fragmentES"; type: "string" }
+ Property { name: "vertex"; type: "string" }
+ Property { name: "fragment"; type: "string" }
+ }
+ Component {
prototype: "Qt3DCore::QComponent"
name: "Qt3D.Extras/DiffuseMapMaterial 2.0"
exports: ["Qt3D.Extras/DiffuseMapMaterial 2.0"]
@@ -919,6 +965,8 @@ Module {
Property { name: "camera"; type: "Qt3DRender::QCamera"; isPointer: true }
Property { name: "linearSpeed"; type: "double" }
Property { name: "lookSpeed"; type: "double" }
+ Property { name: "acceleration"; type: "double" }
+ Property { name: "deceleration"; type: "double" }
}
Component {
prototype: "Qt3DCore::QNode"
@@ -957,6 +1005,18 @@ Module {
}
}
Component {
+ prototype: "Qt3DCore::QNode"
+ name: "Qt3D.Extras/NormalDiffuseMapAlphaEffect 2.0"
+ exports: ["Qt3D.Extras/NormalDiffuseMapAlphaEffect 2.0"]
+ exportMetaObjectRevisions: [0]
+ isComposite: true
+ defaultProperty: "data"
+ Property { name: "vertexES"; type: "string" }
+ Property { name: "fragmentES"; type: "string" }
+ Property { name: "vertex"; type: "string" }
+ Property { name: "fragment"; type: "string" }
+ }
+ Component {
prototype: "Qt3DCore::QComponent"
name: "Qt3D.Extras/NormalDiffuseMapAlphaMaterial 2.0"
exports: ["Qt3D.Extras/NormalDiffuseMapAlphaMaterial 2.0"]
@@ -1027,8 +1087,8 @@ Module {
}
Component {
prototype: "Qt3DCore::QNode"
- name: "Qt3D.Extras/OrbitController 2.0"
- exports: ["Qt3D.Extras/OrbitController 2.0"]
+ name: "Qt3D.Extras/OrbitCameraController 2.0"
+ exports: ["Qt3D.Extras/OrbitCameraController 2.0"]
exportMetaObjectRevisions: [0]
isComposite: true
defaultProperty: "data"
@@ -1078,6 +1138,11 @@ Module {
Property { name: "specular"; type: "QColor" }
Property { name: "shininess"; type: "double" }
Property { name: "alpha"; type: "double" }
+ Property { name: "sourceRgbArg"; type: "int" }
+ Property { name: "destinationRgbArg"; type: "int" }
+ Property { name: "sourceAlphaArg"; type: "int" }
+ Property { name: "destinationAlphaArg"; type: "int" }
+ Property { name: "blendFunctionArg"; type: "int" }
Property { name: "effect"; type: "Qt3DRender::QEffect"; isPointer: true }
Signal {
name: "effectChanged"
@@ -1110,15 +1175,22 @@ Module {
}
}
Component {
- prototype: "Qt3DCore::QNode"
- name: "Qt3D.Extras/SkyboxEntity 2.0"
- exports: ["Qt3D.Extras/SkyboxEntity 2.0"]
+ prototype: "Qt3DCore::QComponent"
+ name: "Qt3D.Extras/TextureMaterial 2.0"
+ exports: ["Qt3D.Extras/TextureMaterial 2.0"]
exportMetaObjectRevisions: [0]
isComposite: true
defaultProperty: "data"
- Property { name: "baseName"; type: "string" }
- Property { name: "extension"; type: "string" }
- Property { name: "skyboxTexture"; type: "Qt3DRender::QTextureCubeMap"; isPointer: true }
- Property { name: "cameraPosition"; type: "QVector3D" }
+ Property { name: "texture"; type: "Qt3DRender::QTexture2D"; isPointer: true }
+ Property { name: "textureOffset"; type: "QVector2D" }
+ Property { name: "effect"; type: "Qt3DRender::QEffect"; isPointer: true }
+ Signal {
+ name: "effectChanged"
+ Parameter { name: "effect"; type: "QEffect"; isPointer: true }
+ }
+ Method {
+ name: "setEffect"
+ Parameter { name: "effect"; type: "QEffect"; isPointer: true }
+ }
}
}
diff --git a/src/quick3d/imports/input/plugins.qmltypes b/src/quick3d/imports/input/plugins.qmltypes
index 68ff9fe32..860ab4d68 100644
--- a/src/quick3d/imports/input/plugins.qmltypes
+++ b/src/quick3d/imports/input/plugins.qmltypes
@@ -7,7 +7,7 @@ import QtQuick.tooling 1.2
// 'qmlplugindump -nonrelocatable Qt3D.Input 2.0'
Module {
- dependencies: ["QtQuick 2.0"]
+ dependencies: ["QtQuick 2.7"]
Component {
name: "Qt3DCore::QComponent"
prototype: "Qt3DCore::QNode"
@@ -34,6 +34,7 @@ Module {
name: "enabledChanged"
Parameter { name: "enabled"; type: "bool" }
}
+ Signal { name: "nodeDestroyed" }
Method {
name: "setParent"
Parameter { name: "parent"; type: "QNode"; isPointer: true }
@@ -100,7 +101,6 @@ Module {
name: "Qt3DInput::Input::Quick::Quick3DPhysicalDevice"
prototype: "Qt3DInput::QAbstractPhysicalDevice"
exports: ["Qt3D.Input/QAbstractPhysicalDevice 2.0"]
- isCreatable: false
exportMetaObjectRevisions: [0]
Property { name: "axisSettings"; type: "Qt3DInput::QAxisSetting"; isList: true; isReadonly: true }
}
@@ -262,8 +262,8 @@ Module {
}
Component {
name: "Qt3DInput::QGamepadInput"
- prototype: "Qt3DInput::QAbstractPhysicalDevice"
- Property { name: "deviceId"; type: "int" }
+ prototype: "Qt3DInput::QGamepadInput"
+ Property { name: "axisSettings"; type: "Qt3DInput::QAxisSetting"; isList: true; isReadonly: true }
}
Component {
name: "Qt3DInput::QInputChord"
@@ -336,8 +336,18 @@ Module {
}
Component {
name: "Qt3DInput::QKeyboardDevice"
- prototype: "Qt3DInput::QKeyboardDevice"
- Property { name: "axisSettings"; type: "Qt3DInput::QAxisSetting"; isList: true; isReadonly: true }
+ prototype: "Qt3DInput::QAbstractPhysicalDevice"
+ exports: ["Qt3D.Input/KeyboardDevice 2.0"]
+ Property {
+ name: "activeInput"
+ type: "Qt3DInput::QKeyboardHandler"
+ isReadonly: true
+ isPointer: true
+ }
+ Signal {
+ name: "activeInputChanged"
+ Parameter { name: "activeInput"; type: "QKeyboardHandler"; isPointer: true }
+ }
}
Component {
name: "Qt3DInput::QKeyboardHandler"
@@ -526,8 +536,24 @@ Module {
Component { name: "Qt3DInput::QLogicalDevice"; prototype: "Qt3DCore::QComponent" }
Component {
name: "Qt3DInput::QMouseDevice"
- prototype: "Qt3DInput::QMouseDevice"
- Property { name: "axisSettings"; type: "Qt3DInput::QAxisSetting"; isList: true; isReadonly: true }
+ prototype: "Qt3DInput::QAbstractPhysicalDevice"
+ exports: ["Qt3D.Input/MouseDevice 2.0"]
+ Enum {
+ name: "Axis"
+ values: {
+ "X": 0,
+ "Y": 1
+ }
+ }
+ Property { name: "sensitivity"; type: "float" }
+ Signal {
+ name: "sensitivityChanged"
+ Parameter { name: "value"; type: "float" }
+ }
+ Method {
+ name: "setSensitivity"
+ Parameter { name: "value"; type: "float" }
+ }
}
Component {
name: "Qt3DInput::QMouseEvent"
diff --git a/src/quick3d/imports/logic/plugins.qmltypes b/src/quick3d/imports/logic/plugins.qmltypes
index 036ca96f3..0c0ccc847 100644
--- a/src/quick3d/imports/logic/plugins.qmltypes
+++ b/src/quick3d/imports/logic/plugins.qmltypes
@@ -7,7 +7,7 @@ import QtQuick.tooling 1.2
// 'qmlplugindump -nonrelocatable Qt3D.Logic 2.0'
Module {
- dependencies: ["QtQuick 2.0"]
+ dependencies: ["QtQuick 2.7"]
Component {
name: "Qt3DCore::QComponent"
prototype: "Qt3DCore::QNode"
@@ -34,6 +34,7 @@ Module {
name: "enabledChanged"
Parameter { name: "enabled"; type: "bool" }
}
+ Signal { name: "nodeDestroyed" }
Method {
name: "setParent"
Parameter { name: "parent"; type: "QNode"; isPointer: true }
diff --git a/src/quick3d/imports/render/plugins.qmltypes b/src/quick3d/imports/render/plugins.qmltypes
index af491af6c..a6528daed 100644
--- a/src/quick3d/imports/render/plugins.qmltypes
+++ b/src/quick3d/imports/render/plugins.qmltypes
@@ -7,7 +7,7 @@ import QtQuick.tooling 1.2
// 'qmlplugindump -nonrelocatable Qt3D.Render 2.0'
Module {
- dependencies: ["Qt3D.Core 2.0"]
+ dependencies: ["QtQuick 2.7"]
Component {
name: "QWindow"
prototype: "QObject"
@@ -171,22 +171,380 @@ Module {
Method { name: "requestUpdate"; revision: 3 }
}
Component {
- name: "Qt3DRender::QAbstractLight"
+ name: "Qt3DCore::QComponent"
+ prototype: "Qt3DCore::QNode"
+ Property { name: "isShareable"; type: "bool" }
+ Signal {
+ name: "shareableChanged"
+ Parameter { name: "isShareable"; type: "bool" }
+ }
+ Method {
+ name: "setShareable"
+ Parameter { name: "isShareable"; type: "bool" }
+ }
+ }
+ Component { name: "Qt3DCore::QEntity"; prototype: "Qt3DCore::QNode" }
+ Component {
+ name: "Qt3DCore::QNode"
+ prototype: "QObject"
+ Property { name: "parent"; type: "Qt3DCore::QNode"; isPointer: true }
+ Property { name: "enabled"; type: "bool" }
+ Signal {
+ name: "parentChanged"
+ Parameter { name: "parent"; type: "QObject"; isPointer: true }
+ }
+ Signal {
+ name: "enabledChanged"
+ Parameter { name: "enabled"; type: "bool" }
+ }
+ Signal { name: "nodeDestroyed" }
+ Method {
+ name: "setParent"
+ Parameter { name: "parent"; type: "QNode"; isPointer: true }
+ }
+ Method {
+ name: "setEnabled"
+ Parameter { name: "isEnabled"; type: "bool" }
+ }
+ }
+ Component {
+ name: "Qt3DCore::Quick::Quick3DNode"
defaultProperty: "data"
- prototype: "Qt3DRender::QAbstractLight"
+ prototype: "Qt3DRender::QCameraSelector"
+ exports: ["Qt3D.Render/CameraSelector 2.0"]
+ exportMetaObjectRevisions: [0]
Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
Property { name: "childNodes"; type: "Qt3DCore::QNode"; isList: true; isReadonly: true }
}
Component {
+ name: "Qt3DRender::QAbstractLight"
+ prototype: "Qt3DCore::QComponent"
+ exports: ["Qt3D.Render/Light 2.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ Enum {
+ name: "Type"
+ values: {
+ "PointLight": 0,
+ "DirectionalLight": 1,
+ "SpotLight": 2
+ }
+ }
+ Property { name: "type"; type: "Type"; isReadonly: true }
+ Property { name: "color"; type: "QColor" }
+ Property { name: "intensity"; type: "float" }
+ Signal {
+ name: "colorChanged"
+ Parameter { name: "color"; type: "QColor" }
+ }
+ Signal {
+ name: "intensityChanged"
+ Parameter { name: "intensity"; type: "float" }
+ }
+ Method {
+ name: "setColor"
+ Parameter { name: "color"; type: "QColor" }
+ }
+ Method {
+ name: "setIntensity"
+ Parameter { name: "intensity"; type: "float" }
+ }
+ }
+ Component {
name: "Qt3DRender::QAbstractTexture"
- defaultProperty: "data"
- prototype: "Qt3DRender::QAbstractTexture"
- Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
- Property { name: "childNodes"; type: "Qt3DCore::QNode"; isList: true; isReadonly: true }
+ prototype: "Qt3DCore::QNode"
+ exports: ["Qt3D.Render/Texture 2.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ Enum {
+ name: "Status"
+ values: {
+ "None": 0,
+ "Loading": 1,
+ "Ready": 2,
+ "Error": 3
+ }
+ }
+ Enum {
+ name: "Target"
+ values: {
+ "TargetAutomatic": 0,
+ "Target1D": 3552,
+ "Target1DArray": 35864,
+ "Target2D": 3553,
+ "Target2DArray": 35866,
+ "Target3D": 32879,
+ "TargetCubeMap": 34067,
+ "TargetCubeMapArray": 36873,
+ "Target2DMultisample": 37120,
+ "Target2DMultisampleArray": 37122,
+ "TargetRectangle": 34037,
+ "TargetBuffer": 35882
+ }
+ }
+ Enum {
+ name: "TextureFormat"
+ values: {
+ "NoFormat": 0,
+ "Automatic": 1,
+ "R8_UNorm": 33321,
+ "RG8_UNorm": 33323,
+ "RGB8_UNorm": 32849,
+ "RGBA8_UNorm": 32856,
+ "R16_UNorm": 33322,
+ "RG16_UNorm": 33324,
+ "RGB16_UNorm": 32852,
+ "RGBA16_UNorm": 32859,
+ "R8_SNorm": 36756,
+ "RG8_SNorm": 36757,
+ "RGB8_SNorm": 36758,
+ "RGBA8_SNorm": 36759,
+ "R16_SNorm": 36760,
+ "RG16_SNorm": 36761,
+ "RGB16_SNorm": 36762,
+ "RGBA16_SNorm": 36763,
+ "R8U": 33330,
+ "RG8U": 33336,
+ "RGB8U": 36221,
+ "RGBA8U": 36220,
+ "R16U": 33332,
+ "RG16U": 33338,
+ "RGB16U": 36215,
+ "RGBA16U": 36214,
+ "R32U": 33334,
+ "RG32U": 33340,
+ "RGB32U": 36209,
+ "RGBA32U": 36208,
+ "R8I": 33329,
+ "RG8I": 33335,
+ "RGB8I": 36239,
+ "RGBA8I": 36238,
+ "R16I": 33331,
+ "RG16I": 33337,
+ "RGB16I": 36233,
+ "RGBA16I": 36232,
+ "R32I": 33333,
+ "RG32I": 33339,
+ "RGB32I": 36227,
+ "RGBA32I": 36226,
+ "R16F": 33325,
+ "RG16F": 33327,
+ "RGB16F": 34843,
+ "RGBA16F": 34842,
+ "R32F": 33326,
+ "RG32F": 33328,
+ "RGB32F": 34837,
+ "RGBA32F": 34836,
+ "RGB9E5": 35901,
+ "RG11B10F": 35898,
+ "RG3B2": 10768,
+ "R5G6B5": 36194,
+ "RGB5A1": 32855,
+ "RGBA4": 32854,
+ "RGB10A2": 36975,
+ "D16": 33189,
+ "D24": 33190,
+ "D24S8": 35056,
+ "D32": 33191,
+ "D32F": 36012,
+ "D32FS8X24": 36013,
+ "RGB_DXT1": 33776,
+ "RGBA_DXT1": 33777,
+ "RGBA_DXT3": 33778,
+ "RGBA_DXT5": 33779,
+ "R_ATI1N_UNorm": 36283,
+ "R_ATI1N_SNorm": 36284,
+ "RG_ATI2N_UNorm": 36285,
+ "RG_ATI2N_SNorm": 36286,
+ "RGB_BP_UNSIGNED_FLOAT": 36495,
+ "RGB_BP_SIGNED_FLOAT": 36494,
+ "RGB_BP_UNorm": 36492,
+ "R11_EAC_UNorm": 37488,
+ "R11_EAC_SNorm": 37489,
+ "RG11_EAC_UNorm": 37490,
+ "RG11_EAC_SNorm": 37491,
+ "RGB8_ETC2": 37492,
+ "SRGB8_ETC2": 37493,
+ "RGB8_PunchThrough_Alpha1_ETC2": 37494,
+ "SRGB8_PunchThrough_Alpha1_ETC2": 37495,
+ "RGBA8_ETC2_EAC": 37496,
+ "SRGB8_Alpha8_ETC2_EAC": 37497,
+ "RGB8_ETC1": 36196,
+ "SRGB8": 35905,
+ "SRGB8_Alpha8": 35907,
+ "SRGB_DXT1": 35916,
+ "SRGB_Alpha_DXT1": 35917,
+ "SRGB_Alpha_DXT3": 35918,
+ "SRGB_Alpha_DXT5": 35919,
+ "SRGB_BP_UNorm": 36493,
+ "DepthFormat": 6402,
+ "AlphaFormat": 6406,
+ "RGBFormat": 6407,
+ "RGBAFormat": 6408,
+ "LuminanceFormat": 6409,
+ "LuminanceAlphaFormat": 6410
+ }
+ }
+ Enum {
+ name: "Filter"
+ values: {
+ "Nearest": 9728,
+ "Linear": 9729,
+ "NearestMipMapNearest": 9984,
+ "NearestMipMapLinear": 9986,
+ "LinearMipMapNearest": 9985,
+ "LinearMipMapLinear": 9987
+ }
+ }
+ Enum {
+ name: "CubeMapFace"
+ values: {
+ "CubeMapPositiveX": 34069,
+ "CubeMapNegativeX": 34070,
+ "CubeMapPositiveY": 34071,
+ "CubeMapNegativeY": 34072,
+ "CubeMapPositiveZ": 34073,
+ "CubeMapNegativeZ": 34074
+ }
+ }
+ Enum {
+ name: "ComparisonFunction"
+ values: {
+ "CompareLessEqual": 515,
+ "CompareGreaterEqual": 518,
+ "CompareLess": 513,
+ "CompareGreater": 516,
+ "CompareEqual": 514,
+ "CommpareNotEqual": 517,
+ "CompareAlways": 519,
+ "CompareNever": 512
+ }
+ }
+ Enum {
+ name: "ComparisonMode"
+ values: {
+ "CompareRefToTexture": 34894,
+ "CompareNone": 0
+ }
+ }
+ Property { name: "target"; type: "Target"; isReadonly: true }
+ Property { name: "format"; type: "TextureFormat" }
+ Property { name: "generateMipMaps"; type: "bool" }
+ Property {
+ name: "wrapMode"
+ type: "Qt3DRender::QTextureWrapMode"
+ isReadonly: true
+ isPointer: true
+ }
+ Property { name: "status"; type: "Status"; isReadonly: true }
+ Property { name: "width"; type: "int" }
+ Property { name: "height"; type: "int" }
+ Property { name: "depth"; type: "int" }
+ Property { name: "magnificationFilter"; type: "Filter" }
+ Property { name: "minificationFilter"; type: "Filter" }
+ Property { name: "maximumAnisotropy"; type: "float" }
+ Property { name: "comparisonFunction"; type: "ComparisonFunction" }
+ Property { name: "comparisonMode"; type: "ComparisonMode" }
+ Property { name: "layers"; type: "int" }
+ Signal {
+ name: "formatChanged"
+ Parameter { name: "format"; type: "TextureFormat" }
+ }
+ Signal {
+ name: "statusChanged"
+ Parameter { name: "status"; type: "Status" }
+ }
+ Signal {
+ name: "generateMipMapsChanged"
+ Parameter { name: "generateMipMaps"; type: "bool" }
+ }
+ Signal {
+ name: "widthChanged"
+ Parameter { name: "width"; type: "int" }
+ }
+ Signal {
+ name: "heightChanged"
+ Parameter { name: "height"; type: "int" }
+ }
+ Signal {
+ name: "depthChanged"
+ Parameter { name: "depth"; type: "int" }
+ }
+ Signal {
+ name: "magnificationFilterChanged"
+ Parameter { name: "magnificationFilter"; type: "Filter" }
+ }
+ Signal {
+ name: "minificationFilterChanged"
+ Parameter { name: "minificationFilter"; type: "Filter" }
+ }
+ Signal {
+ name: "maximumAnisotropyChanged"
+ Parameter { name: "maximumAnisotropy"; type: "float" }
+ }
+ Signal {
+ name: "comparisonFunctionChanged"
+ Parameter { name: "comparisonFunction"; type: "ComparisonFunction" }
+ }
+ Signal {
+ name: "comparisonModeChanged"
+ Parameter { name: "comparisonMode"; type: "ComparisonMode" }
+ }
+ Signal {
+ name: "layersChanged"
+ Parameter { name: "layers"; type: "int" }
+ }
+ Method {
+ name: "setFormat"
+ Parameter { name: "format"; type: "TextureFormat" }
+ }
+ Method {
+ name: "setGenerateMipMaps"
+ Parameter { name: "gen"; type: "bool" }
+ }
+ Method {
+ name: "setWidth"
+ Parameter { name: "width"; type: "int" }
+ }
+ Method {
+ name: "setHeight"
+ Parameter { name: "height"; type: "int" }
+ }
+ Method {
+ name: "setDepth"
+ Parameter { name: "depth"; type: "int" }
+ }
+ Method {
+ name: "setMinificationFilter"
+ Parameter { name: "f"; type: "Filter" }
+ }
+ Method {
+ name: "setMagnificationFilter"
+ Parameter { name: "f"; type: "Filter" }
+ }
+ Method {
+ name: "setMaximumAnisotropy"
+ Parameter { name: "anisotropy"; type: "float" }
+ }
+ Method {
+ name: "setComparisonFunction"
+ Parameter { name: "function"; type: "ComparisonFunction" }
+ }
+ Method {
+ name: "setComparisonMode"
+ Parameter { name: "mode"; type: "ComparisonMode" }
+ }
+ Method {
+ name: "setLayers"
+ Parameter { name: "layers"; type: "int" }
+ }
}
Component {
name: "Qt3DRender::QAbstractTextureImage"
prototype: "Qt3DCore::QNode"
+ exports: ["Qt3D.Render/QAbstractTextureImage 2.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
Property { name: "mipLevel"; type: "int" }
Property { name: "layer"; type: "int" }
Property { name: "face"; type: "Qt3DRender::QAbstractTexture::CubeMapFace" }
@@ -215,10 +573,17 @@ Module {
Parameter { name: "face"; type: "QAbstractTexture::CubeMapFace" }
}
}
- Component { name: "Qt3DRender::QAlphaCoverage"; prototype: "Qt3DRender::QRenderState" }
+ Component {
+ name: "Qt3DRender::QAlphaCoverage"
+ prototype: "Qt3DRender::QRenderState"
+ exports: ["Qt3D.Render/AlphaCoverage 2.0"]
+ exportMetaObjectRevisions: [0]
+ }
Component {
name: "Qt3DRender::QAlphaTest"
prototype: "Qt3DRender::QRenderState"
+ exports: ["Qt3D.Render/AlphaTest 2.0"]
+ exportMetaObjectRevisions: [0]
Enum {
name: "AlphaFunction"
values: {
@@ -253,14 +618,122 @@ Module {
}
Component {
name: "Qt3DRender::QAttribute"
- defaultProperty: "data"
- prototype: "Qt3DRender::QAttribute"
- Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
- Property { name: "childNodes"; type: "Qt3DCore::QNode"; isList: true; isReadonly: true }
+ prototype: "Qt3DCore::QNode"
+ exports: ["Qt3D.Render/Attribute 2.0"]
+ exportMetaObjectRevisions: [0]
+ Enum {
+ name: "AttributeType"
+ values: {
+ "VertexAttribute": 0,
+ "IndexAttribute": 1
+ }
+ }
+ Enum {
+ name: "VertexBaseType"
+ values: {
+ "Byte": 0,
+ "UnsignedByte": 1,
+ "Short": 2,
+ "UnsignedShort": 3,
+ "Int": 4,
+ "UnsignedInt": 5,
+ "HalfFloat": 6,
+ "Float": 7,
+ "Double": 8
+ }
+ }
+ Property { name: "buffer"; type: "Qt3DRender::QBuffer"; isPointer: true }
+ Property { name: "name"; type: "string" }
+ Property { name: "vertexBaseType"; type: "VertexBaseType" }
+ Property { name: "vertexSize"; type: "uint" }
+ Property { name: "count"; type: "uint" }
+ Property { name: "byteStride"; type: "uint" }
+ Property { name: "byteOffset"; type: "uint" }
+ Property { name: "divisor"; type: "uint" }
+ Property { name: "attributeType"; type: "AttributeType" }
+ Signal {
+ name: "bufferChanged"
+ Parameter { name: "buffer"; type: "QBuffer"; isPointer: true }
+ }
+ Signal {
+ name: "nameChanged"
+ Parameter { name: "name"; type: "string" }
+ }
+ Signal {
+ name: "dataTypeChanged"
+ Parameter { name: "vertexBaseType"; type: "VertexBaseType" }
+ }
+ Signal {
+ name: "dataSizeChanged"
+ Parameter { name: "vertexSize"; type: "uint" }
+ }
+ Signal {
+ name: "countChanged"
+ Parameter { name: "count"; type: "uint" }
+ }
+ Signal {
+ name: "byteStrideChanged"
+ Parameter { name: "byteStride"; type: "uint" }
+ }
+ Signal {
+ name: "byteOffsetChanged"
+ Parameter { name: "byteOffset"; type: "uint" }
+ }
+ Signal {
+ name: "divisorChanged"
+ Parameter { name: "divisor"; type: "uint" }
+ }
+ Signal {
+ name: "attributeTypeChanged"
+ Parameter { name: "attributeType"; type: "AttributeType" }
+ }
+ Method {
+ name: "setBuffer"
+ Parameter { name: "buffer"; type: "QBuffer"; isPointer: true }
+ }
+ Method {
+ name: "setName"
+ Parameter { name: "name"; type: "string" }
+ }
+ Method {
+ name: "setDataType"
+ Parameter { name: "type"; type: "VertexBaseType" }
+ }
+ Method {
+ name: "setDataSize"
+ Parameter { name: "size"; type: "uint" }
+ }
+ Method {
+ name: "setCount"
+ Parameter { name: "count"; type: "uint" }
+ }
+ Method {
+ name: "setByteStride"
+ Parameter { name: "byteStride"; type: "uint" }
+ }
+ Method {
+ name: "setByteOffset"
+ Parameter { name: "byteOffset"; type: "uint" }
+ }
+ Method {
+ name: "setDivisor"
+ Parameter { name: "divisor"; type: "uint" }
+ }
+ Method {
+ name: "setAttributeType"
+ Parameter { name: "attributeType"; type: "AttributeType" }
+ }
+ Method { name: "defaultPositionAttributeName"; type: "string" }
+ Method { name: "defaultNormalAttributeName"; type: "string" }
+ Method { name: "defaultColorAttributeName"; type: "string" }
+ Method { name: "defaultTextureCoordinateAttributeName"; type: "string" }
+ Method { name: "defaultTangentAttributeName"; type: "string" }
}
Component {
name: "Qt3DRender::QBlendEquation"
prototype: "Qt3DRender::QRenderState"
+ exports: ["Qt3D.Render/BlendEquation 2.0"]
+ exportMetaObjectRevisions: [0]
Enum {
name: "BlendFunction"
values: {
@@ -284,6 +757,8 @@ Module {
Component {
name: "Qt3DRender::QBlendEquationArguments"
prototype: "Qt3DRender::QRenderState"
+ exports: ["Qt3D.Render/BlendEquationArguments 2.0"]
+ exportMetaObjectRevisions: [0]
Enum {
name: "Blending"
values: {
@@ -432,13 +907,226 @@ Module {
}
Component {
name: "Qt3DRender::QCamera"
- defaultProperty: "data"
- prototype: "Qt3DRender::QCamera"
- Property { name: "components"; type: "Qt3DCore::QComponent"; isList: true; isReadonly: true }
+ prototype: "Qt3DCore::QEntity"
+ exports: ["Qt3D.Render/Camera 2.0"]
+ exportMetaObjectRevisions: [0]
+ Enum {
+ name: "CameraTranslationOption"
+ values: {
+ "TranslateViewCenter": 0,
+ "DontTranslateViewCenter": 1
+ }
+ }
+ Property { name: "projectionType"; type: "Qt3DRender::QCameraLens::ProjectionType" }
+ Property { name: "nearPlane"; type: "float" }
+ Property { name: "farPlane"; type: "float" }
+ Property { name: "fieldOfView"; type: "float" }
+ Property { name: "aspectRatio"; type: "float" }
+ Property { name: "left"; type: "float" }
+ Property { name: "right"; type: "float" }
+ Property { name: "bottom"; type: "float" }
+ Property { name: "top"; type: "float" }
+ Property { name: "projectionMatrix"; type: "QMatrix4x4" }
+ Property { name: "position"; type: "QVector3D" }
+ Property { name: "upVector"; type: "QVector3D" }
+ Property { name: "viewCenter"; type: "QVector3D" }
+ Property { name: "viewVector"; type: "QVector3D"; isReadonly: true }
+ Property { name: "viewMatrix"; type: "QMatrix4x4"; isReadonly: true }
+ Signal {
+ name: "projectionTypeChanged"
+ Parameter { name: "projectionType"; type: "QCameraLens::ProjectionType" }
+ }
+ Signal {
+ name: "nearPlaneChanged"
+ Parameter { name: "nearPlane"; type: "float" }
+ }
+ Signal {
+ name: "farPlaneChanged"
+ Parameter { name: "farPlane"; type: "float" }
+ }
+ Signal {
+ name: "fieldOfViewChanged"
+ Parameter { name: "fieldOfView"; type: "float" }
+ }
+ Signal {
+ name: "aspectRatioChanged"
+ Parameter { name: "aspectRatio"; type: "float" }
+ }
+ Signal {
+ name: "leftChanged"
+ Parameter { name: "left"; type: "float" }
+ }
+ Signal {
+ name: "rightChanged"
+ Parameter { name: "right"; type: "float" }
+ }
+ Signal {
+ name: "bottomChanged"
+ Parameter { name: "bottom"; type: "float" }
+ }
+ Signal {
+ name: "topChanged"
+ Parameter { name: "top"; type: "float" }
+ }
+ Signal {
+ name: "projectionMatrixChanged"
+ Parameter { name: "projectionMatrix"; type: "QMatrix4x4" }
+ }
+ Signal {
+ name: "positionChanged"
+ Parameter { name: "position"; type: "QVector3D" }
+ }
+ Signal {
+ name: "upVectorChanged"
+ Parameter { name: "upVector"; type: "QVector3D" }
+ }
+ Signal {
+ name: "viewCenterChanged"
+ Parameter { name: "viewCenter"; type: "QVector3D" }
+ }
+ Signal {
+ name: "viewVectorChanged"
+ Parameter { name: "viewVector"; type: "QVector3D" }
+ }
+ Method {
+ name: "setProjectionType"
+ Parameter { name: "type"; type: "QCameraLens::ProjectionType" }
+ }
+ Method {
+ name: "setNearPlane"
+ Parameter { name: "nearPlane"; type: "float" }
+ }
+ Method {
+ name: "setFarPlane"
+ Parameter { name: "farPlane"; type: "float" }
+ }
+ Method {
+ name: "setFieldOfView"
+ Parameter { name: "fieldOfView"; type: "float" }
+ }
+ Method {
+ name: "setAspectRatio"
+ Parameter { name: "aspectRatio"; type: "float" }
+ }
+ Method {
+ name: "setLeft"
+ Parameter { name: "left"; type: "float" }
+ }
+ Method {
+ name: "setRight"
+ Parameter { name: "right"; type: "float" }
+ }
+ Method {
+ name: "setBottom"
+ Parameter { name: "bottom"; type: "float" }
+ }
+ Method {
+ name: "setTop"
+ Parameter { name: "top"; type: "float" }
+ }
+ Method {
+ name: "setProjectionMatrix"
+ Parameter { name: "projectionMatrix"; type: "QMatrix4x4" }
+ }
+ Method {
+ name: "setPosition"
+ Parameter { name: "position"; type: "QVector3D" }
+ }
+ Method {
+ name: "setUpVector"
+ Parameter { name: "upVector"; type: "QVector3D" }
+ }
+ Method {
+ name: "setViewCenter"
+ Parameter { name: "viewCenter"; type: "QVector3D" }
+ }
+ Method {
+ name: "tiltRotation"
+ type: "QQuaternion"
+ Parameter { name: "angle"; type: "float" }
+ }
+ Method {
+ name: "panRotation"
+ type: "QQuaternion"
+ Parameter { name: "angle"; type: "float" }
+ }
+ Method {
+ name: "rollRotation"
+ type: "QQuaternion"
+ Parameter { name: "angle"; type: "float" }
+ }
+ Method {
+ name: "rotation"
+ type: "QQuaternion"
+ Parameter { name: "angle"; type: "float" }
+ Parameter { name: "axis"; type: "QVector3D" }
+ }
+ Method {
+ name: "translate"
+ Parameter { name: "vLocal"; type: "QVector3D" }
+ Parameter { name: "option"; type: "CameraTranslationOption" }
+ }
+ Method {
+ name: "translate"
+ Parameter { name: "vLocal"; type: "QVector3D" }
+ }
+ Method {
+ name: "translateWorld"
+ Parameter { name: "vWorld"; type: "QVector3D" }
+ Parameter { name: "option"; type: "CameraTranslationOption" }
+ }
+ Method {
+ name: "translateWorld"
+ Parameter { name: "vWorld"; type: "QVector3D" }
+ }
+ Method {
+ name: "tilt"
+ Parameter { name: "angle"; type: "float" }
+ }
+ Method {
+ name: "pan"
+ Parameter { name: "angle"; type: "float" }
+ }
+ Method {
+ name: "pan"
+ Parameter { name: "angle"; type: "float" }
+ Parameter { name: "axis"; type: "QVector3D" }
+ }
+ Method {
+ name: "roll"
+ Parameter { name: "angle"; type: "float" }
+ }
+ Method {
+ name: "tiltAboutViewCenter"
+ Parameter { name: "angle"; type: "float" }
+ }
+ Method {
+ name: "panAboutViewCenter"
+ Parameter { name: "angle"; type: "float" }
+ }
+ Method {
+ name: "panAboutViewCenter"
+ Parameter { name: "angle"; type: "float" }
+ Parameter { name: "axis"; type: "QVector3D" }
+ }
+ Method {
+ name: "rollAboutViewCenter"
+ Parameter { name: "angle"; type: "float" }
+ }
+ Method {
+ name: "rotate"
+ Parameter { name: "q"; type: "QQuaternion" }
+ }
+ Method {
+ name: "rotateAboutViewCenter"
+ Parameter { name: "q"; type: "QQuaternion" }
+ }
}
Component {
name: "Qt3DRender::QCameraLens"
prototype: "Qt3DCore::QComponent"
+ exports: ["Qt3D.Render/CameraLens 2.0"]
+ exportMetaObjectRevisions: [0]
Enum {
name: "ProjectionType"
values: {
@@ -555,6 +1243,8 @@ Module {
Component {
name: "Qt3DRender::QClearBuffers"
prototype: "Qt3DRender::QFrameGraphNode"
+ exports: ["Qt3D.Render/ClearBuffers 2.0"]
+ exportMetaObjectRevisions: [0]
Enum {
name: "BufferType"
values: {
@@ -572,6 +1262,7 @@ Module {
Property { name: "clearColor"; type: "QColor" }
Property { name: "clearDepthValue"; type: "float" }
Property { name: "clearStencilValue"; type: "int" }
+ Property { name: "colorBuffer"; type: "Qt3DRender::QRenderTargetOutput"; isPointer: true }
Signal {
name: "buffersChanged"
Parameter { name: "buffers"; type: "BufferType" }
@@ -588,6 +1279,10 @@ Module {
name: "clearStencilValueChanged"
Parameter { name: "clearStencilValue"; type: "int" }
}
+ Signal {
+ name: "colorBufferChanged"
+ Parameter { name: "buffer"; type: "QRenderTargetOutput"; isPointer: true }
+ }
Method {
name: "setBuffers"
Parameter { name: "buffers"; type: "BufferType" }
@@ -604,17 +1299,49 @@ Module {
name: "setClearStencilValue"
Parameter { name: "clearStencilValue"; type: "int" }
}
+ Method {
+ name: "setColorBuffer"
+ Parameter { name: "buffer"; type: "QRenderTargetOutput"; isPointer: true }
+ }
}
Component {
name: "Qt3DRender::QClipPlane"
- defaultProperty: "data"
- prototype: "Qt3DRender::QClipPlane"
- Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
- Property { name: "childNodes"; type: "Qt3DCore::QNode"; isList: true; isReadonly: true }
+ prototype: "Qt3DRender::QRenderState"
+ exports: ["Qt3D.Render/ClipPlane 2.0"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "planeIndex"; type: "int" }
+ Property { name: "normal"; type: "QVector3D" }
+ Property { name: "distance"; type: "float" }
+ Signal {
+ name: "planeIndexChanged"
+ Parameter { name: "planeIndex"; type: "int" }
+ }
+ Signal {
+ name: "normalChanged"
+ Parameter { name: "normal"; type: "QVector3D" }
+ }
+ Signal {
+ name: "distanceChanged"
+ Parameter { name: "distance"; type: "float" }
+ }
+ Method {
+ name: "setPlaneIndex"
+ Parameter { type: "int" }
+ }
+ Method {
+ name: "setNormal"
+ Parameter { type: "QVector3D" }
+ }
+ Method {
+ name: "setDistance"
+ Parameter { type: "float" }
+ }
}
Component {
name: "Qt3DRender::QColorMask"
prototype: "Qt3DRender::QRenderState"
+ exports: ["Qt3D.Render/ColorMask 2.0"]
+ exportMetaObjectRevisions: [0]
Property { name: "redMasked"; type: "bool" }
Property { name: "greenMasked"; type: "bool" }
Property { name: "blueMasked"; type: "bool" }
@@ -654,14 +1381,30 @@ Module {
}
Component {
name: "Qt3DRender::QComputeCommand"
- defaultProperty: "data"
- prototype: "Qt3DRender::QComputeCommand"
- Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
- Property { name: "childNodes"; type: "Qt3DCore::QNode"; isList: true; isReadonly: true }
+ prototype: "Qt3DCore::QComponent"
+ exports: ["Qt3D.Render/ComputeCommand 2.0"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "workGroupX"; type: "int" }
+ Property { name: "workGroupY"; type: "int" }
+ Property { name: "workGroupZ"; type: "int" }
+ Method {
+ name: "setWorkGroupX"
+ Parameter { name: "workGroupX"; type: "int" }
+ }
+ Method {
+ name: "setWorkGroupY"
+ Parameter { name: "workGroupY"; type: "int" }
+ }
+ Method {
+ name: "setWorkGroupZ"
+ Parameter { name: "workGroupZ"; type: "int" }
+ }
}
Component {
name: "Qt3DRender::QCullFace"
prototype: "Qt3DRender::QRenderState"
+ exports: ["Qt3D.Render/CullFace 2.0"]
+ exportMetaObjectRevisions: [0]
Enum {
name: "CullingMode"
values: {
@@ -684,6 +1427,8 @@ Module {
Component {
name: "Qt3DRender::QDepthTest"
prototype: "Qt3DRender::QRenderState"
+ exports: ["Qt3D.Render/DepthTest 2.0"]
+ exportMetaObjectRevisions: [0]
Enum {
name: "DepthFunction"
values: {
@@ -709,23 +1454,52 @@ Module {
}
Component {
name: "Qt3DRender::QDirectionalLight"
- defaultProperty: "data"
- prototype: "Qt3DRender::QDirectionalLight"
- Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
- Property { name: "childNodes"; type: "Qt3DCore::QNode"; isList: true; isReadonly: true }
+ prototype: "Qt3DRender::QAbstractLight"
+ exports: ["Qt3D.Render/DirectionalLight 2.0"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "worldDirection"; type: "QVector3D" }
+ Signal {
+ name: "worldDirectionChanged"
+ Parameter { name: "worldDirection"; type: "QVector3D" }
+ }
+ Method {
+ name: "setWorldDirection"
+ Parameter { name: "worldDirection"; type: "QVector3D" }
+ }
}
Component {
name: "Qt3DRender::QDispatchCompute"
- defaultProperty: "data"
- prototype: "Qt3DRender::QDispatchCompute"
- Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
- Property { name: "childNodes"; type: "Qt3DCore::QNode"; isList: true; isReadonly: true }
+ prototype: "Qt3DRender::QFrameGraphNode"
+ exports: ["Qt3D.Render/DispatchCompute 2.0"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "workGroupX"; type: "int" }
+ Property { name: "workGroupY"; type: "int" }
+ Property { name: "workGroupZ"; type: "int" }
+ Method {
+ name: "setWorkGroupX"
+ Parameter { name: "workGroupX"; type: "int" }
+ }
+ Method {
+ name: "setWorkGroupY"
+ Parameter { name: "workGroupY"; type: "int" }
+ }
+ Method {
+ name: "setWorkGroupZ"
+ Parameter { name: "workGroupZ"; type: "int" }
+ }
+ }
+ Component {
+ name: "Qt3DRender::QDithering"
+ prototype: "Qt3DRender::QRenderState"
+ exports: ["Qt3D.Render/Dithering 2.0"]
+ exportMetaObjectRevisions: [0]
}
- Component { name: "Qt3DRender::QDithering"; prototype: "Qt3DRender::QRenderState" }
Component { name: "Qt3DRender::QEffect"; prototype: "Qt3DCore::QNode" }
Component {
name: "Qt3DRender::QFilterKey"
prototype: "Qt3DCore::QNode"
+ exports: ["Qt3D.Render/FilterKey 2.0"]
+ exportMetaObjectRevisions: [0]
Property { name: "value"; type: "QVariant" }
Property { name: "name"; type: "string" }
Signal {
@@ -745,10 +1519,18 @@ Module {
Parameter { name: "customType"; type: "string" }
}
}
- Component { name: "Qt3DRender::QFrameGraphNode"; prototype: "Qt3DCore::QNode" }
+ Component {
+ name: "Qt3DRender::QFrameGraphNode"
+ prototype: "Qt3DCore::QNode"
+ exports: ["Qt3D.Render/FrameGraphNode 2.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ }
Component {
name: "Qt3DRender::QFrontFace"
prototype: "Qt3DRender::QRenderState"
+ exports: ["Qt3D.Render/FrontFace 2.0"]
+ exportMetaObjectRevisions: [0]
Enum {
name: "WindingDirection"
values: {
@@ -766,7 +1548,12 @@ Module {
Parameter { name: "direction"; type: "WindingDirection" }
}
}
- Component { name: "Qt3DRender::QFrustumCulling"; prototype: "Qt3DRender::QFrameGraphNode" }
+ Component {
+ name: "Qt3DRender::QFrustumCulling"
+ prototype: "Qt3DRender::QFrameGraphNode"
+ exports: ["Qt3D.Render/FrustumCulling 2.0"]
+ exportMetaObjectRevisions: [0]
+ }
Component {
name: "Qt3DRender::QGeometry"
prototype: "Qt3DCore::QNode"
@@ -783,10 +1570,20 @@ Module {
name: "setBoundingVolumePositionAttribute"
Parameter { name: "boundingVolumePositionAttribute"; type: "QAttribute"; isPointer: true }
}
+ Method {
+ name: "addAttribute"
+ Parameter { name: "attribute"; type: "Qt3DRender::QAttribute"; isPointer: true }
+ }
+ Method {
+ name: "removeAttribute"
+ Parameter { name: "attribute"; type: "Qt3DRender::QAttribute"; isPointer: true }
+ }
}
Component {
name: "Qt3DRender::QGeometryRenderer"
prototype: "Qt3DCore::QComponent"
+ exports: ["Qt3D.Render/GeometryRenderer 2.0"]
+ exportMetaObjectRevisions: [0]
Enum {
name: "PrimitiveType"
values: {
@@ -808,6 +1605,7 @@ Module {
Property { name: "vertexCount"; type: "int" }
Property { name: "indexOffset"; type: "int" }
Property { name: "firstInstance"; type: "int" }
+ Property { name: "firstVertex"; type: "int" }
Property { name: "restartIndexValue"; type: "int" }
Property { name: "verticesPerPatch"; type: "int" }
Property { name: "primitiveRestartEnabled"; type: "bool" }
@@ -830,6 +1628,10 @@ Module {
Parameter { name: "firstInstance"; type: "int" }
}
Signal {
+ name: "firstVertexChanged"
+ Parameter { name: "firstVertex"; type: "int" }
+ }
+ Signal {
name: "restartIndexValueChanged"
Parameter { name: "restartIndexValue"; type: "int" }
}
@@ -866,6 +1668,10 @@ Module {
Parameter { name: "firstInstance"; type: "int" }
}
Method {
+ name: "setFirstVertex"
+ Parameter { name: "firstVertex"; type: "int" }
+ }
+ Method {
name: "setRestartIndexValue"
Parameter { name: "index"; type: "int" }
}
@@ -914,11 +1720,11 @@ Module {
Property { name: "vendor"; type: "string" }
Signal {
name: "apiChanged"
- Parameter { name: "api"; type: "Api" }
+ Parameter { name: "api"; type: "Qt3DRender::QGraphicsApiFilter::Api" }
}
Signal {
name: "profileChanged"
- Parameter { name: "profile"; type: "OpenGLProfile" }
+ Parameter { name: "profile"; type: "Qt3DRender::QGraphicsApiFilter::OpenGLProfile" }
}
Signal {
name: "minorVersionChanged"
@@ -964,18 +1770,11 @@ Module {
}
Component {
name: "Qt3DRender::QLayer"
- defaultProperty: "data"
- prototype: "Qt3DRender::QLayer"
- Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
- Property { name: "childNodes"; type: "Qt3DCore::QNode"; isList: true; isReadonly: true }
- }
- Component {
- name: "Qt3DRender::QLayerFilter"
- defaultProperty: "data"
- prototype: "Qt3DRender::QLayerFilter"
- Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
- Property { name: "childNodes"; type: "Qt3DCore::QNode"; isList: true; isReadonly: true }
+ prototype: "Qt3DCore::QComponent"
+ exports: ["Qt3D.Render/Layer 2.0"]
+ exportMetaObjectRevisions: [0]
}
+ Component { name: "Qt3DRender::QLayerFilter"; prototype: "Qt3DRender::QFrameGraphNode" }
Component {
name: "Qt3DRender::QMaterial"
prototype: "Qt3DCore::QComponent"
@@ -992,6 +1791,8 @@ Module {
Component {
name: "Qt3DRender::QMesh"
prototype: "Qt3DRender::QGeometryRenderer"
+ exports: ["Qt3D.Render/Mesh 2.0"]
+ exportMetaObjectRevisions: [0]
Property { name: "source"; type: "QUrl" }
Property { name: "meshName"; type: "string" }
Signal {
@@ -1014,28 +1815,97 @@ Module {
Component {
name: "Qt3DRender::QMultiSampleAntiAliasing"
prototype: "Qt3DRender::QRenderState"
+ exports: ["Qt3D.Render/MultiSampleAntiAliasing 2.0"]
+ exportMetaObjectRevisions: [0]
}
Component {
name: "Qt3DRender::QNoDepthMask"
- defaultProperty: "data"
- prototype: "Qt3DRender::QNoDepthMask"
- Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
- Property { name: "childNodes"; type: "Qt3DCore::QNode"; isList: true; isReadonly: true }
+ prototype: "Qt3DRender::QRenderState"
+ exports: ["Qt3D.Render/NoDepthMask 2.0"]
+ exportMetaObjectRevisions: [0]
+ }
+ Component {
+ name: "Qt3DRender::QNoDraw"
+ prototype: "Qt3DRender::QFrameGraphNode"
+ exports: ["Qt3D.Render/NoDraw 2.0"]
+ exportMetaObjectRevisions: [0]
}
- Component { name: "Qt3DRender::QNoDraw"; prototype: "Qt3DRender::QFrameGraphNode" }
Component {
name: "Qt3DRender::QObjectPicker"
- defaultProperty: "data"
- prototype: "Qt3DRender::QObjectPicker"
- Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
- Property { name: "childNodes"; type: "Qt3DCore::QNode"; isList: true; isReadonly: true }
+ prototype: "Qt3DCore::QComponent"
+ exports: ["Qt3D.Render/ObjectPicker 2.0"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "hoverEnabled"; type: "bool" }
+ Property { name: "dragEnabled"; type: "bool" }
+ Property { name: "pressed"; type: "bool"; isReadonly: true }
+ Property { name: "containsMouse"; type: "bool"; isReadonly: true }
+ Signal {
+ name: "pressed"
+ Parameter { name: "pick"; type: "Qt3DRender::QPickEvent"; isPointer: true }
+ }
+ Signal {
+ name: "released"
+ Parameter { name: "pick"; type: "Qt3DRender::QPickEvent"; isPointer: true }
+ }
+ Signal {
+ name: "clicked"
+ Parameter { name: "pick"; type: "Qt3DRender::QPickEvent"; isPointer: true }
+ }
+ Signal {
+ name: "moved"
+ Parameter { name: "pick"; type: "Qt3DRender::QPickEvent"; isPointer: true }
+ }
+ Signal { name: "entered" }
+ Signal { name: "exited" }
+ Signal {
+ name: "hoverEnabledChanged"
+ Parameter { name: "hoverEnabled"; type: "bool" }
+ }
+ Signal {
+ name: "dragEnabledChanged"
+ Parameter { name: "dragEnabled"; type: "bool" }
+ }
+ Signal {
+ name: "pressedChanged"
+ Parameter { name: "pressed"; type: "bool" }
+ }
+ Signal {
+ name: "containsMouseChanged"
+ Parameter { name: "containsMouse"; type: "bool" }
+ }
+ Method {
+ name: "setHoverEnabled"
+ Parameter { name: "hoverEnabled"; type: "bool" }
+ }
+ Method {
+ name: "setDragEnabled"
+ Parameter { name: "dragEnabled"; type: "bool" }
+ }
}
Component {
name: "Qt3DRender::QParameter"
- defaultProperty: "data"
- prototype: "Qt3DRender::QParameter"
- Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
- Property { name: "childNodes"; type: "Qt3DCore::QNode"; isList: true; isReadonly: true }
+ prototype: "Qt3DCore::QNode"
+ exports: ["Qt3D.Render/QParameter 2.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ Property { name: "name"; type: "string" }
+ Property { name: "value"; type: "QVariant" }
+ Signal {
+ name: "valueChanged"
+ Parameter { name: "value"; type: "QVariant" }
+ }
+ Signal {
+ name: "nameChanged"
+ Parameter { name: "name"; type: "string" }
+ }
+ Method {
+ name: "setName"
+ Parameter { name: "name"; type: "string" }
+ }
+ Method {
+ name: "setValue"
+ Parameter { name: "dv"; type: "QVariant" }
+ }
}
Component {
name: "Qt3DRender::QPickEvent"
@@ -1060,6 +1930,8 @@ Module {
Component {
name: "Qt3DRender::QPickingSettings"
prototype: "Qt3DCore::QNode"
+ exports: ["Qt3D.Render/PickingSettings 2.0"]
+ exportMetaObjectRevisions: [0]
Enum {
name: "PickMethod"
values: {
@@ -1095,21 +1967,73 @@ Module {
}
Component {
name: "Qt3DRender::QPointLight"
- defaultProperty: "data"
- prototype: "Qt3DRender::QPointLight"
- Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
- Property { name: "childNodes"; type: "Qt3DCore::QNode"; isList: true; isReadonly: true }
+ prototype: "Qt3DRender::QAbstractLight"
+ exports: ["Qt3D.Render/PointLight 2.0"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "constantAttenuation"; type: "float" }
+ Property { name: "linearAttenuation"; type: "float" }
+ Property { name: "quadraticAttenuation"; type: "float" }
+ Signal {
+ name: "constantAttenuationChanged"
+ Parameter { name: "constantAttenuation"; type: "float" }
+ }
+ Signal {
+ name: "linearAttenuationChanged"
+ Parameter { name: "linearAttenuation"; type: "float" }
+ }
+ Signal {
+ name: "quadraticAttenuationChanged"
+ Parameter { name: "quadraticAttenuation"; type: "float" }
+ }
+ Method {
+ name: "setConstantAttenuation"
+ Parameter { name: "value"; type: "float" }
+ }
+ Method {
+ name: "setLinearAttenuation"
+ Parameter { name: "value"; type: "float" }
+ }
+ Method {
+ name: "setQuadraticAttenuation"
+ Parameter { name: "value"; type: "float" }
+ }
}
Component {
name: "Qt3DRender::QPointSize"
- defaultProperty: "data"
- prototype: "Qt3DRender::QPointSize"
- Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
- Property { name: "childNodes"; type: "Qt3DCore::QNode"; isList: true; isReadonly: true }
+ prototype: "Qt3DRender::QRenderState"
+ exports: ["Qt3D.Render/PointSize 2.0"]
+ exportMetaObjectRevisions: [0]
+ Enum {
+ name: "SizeMode"
+ values: {
+ "Fixed": 0,
+ "Programmable": 1
+ }
+ }
+ Property { name: "sizeMode"; type: "SizeMode" }
+ Property { name: "value"; type: "float" }
+ Signal {
+ name: "sizeModeChanged"
+ Parameter { name: "sizeMode"; type: "SizeMode" }
+ }
+ Signal {
+ name: "valueChanged"
+ Parameter { name: "value"; type: "float" }
+ }
+ Method {
+ name: "setSizeMode"
+ Parameter { name: "sizeMode"; type: "SizeMode" }
+ }
+ Method {
+ name: "setValue"
+ Parameter { name: "value"; type: "float" }
+ }
}
Component {
name: "Qt3DRender::QPolygonOffset"
prototype: "Qt3DRender::QRenderState"
+ exports: ["Qt3D.Render/PolygonOffset 2.0"]
+ exportMetaObjectRevisions: [0]
Property { name: "scaleFactor"; type: "float" }
Property { name: "depthSteps"; type: "float" }
Signal {
@@ -1146,23 +2070,84 @@ Module {
Component {
name: "Qt3DRender::QRenderSettings"
defaultProperty: "activeFrameGraph"
- prototype: "Qt3DRender::QRenderSettings"
- Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
- Property { name: "childNodes"; type: "Qt3DCore::QNode"; isList: true; isReadonly: true }
+ prototype: "Qt3DCore::QComponent"
+ exports: ["Qt3D.Render/RenderSettings 2.0"]
+ exportMetaObjectRevisions: [0]
+ Enum {
+ name: "RenderPolicy"
+ values: {
+ "OnDemand": 0,
+ "Always": 1
+ }
+ }
+ Property {
+ name: "pickingSettings"
+ type: "Qt3DRender::QPickingSettings"
+ isReadonly: true
+ isPointer: true
+ }
+ Property { name: "renderPolicy"; type: "RenderPolicy" }
+ Property { name: "activeFrameGraph"; type: "Qt3DRender::QFrameGraphNode"; isPointer: true }
+ Signal {
+ name: "activeFrameGraphChanged"
+ Parameter { name: "activeFrameGraph"; type: "QFrameGraphNode"; isPointer: true }
+ }
+ Signal {
+ name: "renderPolicyChanged"
+ Parameter { name: "renderPolicy"; type: "RenderPolicy" }
+ }
+ Method {
+ name: "setActiveFrameGraph"
+ Parameter { name: "activeFrameGraph"; type: "QFrameGraphNode"; isPointer: true }
+ }
+ Method {
+ name: "setRenderPolicy"
+ Parameter { name: "renderPolicy"; type: "RenderPolicy" }
+ }
+ }
+ Component {
+ name: "Qt3DRender::QRenderState"
+ prototype: "Qt3DCore::QNode"
+ exports: ["Qt3D.Render/RenderState 2.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
}
- Component { name: "Qt3DRender::QRenderState"; prototype: "Qt3DCore::QNode" }
Component { name: "Qt3DRender::QRenderStateSet"; prototype: "Qt3DRender::QFrameGraphNode" }
Component {
name: "Qt3DRender::QRenderSurfaceSelector"
- defaultProperty: "data"
- prototype: "Qt3DRender::QRenderSurfaceSelector"
- Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
- Property { name: "childNodes"; type: "Qt3DCore::QNode"; isList: true; isReadonly: true }
+ prototype: "Qt3DRender::QFrameGraphNode"
+ exports: ["Qt3D.Render/RenderSurfaceSelector 2.0"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "surface"; type: "QObject"; isPointer: true }
+ Property { name: "externalRenderTargetSize"; type: "QSize"; isReadonly: true }
+ Property { name: "surfacePixelRatio"; type: "float" }
+ Signal {
+ name: "surfaceChanged"
+ Parameter { name: "surface"; type: "QObject"; isPointer: true }
+ }
+ Signal {
+ name: "externalRenderTargetSizeChanged"
+ Parameter { name: "size"; type: "QSize" }
+ }
+ Signal {
+ name: "surfacePixelRatioChanged"
+ Parameter { name: "ratio"; type: "float" }
+ }
+ Method {
+ name: "setSurface"
+ Parameter { name: "surfaceObject"; type: "QObject"; isPointer: true }
+ }
+ Method {
+ name: "setSurfacePixelRatio"
+ Parameter { name: "ratio"; type: "float" }
+ }
}
Component { name: "Qt3DRender::QRenderTarget"; prototype: "Qt3DCore::QComponent" }
Component {
name: "Qt3DRender::QRenderTargetOutput"
prototype: "Qt3DCore::QNode"
+ exports: ["Qt3D.Render/RenderTargetOutput 2.0"]
+ exportMetaObjectRevisions: [0]
Enum {
name: "AttachmentPoint"
values: {
@@ -1279,22 +2264,64 @@ Module {
}
Component {
name: "Qt3DRender::QScissorTest"
- defaultProperty: "data"
- prototype: "Qt3DRender::QScissorTest"
- Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
- Property { name: "childNodes"; type: "Qt3DCore::QNode"; isList: true; isReadonly: true }
+ prototype: "Qt3DRender::QRenderState"
+ exports: ["Qt3D.Render/ScissorTest 2.0"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "left"; type: "int" }
+ Property { name: "bottom"; type: "int" }
+ Property { name: "width"; type: "int" }
+ Property { name: "height"; type: "int" }
+ Signal {
+ name: "leftChanged"
+ Parameter { name: "left"; type: "int" }
+ }
+ Signal {
+ name: "bottomChanged"
+ Parameter { name: "bottom"; type: "int" }
+ }
+ Signal {
+ name: "widthChanged"
+ Parameter { name: "width"; type: "int" }
+ }
+ Signal {
+ name: "heightChanged"
+ Parameter { name: "height"; type: "int" }
+ }
+ Method {
+ name: "setLeft"
+ Parameter { name: "left"; type: "int" }
+ }
+ Method {
+ name: "setBottom"
+ Parameter { name: "bottom"; type: "int" }
+ }
+ Method {
+ name: "setWidth"
+ Parameter { name: "width"; type: "int" }
+ }
+ Method {
+ name: "setHeight"
+ Parameter { name: "height"; type: "int" }
+ }
}
Component {
name: "Qt3DRender::QSeamlessCubemap"
- defaultProperty: "data"
- prototype: "Qt3DRender::QSeamlessCubemap"
- Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
- Property { name: "childNodes"; type: "Qt3DCore::QNode"; isList: true; isReadonly: true }
+ prototype: "Qt3DRender::QRenderState"
+ exports: ["Qt3D.Render/SeamlessCubemap 2.0"]
+ exportMetaObjectRevisions: [0]
+ }
+ Component {
+ name: "Qt3DRender::QShaderData"
+ prototype: "Qt3DCore::QComponent"
+ exports: ["Qt3D.Render/QShaderData 2.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
}
- Component { name: "Qt3DRender::QShaderData"; prototype: "Qt3DCore::QComponent" }
Component {
name: "Qt3DRender::QShaderProgram"
prototype: "Qt3DCore::QNode"
+ exports: ["Qt3D.Render/ShaderProgram 2.0"]
+ exportMetaObjectRevisions: [0]
Enum {
name: "ShaderType"
values: {
@@ -1369,6 +2396,8 @@ Module {
Component {
name: "Qt3DRender::QSortPolicy"
prototype: "Qt3DRender::QFrameGraphNode"
+ exports: ["Qt3D.Render/SortPolicy 2.0"]
+ exportMetaObjectRevisions: [0]
Enum {
name: "SortType"
values: {
@@ -1398,6 +2427,8 @@ Module {
Component {
name: "Qt3DRender::QSpotLight"
prototype: "Qt3DRender::QAbstractLight"
+ exports: ["Qt3D.Render/SpotLight 2.0"]
+ exportMetaObjectRevisions: [0]
Property { name: "constantAttenuation"; type: "float" }
Property { name: "linearAttenuation"; type: "float" }
Property { name: "quadraticAttenuation"; type: "float" }
@@ -1447,6 +2478,8 @@ Module {
Component {
name: "Qt3DRender::QStencilMask"
prototype: "Qt3DRender::QRenderState"
+ exports: ["Qt3D.Render/StencilMask 2.0"]
+ exportMetaObjectRevisions: [0]
Property { name: "frontOutputMask"; type: "uint" }
Property { name: "backOutputMask"; type: "uint" }
Signal {
@@ -1469,6 +2502,8 @@ Module {
Component {
name: "Qt3DRender::QStencilOperation"
prototype: "Qt3DRender::QRenderState"
+ exports: ["Qt3D.Render/StencilOperation 2.0"]
+ exportMetaObjectRevisions: [0]
Property {
name: "front"
type: "Qt3DRender::QStencilOperationArguments"
@@ -1545,6 +2580,8 @@ Module {
Component {
name: "Qt3DRender::QStencilTest"
prototype: "Qt3DRender::QRenderState"
+ exports: ["Qt3D.Render/StencilTest 2.0"]
+ exportMetaObjectRevisions: [0]
Property {
name: "front"
type: "Qt3DRender::QStencilTestArguments"
@@ -1651,6 +2688,8 @@ Module {
Component {
name: "Qt3DRender::QTextureImage"
prototype: "Qt3DRender::QAbstractTextureImage"
+ exports: ["Qt3D.Render/TextureImage 2.0"]
+ exportMetaObjectRevisions: [0]
Enum {
name: "Status"
values: {
@@ -1746,7 +2785,6 @@ Module {
}
Component {
name: "Qt3DRender::Render::Quick::Quick3DBuffer"
- defaultProperty: "data"
prototype: "Qt3DRender::QBuffer"
exports: ["Qt3D.Render/Buffer 2.0"]
exportMetaObjectRevisions: [0]
@@ -1756,7 +2794,6 @@ Module {
}
Component {
name: "Qt3DRender::Render::Quick::Quick3DEffect"
- defaultProperty: "data"
prototype: "Qt3DRender::QEffect"
exports: ["Qt3D.Render/Effect 2.0"]
exportMetaObjectRevisions: [0]
@@ -1772,8 +2809,14 @@ Module {
Property { name: "attributes"; type: "Qt3DRender::QAttribute"; isList: true; isReadonly: true }
}
Component {
+ name: "Qt3DRender::Render::Quick::Quick3DLayerFilter"
+ prototype: "Qt3DRender::QLayerFilter"
+ exports: ["Qt3D.Render/LayerFilter 2.0"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "layers"; type: "Qt3DRender::QLayer"; isList: true; isReadonly: true }
+ }
+ Component {
name: "Qt3DRender::Render::Quick::Quick3DMaterial"
- defaultProperty: "data"
prototype: "Qt3DRender::QMaterial"
exports: ["Qt3D.Render/Material 2.0"]
exportMetaObjectRevisions: [0]
@@ -1781,14 +2824,12 @@ Module {
}
Component {
name: "Qt3DRender::Render::Quick::Quick3DParameter"
- defaultProperty: "data"
- prototype: "Qt3DRender::Render::Quick::Quick3DParameter"
- Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
- Property { name: "childNodes"; type: "Qt3DCore::QNode"; isList: true; isReadonly: true }
+ prototype: "Qt3DRender::QParameter"
+ exports: ["Qt3D.Render/Parameter 2.0"]
+ exportMetaObjectRevisions: [0]
}
Component {
name: "Qt3DRender::Render::Quick::Quick3DRenderPass"
- defaultProperty: "data"
prototype: "Qt3DRender::QRenderPass"
exports: ["Qt3D.Render/RenderPass 2.0"]
exportMetaObjectRevisions: [0]
@@ -1803,7 +2844,6 @@ Module {
}
Component {
name: "Qt3DRender::Render::Quick::Quick3DRenderPassFilter"
- defaultProperty: "data"
prototype: "Qt3DRender::QRenderPassFilter"
exports: ["Qt3D.Render/RenderPassFilter 2.0"]
exportMetaObjectRevisions: [0]
@@ -1812,7 +2852,6 @@ Module {
}
Component {
name: "Qt3DRender::Render::Quick::Quick3DRenderTargetOutput"
- defaultProperty: "data"
prototype: "Qt3DRender::QRenderTarget"
exports: ["Qt3D.Render/RenderTarget 2.0"]
exportMetaObjectRevisions: [0]
@@ -1825,7 +2864,6 @@ Module {
}
Component {
name: "Qt3DRender::Render::Quick::Quick3DRenderTargetSelector"
- defaultProperty: "data"
prototype: "Qt3DRender::QRenderTargetSelector"
exports: ["Qt3D.Render/RenderTargetSelector 2.0"]
exportMetaObjectRevisions: [0]
@@ -1833,27 +2871,26 @@ Module {
}
Component {
name: "Qt3DRender::Render::Quick::Quick3DScene"
- defaultProperty: "data"
prototype: "Qt3DRender::QSceneLoader"
exports: ["Qt3D.Render/SceneLoader 2.0"]
exportMetaObjectRevisions: [0]
}
Component {
name: "Qt3DRender::Render::Quick::Quick3DShaderData"
- defaultProperty: "data"
- prototype: "Qt3DRender::Render::Quick::Quick3DShaderData"
- Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
- Property { name: "childNodes"; type: "Qt3DCore::QNode"; isList: true; isReadonly: true }
+ prototype: "Qt3DRender::QShaderData"
+ exports: ["Qt3D.Render/ShaderData 2.0"]
+ exportMetaObjectRevisions: [0]
}
Component {
name: "Qt3DRender::Render::Quick::Quick3DShaderDataArray"
defaultProperty: "values"
prototype: "Qt3DCore::QNode"
+ exports: ["Qt3D.Render/ShaderDataArray 2.0"]
+ exportMetaObjectRevisions: [0]
Property { name: "values"; type: "Qt3DRender::QShaderData"; isList: true; isReadonly: true }
}
Component {
name: "Qt3DRender::Render::Quick::Quick3DStateSet"
- defaultProperty: "data"
prototype: "Qt3DRender::QRenderStateSet"
exports: ["Qt3D.Render/RenderStateSet 2.0"]
exportMetaObjectRevisions: [0]
@@ -1866,7 +2903,6 @@ Module {
}
Component {
name: "Qt3DRender::Render::Quick::Quick3DTechnique"
- defaultProperty: "data"
prototype: "Qt3DRender::QTechnique"
exports: ["Qt3D.Render/Technique 2.0"]
exportMetaObjectRevisions: [0]
@@ -1876,7 +2912,6 @@ Module {
}
Component {
name: "Qt3DRender::Render::Quick::Quick3DTechniqueFilter"
- defaultProperty: "data"
prototype: "Qt3DRender::QTechniqueFilter"
exports: ["Qt3D.Render/TechniqueFilter 2.0"]
exportMetaObjectRevisions: [0]
@@ -1886,7 +2921,7 @@ Module {
Component {
name: "Qt3DRender::Render::Quick::Quick3DTextureExtension"
defaultProperty: "textureImages"
- prototype: "Qt3DRender::QTexture1D"
+ prototype: "Qt3DRender::QTextureLoader"
exports: [
"Qt3D.Render/Texture1D 2.0",
"Qt3D.Render/Texture1DArray 2.0",
@@ -1911,7 +2946,6 @@ Module {
}
Component {
name: "Qt3DRender::Render::Quick::Quick3DViewport"
- defaultProperty: "data"
prototype: "Qt3DRender::QViewport"
exports: ["Qt3D.Render/Viewport 2.0"]
exportMetaObjectRevisions: [0]
diff --git a/src/quick3d/imports/scene3d/plugins.qmltypes b/src/quick3d/imports/scene3d/plugins.qmltypes
index da56b97ea..46df37093 100644
--- a/src/quick3d/imports/scene3d/plugins.qmltypes
+++ b/src/quick3d/imports/scene3d/plugins.qmltypes
@@ -7,7 +7,7 @@ import QtQuick.tooling 1.2
// 'qmlplugindump -nonrelocatable QtQuick.Scene3D 2.0'
Module {
- dependencies: ["QtQuick 2.0"]
+ dependencies: ["QtQuick 2.7"]
Component {
name: "Qt3DRender::Scene3DItem"
defaultProperty: "entity"
diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp
index 7bd3f830c..152c35199 100644
--- a/src/render/backend/renderer.cpp
+++ b/src/render/backend/renderer.cpp
@@ -160,6 +160,9 @@ Renderer::Renderer(QRenderAspect::RenderType type)
, m_calculateBoundingVolumeJob(Render::CalculateBoundingVolumeJobPtr::create())
, m_updateWorldBoundingVolumeJob(Render::UpdateWorldBoundingVolumeJobPtr::create())
, m_sendRenderCaptureJob(Render::SendRenderCaptureJobPtr::create(this))
+ , m_bufferGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForDirtyBuffers(); }, JobTypes::DirtyBufferGathering))
+ , m_textureGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForDirtyTextures(); }, JobTypes::DirtyTextureGathering))
+ , m_shaderGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForDirtyShaders(); }, JobTypes::DirtyShaderGathering))
#ifdef QT3D_JOBS_RUN_STATS
, m_commandExecuter(new Qt3DRender::Debug::CommandExecuter(this))
#endif
@@ -679,51 +682,6 @@ void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderView
// Prepare the ShaderParameterPack based on the active uniforms of the shader
shader->prepareUniforms(command->m_parameterPack);
- // TO DO: The step below could be performed by the RenderCommand builder job
- { // Scoped to show extent
- if ((command->m_isValid = !command->m_attributes.empty()) == false)
- continue;
-
- // Update the draw command with what's going to be needed for the drawing
- uint primitiveCount = rGeometryRenderer->vertexCount();
- uint estimatedCount = 0;
- Attribute *indexAttribute = nullptr;
-
- const QVector<Qt3DCore::QNodeId> attributeIds = rGeometry->attributes();
- for (Qt3DCore::QNodeId attributeId : attributeIds) {
- Attribute *attribute = m_nodesManager->attributeManager()->lookupResource(attributeId);
- if (attribute->attributeType() == QAttribute::IndexAttribute)
- indexAttribute = attribute;
- else if (command->m_attributes.contains(attribute->nameId()))
- estimatedCount = qMax(attribute->count(), estimatedCount);
- }
-
- // Update the draw command with all the information required for the drawing
- if ((command->m_drawIndexed = (indexAttribute != nullptr)) == true) {
- command->m_indexAttributeDataType = GraphicsContext::glDataTypeFromAttributeDataType(indexAttribute->vertexBaseType());
- command->m_indexAttributeByteOffset = indexAttribute->byteOffset();
- }
-
- // Use the count specified by the GeometryRender
- // If not specify use the indexAttribute count if present
- // Otherwise tries to use the count from the attribute with the highest count
- if (primitiveCount == 0) {
- if (indexAttribute)
- primitiveCount = indexAttribute->count();
- else
- primitiveCount = estimatedCount;
- }
-
- command->m_primitiveCount = primitiveCount;
- command->m_primitiveType = rGeometryRenderer->primitiveType();
- command->m_primitiveRestartEnabled = rGeometryRenderer->primitiveRestartEnabled();
- command->m_restartIndexValue = rGeometryRenderer->restartIndexValue();
- command->m_firstInstance = rGeometryRenderer->firstInstance();
- command->m_instanceCount = rGeometryRenderer->instanceCount();
- command->m_firstVertex = rGeometryRenderer->firstVertex();
- command->m_indexOffset = rGeometryRenderer->indexOffset();
- command->m_verticesPerPatch = rGeometryRenderer->verticesPerPatch();
- }
} else if (command->m_type == RenderCommand::Compute) {
Shader *shader = m_nodesManager->data<Shader, ShaderManager>(command->m_shader);
Q_ASSERT(shader);
@@ -750,48 +708,76 @@ void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderView
m_dirtyGeometry.clear();
}
-void Renderer::updateGLResources()
+// Executed in a job
+void Renderer::lookForDirtyBuffers()
{
- // TO DO: The loops could be performed in a job so that we only
- // have the actual dirty elements
-
const QVector<HBuffer> activeBufferHandles = m_nodesManager->bufferManager()->activeHandles();
for (HBuffer handle: activeBufferHandles) {
Buffer *buffer = m_nodesManager->bufferManager()->data(handle);
- // Perform data upload
- if (buffer->isDirty()) {
- // Forces creation if it doesn't exit
- if (!m_graphicsContext->hasGLBufferForBuffer(buffer))
- m_graphicsContext->glBufferForRenderBuffer(buffer);
- else // Otherwise update the glBuffer
- m_graphicsContext->updateBuffer(buffer);
- buffer->unsetDirty();
- }
+ if (buffer->isDirty())
+ m_dirtyBuffers.push_back(handle);
}
+}
- const QVector<HTechnique> activeTechniques = m_nodesManager->techniqueManager()->activeHandles();
- for (HTechnique techniqueHandle : activeTechniques) {
- Technique *technique = m_nodesManager->techniqueManager()->data(techniqueHandle);
- // If api of the renderer matches the one from the technique
- if (*contextInfo() == *technique->graphicsApiFilter()) {
- const auto passIds = technique->renderPasses();
- for (const QNodeId passId : passIds) {
- RenderPass *renderPass = m_nodesManager->renderPassManager()->lookupResource(passId);
- HShader shaderHandle = m_nodesManager->shaderManager()->lookupHandle(renderPass->shaderProgram());
- Shader *shader = m_nodesManager->shaderManager()->data(shaderHandle);
- if (shader != nullptr && !shader->isLoaded())
- m_graphicsContext->loadShader(shader);
+// Executed in a job
+void Renderer::lookForDirtyTextures()
+{
+ const QVector<HTexture> activeTextureHandles = m_nodesManager->textureManager()->activeHandles();
+ for (HTexture handle: activeTextureHandles) {
+ Texture *texture = m_nodesManager->textureManager()->data(handle);
+ if (texture->isDirty())
+ m_dirtyTextures.push_back(handle);
+ }
+}
+
+// Executed in a job
+void Renderer::lookForDirtyShaders()
+{
+ if (isRunning()) {
+ const QVector<HTechnique> activeTechniques = m_nodesManager->techniqueManager()->activeHandles();
+ for (HTechnique techniqueHandle : activeTechniques) {
+ Technique *technique = m_nodesManager->techniqueManager()->data(techniqueHandle);
+ // If api of the renderer matches the one from the technique
+ if (*contextInfo() == *technique->graphicsApiFilter()) {
+ const auto passIds = technique->renderPasses();
+ for (const QNodeId passId : passIds) {
+ RenderPass *renderPass = m_nodesManager->renderPassManager()->lookupResource(passId);
+ HShader shaderHandle = m_nodesManager->shaderManager()->lookupHandle(renderPass->shaderProgram());
+ Shader *shader = m_nodesManager->shaderManager()->data(shaderHandle);
+ if (shader != nullptr && !shader->isLoaded())
+ m_dirtyShaders.push_back(shaderHandle);
+ }
}
}
}
+}
- const QVector<HTexture> activeTextureHandles = m_nodesManager->textureManager()->activeHandles();
+void Renderer::updateGLResources()
+{
+ const QVector<HBuffer> dirtyBufferHandles = std::move(m_dirtyBuffers);
+ for (HBuffer handle: dirtyBufferHandles) {
+ Buffer *buffer = m_nodesManager->bufferManager()->data(handle);
+ // Perform data upload
+ // Forces creation if it doesn't exit
+ if (!m_graphicsContext->hasGLBufferForBuffer(buffer))
+ m_graphicsContext->glBufferForRenderBuffer(buffer);
+ else // Otherwise update the glBuffer
+ m_graphicsContext->updateBuffer(buffer);
+ buffer->unsetDirty();
+ }
+
+ const QVector<HShader> dirtyShaderHandles = std::move(m_dirtyShaders);
+ for (HShader handle: dirtyShaderHandles) {
+ Shader *shader = m_nodesManager->shaderManager()->data(handle);
+ // Compile shader
+ m_graphicsContext->loadShader(shader);
+ }
+
+ const QVector<HTexture> activeTextureHandles = std::move(m_dirtyTextures);
for (HTexture handle: activeTextureHandles) {
Texture *texture = m_nodesManager->textureManager()->data(handle);
- if (texture->isDirty()) {
- // Upload/Update texture
- texture->getOrCreateGLTexture();
- }
+ // Upload/Update texture
+ texture->getOrCreateGLTexture();
}
}
@@ -1000,6 +986,22 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
for (const QAspectJobPtr &bufferJob : bufferJobs)
m_calculateBoundingVolumeJob->addDependency(bufferJob);
+
+ // Traverse the current framegraph. For each leaf node create a
+ // RenderView and set its configuration then create a job to
+ // populate the RenderView with a set of RenderCommands that get
+ // their details from the RenderNodes that are visible to the
+ // Camera selected by the framegraph configuration
+ FrameGraphVisitor visitor(this, m_nodesManager->frameGraphManager());
+ visitor.traverse(frameGraphRoot(), &renderBinJobs);
+
+ // Set dependencies of resource gatherer
+ for (const QAspectJobPtr &jobPtr : renderBinJobs) {
+ jobPtr->addDependency(m_bufferGathererJob);
+ jobPtr->addDependency(m_textureGathererJob);
+ jobPtr->addDependency(m_shaderGathererJob);
+ }
+
// Add jobs
renderBinJobs.push_back(m_framePreparationJob);
renderBinJobs.push_back(m_expandBoundingVolumeJob);
@@ -1010,13 +1012,10 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
renderBinJobs.push_back(m_sendRenderCaptureJob);
renderBinJobs.append(bufferJobs);
- // Traverse the current framegraph. For each leaf node create a
- // RenderView and set its configuration then create a job to
- // populate the RenderView with a set of RenderCommands that get
- // their details from the RenderNodes that are visible to the
- // Camera selected by the framegraph configuration
- FrameGraphVisitor visitor(this, m_nodesManager->frameGraphManager());
- visitor.traverse(frameGraphRoot(), &renderBinJobs);
+ // Jobs to prepare GL Resource upload
+ renderBinJobs.push_back(m_bufferGathererJob);
+ renderBinJobs.push_back(m_textureGathererJob);
+ renderBinJobs.push_back(m_shaderGathererJob);
// Set target number of RenderViews
m_renderQueue->setTargetRenderViewCount(visitor.leafNodeCount());
diff --git a/src/render/backend/renderer_p.h b/src/render/backend/renderer_p.h
index 05a639d17..9f78df772 100644
--- a/src/render/backend/renderer_p.h
+++ b/src/render/backend/renderer_p.h
@@ -70,6 +70,7 @@
#include <Qt3DRender/private/updateworldboundingvolumejob_p.h>
#include <Qt3DRender/private/platformsurfacefilter_p.h>
#include <Qt3DRender/private/sendrendercapturejob_p.h>
+#include <Qt3DRender/private/genericlambdajob_p.h>
#include <QHash>
#include <QMatrix4x4>
@@ -84,6 +85,8 @@
#include <QScopedPointer>
#include <QSemaphore>
+#include <functional>
+
QT_BEGIN_NAMESPACE
class QSurface;
@@ -297,6 +300,18 @@ private:
HVao *previousVAOHandle,
OpenGLVertexArrayObject **vao);
+ GenericLambdaJobPtr<std::function<void ()>> m_bufferGathererJob;
+ GenericLambdaJobPtr<std::function<void ()>> m_textureGathererJob;
+ GenericLambdaJobPtr<std::function<void ()>> m_shaderGathererJob;
+
+ void lookForDirtyBuffers();
+ void lookForDirtyTextures();
+ void lookForDirtyShaders();
+
+ QVector<HBuffer> m_dirtyBuffers;
+ QVector<HShader> m_dirtyShaders;
+ QVector<HTexture> m_dirtyTextures;
+
#ifdef QT3D_JOBS_RUN_STATS
QScopedPointer<Qt3DRender::Debug::CommandExecuter> m_commandExecuter;
friend class Qt3DRender::Debug::CommandExecuter;
diff --git a/src/render/backend/renderview.cpp b/src/render/backend/renderview.cpp
index df165e2d0..7e9b695ed 100644
--- a/src/render/backend/renderview.cpp
+++ b/src/render/backend/renderview.cpp
@@ -418,13 +418,15 @@ QVector<RenderCommand *> RenderView::buildDrawRenderCommands(const QVector<Entit
const Qt3DCore::QNodeId materialComponentId = node->componentUuid<Material>();
const QVector<RenderPassParameterData> renderPassData = m_parameters.value(materialComponentId);
+ HGeometry geometryHandle = m_manager->lookupHandle<Geometry, GeometryManager, HGeometry>(geometryRenderer->geometryId());
+ Geometry *geometry = m_manager->data<Geometry, GeometryManager>(geometryHandle);
// 1 RenderCommand per RenderPass pass on an Entity with a Mesh
for (const RenderPassParameterData &passData : renderPassData) {
// Add the RenderPass Parameters
RenderCommand *command = new RenderCommand();
command->m_depth = m_data.m_eyePos.distanceToPoint(node->worldBoundingVolume()->center());
- command->m_geometry = m_manager->lookupHandle<Geometry, GeometryManager, HGeometry>(geometryRenderer->geometryId());
+ command->m_geometry = geometryHandle;
command->m_geometryRenderer = geometryRendererHandle;
// For RenderPass based states we use the globally set RenderState
// if no renderstates are defined as part of the pass. That means:
@@ -455,6 +457,51 @@ QVector<RenderCommand *> RenderView::buildDrawRenderCommands(const QVector<Entit
// make sure this is cleared before we leave this function
setShaderAndUniforms(command, pass, globalParameters, *(node->worldTransform()), lightSources.mid(0, std::max(lightSources.size(), MAX_LIGHTS)));
+ // Store all necessary information for actual drawing if command is valid
+ command->m_isValid = !command->m_attributes.empty();
+ if (command->m_isValid) {
+ // Update the draw command with what's going to be needed for the drawing
+ uint primitiveCount = geometryRenderer->vertexCount();
+ uint estimatedCount = 0;
+ Attribute *indexAttribute = nullptr;
+
+ const QVector<Qt3DCore::QNodeId> attributeIds = geometry->attributes();
+ for (Qt3DCore::QNodeId attributeId : attributeIds) {
+ Attribute *attribute = m_manager->attributeManager()->lookupResource(attributeId);
+ if (attribute->attributeType() == QAttribute::IndexAttribute)
+ indexAttribute = attribute;
+ else if (command->m_attributes.contains(attribute->nameId()))
+ estimatedCount = qMax(attribute->count(), estimatedCount);
+ }
+
+ // Update the draw command with all the information required for the drawing
+ command->m_drawIndexed = (indexAttribute != nullptr);
+ if (command->m_drawIndexed) {
+ command->m_indexAttributeDataType = GraphicsContext::glDataTypeFromAttributeDataType(indexAttribute->vertexBaseType());
+ command->m_indexAttributeByteOffset = indexAttribute->byteOffset();
+ }
+
+ // Use the count specified by the GeometryRender
+ // If not specified use the indexAttribute count if present
+ // Otherwise tries to use the count from the attribute with the highest count
+ if (primitiveCount == 0) {
+ if (indexAttribute)
+ primitiveCount = indexAttribute->count();
+ else
+ primitiveCount = estimatedCount;
+ }
+
+ command->m_primitiveCount = primitiveCount;
+ command->m_primitiveType = geometryRenderer->primitiveType();
+ command->m_primitiveRestartEnabled = geometryRenderer->primitiveRestartEnabled();
+ command->m_restartIndexValue = geometryRenderer->restartIndexValue();
+ command->m_firstInstance = geometryRenderer->firstInstance();
+ command->m_instanceCount = geometryRenderer->instanceCount();
+ command->m_firstVertex = geometryRenderer->firstVertex();
+ command->m_indexOffset = geometryRenderer->indexOffset();
+ command->m_verticesPerPatch = geometryRenderer->verticesPerPatch();
+ }
+
buildSortingKey(command);
commands.append(command);
}
@@ -786,6 +833,9 @@ void RenderView::setShaderAndUniforms(RenderCommand *command, RenderPass *rPass,
Entity *lightEntity = lightSource.entity;
const QVector3D worldPos = lightEntity->worldBoundingVolume()->center();
for (Light *light : lightSource.lights) {
+ if (!light->isEnabled())
+ continue;
+
ShaderData *shaderData = m_manager->shaderDataManager()->lookupResource(light->shaderData());
if (!shaderData)
continue;
diff --git a/src/render/backend/uniform.cpp b/src/render/backend/uniform.cpp
index 3bc1f78ce..24b7b88ef 100644
--- a/src/render/backend/uniform.cpp
+++ b/src/render/backend/uniform.cpp
@@ -59,7 +59,7 @@ UniformValue UniformValue::fromVariant(const QVariant &variant)
UniformValue v;
switch (variant.userType()) {
case QMetaType::Bool:
- v.m_data.ivec[0] = variant.toBool();
+ v.data<bool>()[0] = variant.toBool();
break;
case QMetaType::Int:
case QMetaType::UInt:
@@ -71,85 +71,86 @@ UniformValue UniformValue::fromVariant(const QVariant &variant)
case QMetaType::UShort:
case QMetaType::Char:
case QMetaType::UChar:
- v.m_data.ivec[0] = variant.toInt();
+ v.data<int>()[0] = variant.toInt();
break;
case QMetaType::Float:
case QMetaType::Double: // Convert double to floats
- v.m_data.fvec[0] = variant.toFloat();
+ v.m_data[0] = variant.toFloat();
break;
case QMetaType::QPoint: {
const QPoint p = variant.toPoint();
- v.m_data.ivec[0] = p.x();
- v.m_data.ivec[1] = p.y();
+ v.data<int>()[0] = p.x();
+ v.data<int>()[1] = p.y();
break;
}
case QMetaType::QSize: {
const QSize s = variant.toSize();
- v.m_data.ivec[0] = s.width();
- v.m_data.ivec[1] = s.height();
+ v.data<int>()[0] = s.width();
+ v.data<int>()[1] = s.height();
break;
}
case QMetaType::QRect: {
const QRect r = variant.toRect();
- v.m_data.ivec[0] = r.x();
- v.m_data.ivec[1] = r.y();
- v.m_data.ivec[2] = r.width();
- v.m_data.ivec[3] = r.height();
+ v.data<int>()[0] = r.x();
+ v.data<int>()[1] = r.y();
+ v.data<int>()[2] = r.width();
+ v.data<int>()[3] = r.height();
break;
}
case QMetaType::QSizeF: {
const QSizeF s = variant.toSize();
- v.m_data.fvec[0] = s.width();
- v.m_data.fvec[1] = s.height();
+ v.m_data[0] = s.width();
+ v.m_data[1] = s.height();
break;
}
case QMetaType::QPointF: {
const QPointF p = variant.toPointF();
- v.m_data.fvec[0] = p.x();
- v.m_data.fvec[1] = p.y();
+ v.m_data[0] = p.x();
+ v.m_data[1] = p.y();
break;
}
case QMetaType::QRectF: {
const QRectF r = variant.toRect();
- v.m_data.fvec[0] = r.x();
- v.m_data.fvec[1] = r.y();
- v.m_data.fvec[2] = r.width();
- v.m_data.fvec[3] = r.height();
+ v.m_data[0] = r.x();
+ v.m_data[1] = r.y();
+ v.m_data[2] = r.width();
+ v.m_data[3] = r.height();
break;
}
case QMetaType::QVector2D: {
const QVector2D vec2 = variant.value<QVector2D>();
- v.m_data.fvec[0] = vec2.x();
- v.m_data.fvec[1] = vec2.y();
+ v.m_data[0] = vec2.x();
+ v.m_data[1] = vec2.y();
break;
}
case QMetaType::QVector3D: {
const QVector3D vec3 = variant.value<QVector3D>();
- v.m_data.fvec[0] = vec3.x();
- v.m_data.fvec[1] = vec3.y();
- v.m_data.fvec[2] = vec3.z();
+ v.m_data[0] = vec3.x();
+ v.m_data[1] = vec3.y();
+ v.m_data[2] = vec3.z();
break;
}
case QMetaType::QVector4D: {
const QVector4D vec4 = variant.value<QVector4D>();
- v.m_data.fvec[0] = vec4.x();
- v.m_data.fvec[1] = vec4.y();
- v.m_data.fvec[2] = vec4.z();
- v.m_data.fvec[3] = vec4.w();
+ v.m_data[0] = vec4.x();
+ v.m_data[1] = vec4.y();
+ v.m_data[2] = vec4.z();
+ v.m_data[3] = vec4.w();
break;
}
case QMetaType::QColor: {
const QColor col = variant.value<QColor>();
- v.m_data.fvec[0] = col.redF();
- v.m_data.fvec[1] = col.greenF();
- v.m_data.fvec[2] = col.blueF();
- v.m_data.fvec[3] = col.alphaF();
+ v.m_data[0] = col.redF();
+ v.m_data[1] = col.greenF();
+ v.m_data[2] = col.blueF();
+ v.m_data[3] = col.alphaF();
break;
}
case QMetaType::QMatrix4x4: {
const QMatrix4x4 mat44 = variant.value<QMatrix4x4>();
// Use constData because we want column-major layout
- memcpy(v.data<float>(), mat44.constData(), sizeof(16 * sizeof(float)));
+ v.m_data.resize(16);
+ memcpy(v.data<float>(), mat44.constData(), 16 * sizeof(float));
break;
}
default:
diff --git a/src/render/backend/uniform_p.h b/src/render/backend/uniform_p.h
index aa4b06bf9..dc16365a0 100644
--- a/src/render/backend/uniform_p.h
+++ b/src/render/backend/uniform_p.h
@@ -123,40 +123,49 @@ public:
// and not float. Otherwise, at when filling the uniforms, calling constData<float>
// on something that contains a double will result in wrong values
- UniformValue() {}
- UniformValue(int i) { m_data.ivec[0] = i; }
- UniformValue(uint i) { m_data.ivec[0] = i; }
- UniformValue(float f) { m_data.fvec[0] = f; }
- UniformValue(double d) { m_data.fvec[0] = d; } // Double to float conversion
- UniformValue(bool b) { m_data.ivec[0] = b; }
- UniformValue(const QVector2D &vec2) { memcpy(&m_data, &vec2, sizeof(QVector2D)); }
- UniformValue(const QVector3D &vec3) { memcpy(&m_data, &vec3, sizeof(QVector3D)); }
- UniformValue(const QVector4D &vec4) { memcpy(&m_data, &vec4, sizeof(QVector4D)); }
+ UniformValue()
+ : m_data(4)
+ {
+ memset(m_data.data(), 0, m_data.size() * sizeof(float));
+ }
+
+ UniformValue(int i) : UniformValue() { data<int>()[0] = i; }
+ UniformValue(uint i) : UniformValue() { data<uint>()[0] = i; }
+ UniformValue(float f) : UniformValue() { data<float>()[0] = f; }
+ UniformValue(double d) : UniformValue() { data<float>()[0] = d; } // Double to float conversion
+ UniformValue(bool b) : UniformValue() { data<bool>()[0] = b; }
+ UniformValue(const QVector2D &vec2) : UniformValue() { memcpy(m_data.data(), &vec2, sizeof(QVector2D)); }
+ UniformValue(const QVector3D &vec3) : UniformValue() { memcpy(m_data.data(), &vec3, sizeof(QVector3D)); }
+ UniformValue(const QVector4D &vec4) : m_data(4) { memcpy(m_data.data(), &vec4, sizeof(QVector4D)); }
UniformValue(const QMatrix3x3 &mat33)
+ : m_data(9)
{
// Use constData because we want column-major layout
- memcpy(&m_data, mat33.constData(), 9 * sizeof(float));
+ memcpy(m_data.data(), mat33.constData(), 9 * sizeof(float));
}
UniformValue(const QMatrix4x4 &mat44)
+ : m_data(16)
{
// Use constData because we want column-major layout
- memcpy(&m_data, mat44.constData(), 16 * sizeof(float));
+ memcpy(m_data.data(), mat44.constData(), 16 * sizeof(float));
}
// For nodes which will later be replaced by a Texture or Buffer
UniformValue(Qt3DCore::QNodeId id)
+ : UniformValue()
{
m_valueType = NodeId;
- memcpy(&m_data, &id, sizeof(Qt3DCore::QNodeId));
+ memcpy(m_data.data(), &id, sizeof(Qt3DCore::QNodeId));
}
// For textures
UniformValue(UniformValue::Texture t)
+ : UniformValue()
{
m_valueType = TextureValue;
- memcpy(&m_data, &t, sizeof(Texture));
+ memcpy(m_data.data(), &t, sizeof(Texture));
}
ValueType valueType() const { return m_valueType; }
@@ -166,18 +175,18 @@ public:
template<typename T>
const T *constData() const
{
- return reinterpret_cast<const T *>(&m_data);
+ return reinterpret_cast<const T *>(m_data.constData());
}
template<typename T>
T *data()
{
- return reinterpret_cast<T *>(&m_data);
+ return reinterpret_cast<T *>(m_data.data());
}
bool operator==(const UniformValue &other) const
{
- return memcmp(&m_data, &other.m_data, sizeof(u_Uniform)) == 0;
+ return other.m_data == m_data;
}
bool operator!=(const UniformValue &other) const
@@ -185,15 +194,9 @@ public:
return !(*this == other);
}
private:
- union u_Uniform {
- int ivec[4]; // store uint/ints/bools
- float fvec[16]; // for matrix4 (note: we could have a special case for matrices)
-
- u_Uniform()
- {
- memset(this, 0, sizeof(u_Uniform));
- }
- } m_data;
+ // Allocate 4 floats on stack
+ // For larger elements, heap allocation will be used
+ QVarLengthArray<float, 4> m_data;
ValueType m_valueType = ScalarValue;
};
diff --git a/src/render/framegraph/framegraphnode.cpp b/src/render/framegraph/framegraphnode.cpp
index 5d1df3a8c..dcf3cfacc 100644
--- a/src/render/framegraph/framegraphnode.cpp
+++ b/src/render/framegraph/framegraphnode.cpp
@@ -40,6 +40,8 @@
#include "framegraphnode_p.h"
#include <Qt3DRender/private/renderer_p.h>
#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DCore/qpropertynoderemovedchange.h>
+#include <Qt3DCore/qpropertynodeaddedchange.h>
QT_BEGIN_NAMESPACE
@@ -84,6 +86,12 @@ FrameGraphManager *FrameGraphNode::manager() const
void FrameGraphNode::setParentId(Qt3DCore::QNodeId parentId)
{
if (m_parentId != parentId) {
+ // We already had a parent, tell it to abandon us
+ if (!m_parentId.isNull()) {
+ FrameGraphNode *parent = m_manager->lookupNode(m_parentId);
+ if (parent != nullptr)
+ parent->m_childrenIds.removeAll(peerId());
+ }
m_parentId = parentId;
FrameGraphNode *parent = m_manager->lookupNode(m_parentId);
if (parent != nullptr && !parent->m_childrenIds.contains(peerId()))
@@ -141,6 +149,31 @@ QVector<FrameGraphNode *> FrameGraphNode::children() const
return children;
}
+void FrameGraphNode::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
+{
+ switch (e->type()) {
+
+ case Qt3DCore::PropertyValueAdded: {
+ Qt3DCore::QPropertyNodeAddedChangePtr change = qSharedPointerCast<Qt3DCore::QPropertyNodeAddedChange>(e);
+ if (change->metaObject()->inherits(&QFrameGraphNode::staticMetaObject))
+ appendChildId(change->addedNodeId());
+ break;
+ }
+
+ case Qt3DCore::PropertyValueRemoved: {
+ Qt3DCore::QPropertyNodeRemovedChangePtr change = qSharedPointerCast<Qt3DCore::QPropertyNodeRemovedChange>(e);
+ if (change->metaObject()->inherits(&QFrameGraphNode::staticMetaObject))
+ removeChildId(change->removedNodeId());
+ break;
+ }
+ default:
+ break;
+ }
+
+ markDirty(AbstractRenderer::AllDirty);
+ BackendNode::sceneChangeEvent(e);
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/framegraph/framegraphnode_p.h b/src/render/framegraph/framegraphnode_p.h
index c6e58823b..a29fb8070 100644
--- a/src/render/framegraph/framegraphnode_p.h
+++ b/src/render/framegraph/framegraphnode_p.h
@@ -107,6 +107,8 @@ public:
FrameGraphNode *parent() const;
QVector<FrameGraphNode *> children() const;
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE;
+
protected:
FrameGraphNode(FrameGraphNodeType nodeType, QBackendNode::Mode mode = QBackendNode::ReadOnly);
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_OVERRIDE;
diff --git a/src/render/framegraph/framegraphvisitor.cpp b/src/render/framegraph/framegraphvisitor.cpp
index 3afde9574..4d955724d 100644
--- a/src/render/framegraph/framegraphvisitor.cpp
+++ b/src/render/framegraph/framegraphvisitor.cpp
@@ -228,22 +228,29 @@ void FrameGraphVisitor::visit(Render::FrameGraphNode *node)
rv->setLightSources(std::move(lightGatherer->lights()));
// Remove all entities from the compute and renderable vectors that aren't in the filtered layer vector
- const QVector<Entity *> filteredEntities = filterEntityByLayer->filteredEntities();
+ QVector<Entity *> filteredEntities = filterEntityByLayer->filteredEntities();
- // Note: this could further be improved if needed
- // Set the renderable and computable entities
+ // We sort the vector so that the removal can then be performed linearly
if (!rv->isCompute()) {
QVector<Entity *> renderableEntities = std::move(renderableEntityFilterer->filteredEntities());
+ std::sort(renderableEntities.begin(), renderableEntities.end());
+ std::sort(filteredEntities.begin(), filteredEntities.end());
- for (auto i = renderableEntities.size() - 1; i >= 0; --i) {
- if (!filteredEntities.contains(renderableEntities.at(i)))
+ for (auto i = renderableEntities.size() - 1, j = filteredEntities.size() - 1; i >= 0; --i) {
+ while (j >= 0 && filteredEntities.at(j) > renderableEntities.at(i))
+ --j;
+ if (j < 0 || renderableEntities.at(i) != filteredEntities.at(j))
renderableEntities.removeAt(i);
}
if (rv->frustumCulling()) {
- const QVector<Entity *> visibleEntities = frustumCulling->visibleEntities();
- for (auto i = renderableEntities.size() - 1; i >= 0; --i) {
- if (!visibleEntities.contains(renderableEntities.at(i)))
+ QVector<Entity *> visibleEntities = frustumCulling->visibleEntities();
+ std::sort(visibleEntities.begin(), visibleEntities.end());
+
+ for (auto i = renderableEntities.size() - 1, j = visibleEntities.size() - 1; i >= 0; --i) {
+ while (j >= 0 && visibleEntities.at(j) > renderableEntities.at(i))
+ --j;
+ if (j < 0 || renderableEntities.at(i) != visibleEntities.at(j))
renderableEntities.removeAt(i);
}
}
@@ -259,10 +266,15 @@ void FrameGraphVisitor::visit(Render::FrameGraphNode *node)
} else {
QVector<Entity *> computableEntities = std::move(computeEntityFilterer->filteredEntities());
- for (auto i = computableEntities.size() - 1; i >= 0; --i) {
- if (!filteredEntities.contains(computableEntities.at(i)))
+ std::sort(computableEntities.begin(), computableEntities.end());
+
+ for (auto i = computableEntities.size() - 1, j = filteredEntities.size() - 1; i >= 0; --i) {
+ while (j >= 0 && filteredEntities.at(j) > computableEntities.at(i))
+ --j;
+ if (j < 0 || computableEntities.at(i) != filteredEntities.at(j))
computableEntities.removeAt(i);
}
+
// Split among the number of command builders
const int packetSize = computableEntities.size() / optimalParallelJobCount;
for (auto i = 0; i < optimalParallelJobCount; ++i) {
@@ -315,11 +327,11 @@ void FrameGraphVisitor::visit(Render::FrameGraphNode *node)
clearBufferInfo.drawBufferIndex = attachmentPack.getDrawBufferIndex(clearBufferInfo.attchmentPoint);
};
- auto syncRenderViewCommandBuildingJob = GenericLambdaJobPtr<decltype(syncForRenderCommandBuilding)>::create(syncForRenderCommandBuilding);
- auto syncRenderViewInitializationJob = GenericLambdaJobPtr<decltype(syncRenderViewInitialization)>::create(syncRenderViewInitialization);
- auto syncRenderViewCommandBuildersJob = GenericLambdaJobPtr<decltype(syncRenderViewCommandBuilders)>::create(syncRenderViewCommandBuilders);
- auto syncFrustumCullingJob = GenericLambdaJobPtr<decltype(syncFrustumCulling)>::create(syncFrustumCulling);
- auto setClearBufferDrawIndexJob = GenericLambdaJobPtr<decltype(setClearBufferDrawIndex)>::create(setClearBufferDrawIndex);
+ auto syncRenderViewCommandBuildingJob = GenericLambdaJobPtr<decltype(syncForRenderCommandBuilding)>::create(syncForRenderCommandBuilding, JobTypes::SyncRenderViewCommandBuilding);
+ auto syncRenderViewInitializationJob = GenericLambdaJobPtr<decltype(syncRenderViewInitialization)>::create(syncRenderViewInitialization, JobTypes::SyncRenderViewInitialization);
+ auto syncRenderViewCommandBuildersJob = GenericLambdaJobPtr<decltype(syncRenderViewCommandBuilders)>::create(syncRenderViewCommandBuilders, JobTypes::SyncRenderViewCommandBuilder);
+ auto syncFrustumCullingJob = GenericLambdaJobPtr<decltype(syncFrustumCulling)>::create(syncFrustumCulling, JobTypes::SyncFrustumCulling);
+ auto setClearBufferDrawIndexJob = GenericLambdaJobPtr<decltype(setClearBufferDrawIndex)>::create(setClearBufferDrawIndex, JobTypes::ClearBufferDrawIndex);
// Set dependencies
syncFrustumCullingJob->addDependency(renderer->updateWorldTransformJob());
diff --git a/src/render/frontend/qrendersettings.h b/src/render/frontend/qrendersettings.h
index 68e8f8d7f..3d32dda6b 100644
--- a/src/render/frontend/qrendersettings.h
+++ b/src/render/frontend/qrendersettings.h
@@ -55,7 +55,7 @@ class QT3DRENDERSHARED_EXPORT QRenderSettings : public Qt3DCore::QComponent
{
Q_OBJECT
- Q_PROPERTY(QPickingSettings* pickingSettings READ pickingSettings CONSTANT)
+ Q_PROPERTY(Qt3DRender::QPickingSettings* pickingSettings READ pickingSettings CONSTANT)
Q_PROPERTY(RenderPolicy renderPolicy READ renderPolicy WRITE setRenderPolicy NOTIFY renderPolicyChanged)
Q_PROPERTY(Qt3DRender::QFrameGraphNode *activeFrameGraph READ activeFrameGraph WRITE setActiveFrameGraph NOTIFY activeFrameGraphChanged)
Q_CLASSINFO("DefaultProperty", "activeFrameGraph")
diff --git a/src/render/graphicshelpers/graphicscontext.cpp b/src/render/graphicshelpers/graphicscontext.cpp
index 4c2d902f1..55db3db18 100644
--- a/src/render/graphicshelpers/graphicscontext.cpp
+++ b/src/render/graphicshelpers/graphicscontext.cpp
@@ -66,7 +66,7 @@
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLFunctions_4_3_Core>
#include <Qt3DRender/private/graphicshelpergl2_p.h>
-#include <Qt3DRender/private/graphicshelpergl3_p.h>
+#include <Qt3DRender/private/graphicshelpergl3_2_p.h>
#include <Qt3DRender/private/graphicshelpergl3_3_p.h>
#include <Qt3DRender/private/graphicshelpergl4_p.h>
#endif
@@ -665,7 +665,7 @@ GraphicsHelperInterface *GraphicsContext::resolveHighestOpenGLFunctions()
glHelper = new GraphicsHelperGL3_3();
} else if ((glFunctions = m_gl->versionFunctions<QOpenGLFunctions_3_2_Core>()) != nullptr) {
qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL 3.2";
- glHelper = new GraphicsHelperGL3();
+ glHelper = new GraphicsHelperGL3_2();
} else if ((glFunctions = m_gl->versionFunctions<QOpenGLFunctions_2_0>()) != nullptr) {
qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL 2 Helper";
glHelper = new GraphicsHelperGL2();
@@ -1261,6 +1261,7 @@ void GraphicsContext::applyUniform(const ShaderUniform &description, const Unifo
break;
case UniformType::Mat4x2:
applyUniformHelper<UniformType::Mat4x2>(description.m_location, v);
+ break;
case UniformType::Mat3x4:
applyUniformHelper<UniformType::Mat3x4>(description.m_location, v);
break;
diff --git a/src/render/graphicshelpers/graphicshelpergl3.cpp b/src/render/graphicshelpers/graphicshelpergl3_2.cpp
index da1b95db8..3cb0dd7e5 100644
--- a/src/render/graphicshelpers/graphicshelpergl3.cpp
+++ b/src/render/graphicshelpers/graphicshelpergl3_2.cpp
@@ -37,7 +37,7 @@
**
****************************************************************************/
-#include "graphicshelpergl3_p.h"
+#include "graphicshelpergl3_2_p.h"
#ifndef QT_OPENGL_ES_2
#include <QOpenGLFunctions_3_2_Core>
@@ -71,13 +71,17 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
namespace Render {
-GraphicsHelperGL3::GraphicsHelperGL3()
+GraphicsHelperGL3_2::GraphicsHelperGL3_2()
: m_funcs(nullptr)
, m_tessFuncs()
{
}
-void GraphicsHelperGL3::initializeHelper(QOpenGLContext *context,
+GraphicsHelperGL3_2::~GraphicsHelperGL3_2()
+{
+}
+
+void GraphicsHelperGL3_2::initializeHelper(QOpenGLContext *context,
QAbstractOpenGLFunctions *functions)
{
m_funcs = static_cast<QOpenGLFunctions_3_2_Core*>(functions);
@@ -91,7 +95,7 @@ void GraphicsHelperGL3::initializeHelper(QOpenGLContext *context,
}
}
-void GraphicsHelperGL3::drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType,
+void GraphicsHelperGL3_2::drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType,
GLsizei primitiveCount,
GLint indexType,
void *indices,
@@ -111,7 +115,7 @@ void GraphicsHelperGL3::drawElementsInstancedBaseVertexBaseInstance(GLenum primi
baseVertex);
}
-void GraphicsHelperGL3::drawArraysInstanced(GLenum primitiveType,
+void GraphicsHelperGL3_2::drawArraysInstanced(GLenum primitiveType,
GLint first,
GLsizei count,
GLsizei instances)
@@ -123,7 +127,7 @@ void GraphicsHelperGL3::drawArraysInstanced(GLenum primitiveType,
instances);
}
-void GraphicsHelperGL3::drawArraysInstancedBaseInstance(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances, GLsizei baseInstance)
+void GraphicsHelperGL3_2::drawArraysInstancedBaseInstance(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances, GLsizei baseInstance)
{
if (baseInstance != 0)
qWarning() << "glDrawArraysInstancedBaseInstance is not supported with OpenGL 3";
@@ -133,7 +137,7 @@ void GraphicsHelperGL3::drawArraysInstancedBaseInstance(GLenum primitiveType, GL
instances);
}
-void GraphicsHelperGL3::drawElements(GLenum primitiveType,
+void GraphicsHelperGL3_2::drawElements(GLenum primitiveType,
GLsizei primitiveCount,
GLint indexType,
void *indices,
@@ -146,7 +150,7 @@ void GraphicsHelperGL3::drawElements(GLenum primitiveType,
baseVertex);
}
-void GraphicsHelperGL3::drawArrays(GLenum primitiveType,
+void GraphicsHelperGL3_2::drawArrays(GLenum primitiveType,
GLint first,
GLsizei count)
{
@@ -155,7 +159,7 @@ void GraphicsHelperGL3::drawArrays(GLenum primitiveType,
count);
}
-void GraphicsHelperGL3::setVerticesPerPatch(GLint verticesPerPatch)
+void GraphicsHelperGL3_2::setVerticesPerPatch(GLint verticesPerPatch)
{
#if defined(QT_OPENGL_4)
if (!m_tessFuncs) {
@@ -170,12 +174,12 @@ void GraphicsHelperGL3::setVerticesPerPatch(GLint verticesPerPatch)
#endif
}
-void GraphicsHelperGL3::useProgram(GLuint programId)
+void GraphicsHelperGL3_2::useProgram(GLuint programId)
{
m_funcs->glUseProgram(programId);
}
-QVector<ShaderUniform> GraphicsHelperGL3::programUniformsAndLocations(GLuint programId)
+QVector<ShaderUniform> GraphicsHelperGL3_2::programUniformsAndLocations(GLuint programId)
{
QVector<ShaderUniform> uniforms;
@@ -207,7 +211,7 @@ QVector<ShaderUniform> GraphicsHelperGL3::programUniformsAndLocations(GLuint pro
return uniforms;
}
-QVector<ShaderAttribute> GraphicsHelperGL3::programAttributesAndLocations(GLuint programId)
+QVector<ShaderAttribute> GraphicsHelperGL3_2::programAttributesAndLocations(GLuint programId)
{
QVector<ShaderAttribute> attributes;
GLint nbrActiveAttributes = 0;
@@ -229,7 +233,7 @@ QVector<ShaderAttribute> GraphicsHelperGL3::programAttributesAndLocations(GLuint
return attributes;
}
-QVector<ShaderUniformBlock> GraphicsHelperGL3::programUniformBlocks(GLuint programId)
+QVector<ShaderUniformBlock> GraphicsHelperGL3_2::programUniformBlocks(GLuint programId)
{
QVector<ShaderUniformBlock> blocks;
GLint nbrActiveUniformsBlocks = 0;
@@ -250,7 +254,7 @@ QVector<ShaderUniformBlock> GraphicsHelperGL3::programUniformBlocks(GLuint progr
return blocks;
}
-QVector<ShaderStorageBlock> GraphicsHelperGL3::programShaderStorageBlocks(GLuint programId)
+QVector<ShaderStorageBlock> GraphicsHelperGL3_2::programShaderStorageBlocks(GLuint programId)
{
Q_UNUSED(programId);
QVector<ShaderStorageBlock> blocks;
@@ -258,19 +262,19 @@ QVector<ShaderStorageBlock> GraphicsHelperGL3::programShaderStorageBlocks(GLuint
return blocks;
}
-void GraphicsHelperGL3::vertexAttribDivisor(GLuint index, GLuint divisor)
+void GraphicsHelperGL3_2::vertexAttribDivisor(GLuint index, GLuint divisor)
{
Q_UNUSED(index);
Q_UNUSED(divisor);
qCWarning(Render::Rendering) << "Vertex attribute divisor not available with OpenGL 3.2 core";
}
-void GraphicsHelperGL3::blendEquation(GLenum mode)
+void GraphicsHelperGL3_2::blendEquation(GLenum mode)
{
m_funcs->glBlendEquation(mode);
}
-void GraphicsHelperGL3::blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor)
+void GraphicsHelperGL3_2::blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor)
{
Q_UNUSED(buf);
Q_UNUSED(sfactor);
@@ -279,7 +283,7 @@ void GraphicsHelperGL3::blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor)
qWarning() << "glBlendFunci() not supported by OpenGL 3.0 (since OpenGL 4.0)";
}
-void GraphicsHelperGL3::blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha)
+void GraphicsHelperGL3_2::blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha)
{
Q_UNUSED(buf);
Q_UNUSED(sRGB);
@@ -290,70 +294,70 @@ void GraphicsHelperGL3::blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB,
qWarning() << "glBlendFuncSeparatei() not supported by OpenGL 3.0 (since OpenGL 4.0)";
}
-void GraphicsHelperGL3::alphaTest(GLenum, GLenum)
+void GraphicsHelperGL3_2::alphaTest(GLenum, GLenum)
{
qCWarning(Render::Rendering) << "AlphaTest not available with OpenGL 3.2 core";
}
-void GraphicsHelperGL3::depthTest(GLenum mode)
+void GraphicsHelperGL3_2::depthTest(GLenum mode)
{
m_funcs->glEnable(GL_DEPTH_TEST);
m_funcs->glDepthFunc(mode);
}
-void GraphicsHelperGL3::depthMask(GLenum mode)
+void GraphicsHelperGL3_2::depthMask(GLenum mode)
{
m_funcs->glDepthMask(mode);
}
-void GraphicsHelperGL3::frontFace(GLenum mode)
+void GraphicsHelperGL3_2::frontFace(GLenum mode)
{
m_funcs->glFrontFace(mode);
}
-void GraphicsHelperGL3::setMSAAEnabled(bool enabled)
+void GraphicsHelperGL3_2::setMSAAEnabled(bool enabled)
{
enabled ? m_funcs->glEnable(GL_MULTISAMPLE)
: m_funcs->glDisable(GL_MULTISAMPLE);
}
-void GraphicsHelperGL3::setAlphaCoverageEnabled(bool enabled)
+void GraphicsHelperGL3_2::setAlphaCoverageEnabled(bool enabled)
{
enabled ? m_funcs->glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE)
: m_funcs->glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
}
-GLuint GraphicsHelperGL3::createFrameBufferObject()
+GLuint GraphicsHelperGL3_2::createFrameBufferObject()
{
GLuint id;
m_funcs->glGenFramebuffers(1, &id);
return id;
}
-void GraphicsHelperGL3::releaseFrameBufferObject(GLuint frameBufferId)
+void GraphicsHelperGL3_2::releaseFrameBufferObject(GLuint frameBufferId)
{
m_funcs->glDeleteFramebuffers(1, &frameBufferId);
}
-void GraphicsHelperGL3::bindFrameBufferObject(GLuint frameBufferId)
+void GraphicsHelperGL3_2::bindFrameBufferObject(GLuint frameBufferId)
{
m_funcs->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBufferId);
}
-GLuint GraphicsHelperGL3::boundFrameBufferObject()
+GLuint GraphicsHelperGL3_2::boundFrameBufferObject()
{
GLint id = 0;
m_funcs->glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &id);
return id;
}
-bool GraphicsHelperGL3::checkFrameBufferComplete()
+bool GraphicsHelperGL3_2::checkFrameBufferComplete()
{
return (m_funcs->glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
}
-void GraphicsHelperGL3::bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment)
+void GraphicsHelperGL3_2::bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment)
{
GLenum attr = GL_DEPTH_STENCIL_ATTACHMENT;
@@ -378,7 +382,7 @@ void GraphicsHelperGL3::bindFrameBufferAttachment(QOpenGLTexture *texture, const
texture->release();
}
-bool GraphicsHelperGL3::supportsFeature(GraphicsHelperInterface::Feature feature) const
+bool GraphicsHelperGL3_2::supportsFeature(GraphicsHelperInterface::Feature feature) const
{
switch (feature) {
case MRT:
@@ -386,6 +390,7 @@ bool GraphicsHelperGL3::supportsFeature(GraphicsHelperInterface::Feature feature
case PrimitiveRestart:
case RenderBufferDimensionRetrieval:
case TextureDimensionRetrieval:
+ case BindableFragmentOutputs:
return true;
case Tessellation:
return !m_tessFuncs.isNull();
@@ -394,7 +399,7 @@ bool GraphicsHelperGL3::supportsFeature(GraphicsHelperInterface::Feature feature
}
}
-void GraphicsHelperGL3::drawBuffers(GLsizei n, const int *bufs)
+void GraphicsHelperGL3_2::drawBuffers(GLsizei n, const int *bufs)
{
// Use QVarLengthArray here
QVarLengthArray<GLenum, 16> drawBufs(n);
@@ -404,18 +409,18 @@ void GraphicsHelperGL3::drawBuffers(GLsizei n, const int *bufs)
m_funcs->glDrawBuffers(n, drawBufs.constData());
}
-void GraphicsHelperGL3::bindFragDataLocation(GLuint shader, const QHash<QString, int> &outputs)
+void GraphicsHelperGL3_2::bindFragDataLocation(GLuint shader, const QHash<QString, int> &outputs)
{
for (auto it = outputs.begin(), end = outputs.end(); it != end; ++it)
m_funcs->glBindFragDataLocation(shader, it.value(), it.key().toStdString().c_str());
}
-void GraphicsHelperGL3::bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
+void GraphicsHelperGL3_2::bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
{
m_funcs->glUniformBlockBinding(programId, uniformBlockIndex, uniformBlockBinding);
}
-void GraphicsHelperGL3::bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding)
+void GraphicsHelperGL3_2::bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding)
{
Q_UNUSED(programId);
Q_UNUSED(shaderStorageBlockIndex);
@@ -423,12 +428,12 @@ void GraphicsHelperGL3::bindShaderStorageBlock(GLuint programId, GLuint shaderSt
qWarning() << "SSBO are not supported by OpenGL 3.0 (since OpenGL 4.3)";
}
-void GraphicsHelperGL3::bindBufferBase(GLenum target, GLuint index, GLuint buffer)
+void GraphicsHelperGL3_2::bindBufferBase(GLenum target, GLuint index, GLuint buffer)
{
m_funcs->glBindBufferBase(target, index, buffer);
}
-void GraphicsHelperGL3::buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer)
+void GraphicsHelperGL3_2::buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer)
{
char *bufferData = buffer.data();
@@ -632,7 +637,7 @@ void GraphicsHelperGL3::buildUniformBuffer(const QVariant &v, const ShaderUnifor
}
}
-uint GraphicsHelperGL3::uniformByteSize(const ShaderUniform &description)
+uint GraphicsHelperGL3_2::uniformByteSize(const ShaderUniform &description)
{
uint rawByteSize = 0;
int arrayStride = qMax(description.m_arrayStride, 0);
@@ -756,17 +761,17 @@ uint GraphicsHelperGL3::uniformByteSize(const ShaderUniform &description)
return arrayStride ? rawByteSize * arrayStride : rawByteSize;
}
-void GraphicsHelperGL3::enableClipPlane(int clipPlane)
+void GraphicsHelperGL3_2::enableClipPlane(int clipPlane)
{
m_funcs->glEnable(GL_CLIP_DISTANCE0 + clipPlane);
}
-void GraphicsHelperGL3::disableClipPlane(int clipPlane)
+void GraphicsHelperGL3_2::disableClipPlane(int clipPlane)
{
m_funcs->glDisable(GL_CLIP_DISTANCE0 + clipPlane);
}
-void GraphicsHelperGL3::setClipPlane(int clipPlane, const QVector3D &normal, float distance)
+void GraphicsHelperGL3_2::setClipPlane(int clipPlane, const QVector3D &normal, float distance)
{
// deprecated
Q_UNUSED(clipPlane);
@@ -774,31 +779,31 @@ void GraphicsHelperGL3::setClipPlane(int clipPlane, const QVector3D &normal, flo
Q_UNUSED(distance);
}
-GLint GraphicsHelperGL3::maxClipPlaneCount()
+GLint GraphicsHelperGL3_2::maxClipPlaneCount()
{
GLint max = 0;
m_funcs->glGetIntegerv(GL_MAX_CLIP_DISTANCES, &max);
return max;
}
-void GraphicsHelperGL3::enablePrimitiveRestart(int primitiveRestartIndex)
+void GraphicsHelperGL3_2::enablePrimitiveRestart(int primitiveRestartIndex)
{
m_funcs->glPrimitiveRestartIndex(primitiveRestartIndex);
m_funcs->glEnable(GL_PRIMITIVE_RESTART);
}
-void GraphicsHelperGL3::disablePrimitiveRestart()
+void GraphicsHelperGL3_2::disablePrimitiveRestart()
{
m_funcs->glDisable(GL_PRIMITIVE_RESTART);
}
-void GraphicsHelperGL3::clearBufferf(GLint drawbuffer, const QVector4D &values)
+void GraphicsHelperGL3_2::clearBufferf(GLint drawbuffer, const QVector4D &values)
{
GLfloat vec[4] = {values[0], values[1], values[2], values[3]};
m_funcs->glClearBufferfv(GL_COLOR, drawbuffer, vec);
}
-void GraphicsHelperGL3::pointSize(bool programmable, GLfloat value)
+void GraphicsHelperGL3_2::pointSize(bool programmable, GLfloat value)
{
if (programmable) {
m_funcs->glEnable(GL_PROGRAM_POINT_SIZE);
@@ -808,23 +813,25 @@ void GraphicsHelperGL3::pointSize(bool programmable, GLfloat value)
}
}
-void GraphicsHelperGL3::enablei(GLenum cap, GLuint index)
+void GraphicsHelperGL3_2::enablei(GLenum cap, GLuint index)
{
m_funcs->glEnablei(cap, index);
}
-void GraphicsHelperGL3::disablei(GLenum cap, GLuint index)
+void GraphicsHelperGL3_2::disablei(GLenum cap, GLuint index)
{
m_funcs->glDisablei(cap, index);
}
-void GraphicsHelperGL3::setSeamlessCubemap(bool enable)
+void GraphicsHelperGL3_2::setSeamlessCubemap(bool enable)
{
- Q_UNUSED(enable);
- qWarning() << "GL_TEXTURE_CUBE_MAP_SEAMLESS not supported by OpenGL 3.0 (since 3.2)";
+ if (enable)
+ m_funcs->glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
+ else
+ m_funcs->glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
}
-QSize GraphicsHelperGL3::getRenderBufferDimensions(GLuint renderBufferId)
+QSize GraphicsHelperGL3_2::getRenderBufferDimensions(GLuint renderBufferId)
{
GLint width = 0;
GLint height = 0;
@@ -837,7 +844,7 @@ QSize GraphicsHelperGL3::getRenderBufferDimensions(GLuint renderBufferId)
return QSize(width, height);
}
-QSize GraphicsHelperGL3::getTextureDimensions(GLuint textureId, GLenum target, uint level)
+QSize GraphicsHelperGL3_2::getTextureDimensions(GLuint textureId, GLenum target, uint level)
{
GLint width = 0;
GLint height = 0;
@@ -850,120 +857,120 @@ QSize GraphicsHelperGL3::getTextureDimensions(GLuint textureId, GLenum target, u
return QSize(width, height);
}
-void GraphicsHelperGL3::dispatchCompute(GLuint wx, GLuint wy, GLuint wz)
+void GraphicsHelperGL3_2::dispatchCompute(GLuint wx, GLuint wy, GLuint wz)
{
Q_UNUSED(wx);
Q_UNUSED(wy);
Q_UNUSED(wz);
- qWarning() << "Compute Shaders are not supported by OpenGL 3.0 (since OpenGL 4.3)";
+ qWarning() << "Compute Shaders are not supported by OpenGL 3.2 (since OpenGL 4.3)";
}
-void GraphicsHelperGL3::glUniform1fv(GLint location, GLsizei count, const GLfloat *values)
+void GraphicsHelperGL3_2::glUniform1fv(GLint location, GLsizei count, const GLfloat *values)
{
m_funcs->glUniform1fv(location, count, values);
}
-void GraphicsHelperGL3::glUniform2fv(GLint location, GLsizei count, const GLfloat *values)
+void GraphicsHelperGL3_2::glUniform2fv(GLint location, GLsizei count, const GLfloat *values)
{
m_funcs->glUniform2fv(location, count, values);
}
-void GraphicsHelperGL3::glUniform3fv(GLint location, GLsizei count, const GLfloat *values)
+void GraphicsHelperGL3_2::glUniform3fv(GLint location, GLsizei count, const GLfloat *values)
{
m_funcs->glUniform3fv(location, count, values);
}
-void GraphicsHelperGL3::glUniform4fv(GLint location, GLsizei count, const GLfloat *values)
+void GraphicsHelperGL3_2::glUniform4fv(GLint location, GLsizei count, const GLfloat *values)
{
m_funcs->glUniform4fv(location, count, values);
}
-void GraphicsHelperGL3::glUniform1iv(GLint location, GLsizei count, const GLint *values)
+void GraphicsHelperGL3_2::glUniform1iv(GLint location, GLsizei count, const GLint *values)
{
m_funcs->glUniform1iv(location, count, values);
}
-void GraphicsHelperGL3::glUniform2iv(GLint location, GLsizei count, const GLint *values)
+void GraphicsHelperGL3_2::glUniform2iv(GLint location, GLsizei count, const GLint *values)
{
m_funcs->glUniform2iv(location, count, values);
}
-void GraphicsHelperGL3::glUniform3iv(GLint location, GLsizei count, const GLint *values)
+void GraphicsHelperGL3_2::glUniform3iv(GLint location, GLsizei count, const GLint *values)
{
m_funcs->glUniform3iv(location, count, values);
}
-void GraphicsHelperGL3::glUniform4iv(GLint location, GLsizei count, const GLint *values)
+void GraphicsHelperGL3_2::glUniform4iv(GLint location, GLsizei count, const GLint *values)
{
m_funcs->glUniform4iv(location, count, values);
}
-void GraphicsHelperGL3::glUniform1uiv(GLint location, GLsizei count, const GLuint *values)
+void GraphicsHelperGL3_2::glUniform1uiv(GLint location, GLsizei count, const GLuint *values)
{
m_funcs->glUniform1uiv(location, count, values);
}
-void GraphicsHelperGL3::glUniform2uiv(GLint location, GLsizei count, const GLuint *values)
+void GraphicsHelperGL3_2::glUniform2uiv(GLint location, GLsizei count, const GLuint *values)
{
m_funcs->glUniform2uiv(location, count, values);
}
-void GraphicsHelperGL3::glUniform3uiv(GLint location, GLsizei count, const GLuint *values)
+void GraphicsHelperGL3_2::glUniform3uiv(GLint location, GLsizei count, const GLuint *values)
{
m_funcs->glUniform3uiv(location, count, values);
}
-void GraphicsHelperGL3::glUniform4uiv(GLint location, GLsizei count, const GLuint *values)
+void GraphicsHelperGL3_2::glUniform4uiv(GLint location, GLsizei count, const GLuint *values)
{
m_funcs->glUniform4uiv(location, count, values);
}
-void GraphicsHelperGL3::glUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *values)
+void GraphicsHelperGL3_2::glUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *values)
{
m_funcs->glUniformMatrix2fv(location, count, false, values);
}
-void GraphicsHelperGL3::glUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *values)
+void GraphicsHelperGL3_2::glUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *values)
{
m_funcs->glUniformMatrix3fv(location, count, false, values);
}
-void GraphicsHelperGL3::glUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *values)
+void GraphicsHelperGL3_2::glUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *values)
{
m_funcs->glUniformMatrix4fv(location, count, false, values);
}
-void GraphicsHelperGL3::glUniformMatrix2x3fv(GLint location, GLsizei count, const GLfloat *values)
+void GraphicsHelperGL3_2::glUniformMatrix2x3fv(GLint location, GLsizei count, const GLfloat *values)
{
m_funcs->glUniformMatrix2x3fv(location, count, false, values);
}
-void GraphicsHelperGL3::glUniformMatrix3x2fv(GLint location, GLsizei count, const GLfloat *values)
+void GraphicsHelperGL3_2::glUniformMatrix3x2fv(GLint location, GLsizei count, const GLfloat *values)
{
m_funcs->glUniformMatrix3x2fv(location, count, false, values);
}
-void GraphicsHelperGL3::glUniformMatrix2x4fv(GLint location, GLsizei count, const GLfloat *values)
+void GraphicsHelperGL3_2::glUniformMatrix2x4fv(GLint location, GLsizei count, const GLfloat *values)
{
m_funcs->glUniformMatrix2x4fv(location, count, false, values);
}
-void GraphicsHelperGL3::glUniformMatrix4x2fv(GLint location, GLsizei count, const GLfloat *values)
+void GraphicsHelperGL3_2::glUniformMatrix4x2fv(GLint location, GLsizei count, const GLfloat *values)
{
m_funcs->glUniformMatrix4x2fv(location, count, false, values);
}
-void GraphicsHelperGL3::glUniformMatrix3x4fv(GLint location, GLsizei count, const GLfloat *values)
+void GraphicsHelperGL3_2::glUniformMatrix3x4fv(GLint location, GLsizei count, const GLfloat *values)
{
m_funcs->glUniformMatrix3x4fv(location, count, false, values);
}
-void GraphicsHelperGL3::glUniformMatrix4x3fv(GLint location, GLsizei count, const GLfloat *values)
+void GraphicsHelperGL3_2::glUniformMatrix4x3fv(GLint location, GLsizei count, const GLfloat *values)
{
m_funcs->glUniformMatrix4x3fv(location, count, false, values);
}
-UniformType GraphicsHelperGL3::uniformTypeFromGLType(GLenum type)
+UniformType GraphicsHelperGL3_2::uniformTypeFromGLType(GLenum type)
{
switch (type) {
case GL_FLOAT:
@@ -1000,6 +1007,14 @@ UniformType GraphicsHelperGL3::uniformTypeFromGLType(GLenum type)
return UniformType::IVec3;
case GL_INT_VEC4:
return UniformType::IVec4;
+ case GL_UNSIGNED_INT:
+ return UniformType::UInt;
+ case GL_UNSIGNED_INT_VEC2:
+ return UniformType::UIVec2;
+ case GL_UNSIGNED_INT_VEC3:
+ return UniformType::UIVec3;
+ case GL_UNSIGNED_INT_VEC4:
+ return UniformType::UIVec4;
case GL_BOOL:
return UniformType::Bool;
case GL_BOOL_VEC2:
@@ -1009,6 +1024,7 @@ UniformType GraphicsHelperGL3::uniformTypeFromGLType(GLenum type)
case GL_BOOL_VEC4:
return UniformType::BVec4;
+ case GL_SAMPLER_BUFFER:
case GL_SAMPLER_1D:
case GL_SAMPLER_1D_SHADOW:
case GL_SAMPLER_2D:
@@ -1017,11 +1033,13 @@ UniformType GraphicsHelperGL3::uniformTypeFromGLType(GLenum type)
case GL_SAMPLER_2D_RECT_SHADOW:
case GL_SAMPLER_CUBE:
case GL_SAMPLER_CUBE_SHADOW:
+ case GL_SAMPLER_1D_ARRAY:
case GL_SAMPLER_2D_ARRAY:
case GL_SAMPLER_2D_ARRAY_SHADOW:
case GL_SAMPLER_2D_MULTISAMPLE:
case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
case GL_SAMPLER_3D:
+ case GL_INT_SAMPLER_BUFFER:
case GL_INT_SAMPLER_1D:
case GL_INT_SAMPLER_2D:
case GL_INT_SAMPLER_3D:
@@ -1030,6 +1048,7 @@ UniformType GraphicsHelperGL3::uniformTypeFromGLType(GLenum type)
case GL_INT_SAMPLER_2D_ARRAY:
case GL_INT_SAMPLER_2D_MULTISAMPLE:
case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_BUFFER:
case GL_UNSIGNED_INT_SAMPLER_1D:
case GL_UNSIGNED_INT_SAMPLER_2D:
case GL_UNSIGNED_INT_SAMPLER_3D:
diff --git a/src/render/graphicshelpers/graphicshelpergl3_p.h b/src/render/graphicshelpers/graphicshelpergl3_2_p.h
index 3cc58bd26..b6a4b0c35 100644
--- a/src/render/graphicshelpers/graphicshelpergl3_p.h
+++ b/src/render/graphicshelpers/graphicshelpergl3_2_p.h
@@ -64,10 +64,11 @@ class QOpenGLExtension_ARB_tessellation_shader;
namespace Qt3DRender {
namespace Render {
-class GraphicsHelperGL3 : public GraphicsHelperInterface
+class Q_AUTOTEST_EXPORT GraphicsHelperGL3_2 : public GraphicsHelperInterface
{
public:
- GraphicsHelperGL3();
+ GraphicsHelperGL3_2();
+ ~GraphicsHelperGL3_2();
// QGraphicHelperInterface interface
void alphaTest(GLenum mode1, GLenum mode2) Q_DECL_OVERRIDE;
diff --git a/src/render/graphicshelpers/graphicshelpergl4_p.h b/src/render/graphicshelpers/graphicshelpergl4_p.h
index ad4875f2e..e596b185c 100644
--- a/src/render/graphicshelpers/graphicshelpergl4_p.h
+++ b/src/render/graphicshelpers/graphicshelpergl4_p.h
@@ -63,7 +63,7 @@ class QOpenGLFunctions_4_3_Core;
namespace Qt3DRender {
namespace Render {
-class GraphicsHelperGL4 : public GraphicsHelperInterface
+class Q_AUTOTEST_EXPORT GraphicsHelperGL4 : public GraphicsHelperInterface
{
public:
GraphicsHelperGL4();
diff --git a/src/render/graphicshelpers/graphicshelpers.pri b/src/render/graphicshelpers/graphicshelpers.pri
index ecf2e6b54..e9c5c1bc8 100644
--- a/src/render/graphicshelpers/graphicshelpers.pri
+++ b/src/render/graphicshelpers/graphicshelpers.pri
@@ -8,15 +8,15 @@ HEADERS += \
$$PWD/graphicshelperes2_p.h \
$$PWD/graphicshelperes3_p.h \
$$PWD/graphicshelpergl2_p.h \
- $$PWD/graphicshelpergl3_p.h \
$$PWD/graphicshelpergl3_3_p.h \
- $$PWD/graphicshelpergl4_p.h
+ $$PWD/graphicshelpergl4_p.h \
+ $$PWD/graphicshelpergl3_2_p.h
SOURCES += \
$$PWD/graphicscontext.cpp \
$$PWD/graphicshelperes2.cpp \
$$PWD/graphicshelperes3.cpp \
$$PWD/graphicshelpergl2.cpp \
- $$PWD/graphicshelpergl3.cpp \
$$PWD/graphicshelpergl3_3.cpp \
- $$PWD/graphicshelpergl4.cpp
+ $$PWD/graphicshelpergl4.cpp \
+ $$PWD/graphicshelpergl3_2.cpp
diff --git a/src/render/jobs/genericlambdajob_p.h b/src/render/jobs/genericlambdajob_p.h
index 656af7b8d..aa2fa3430 100644
--- a/src/render/jobs/genericlambdajob_p.h
+++ b/src/render/jobs/genericlambdajob_p.h
@@ -64,11 +64,11 @@ template<typename T>
class GenericLambdaJob : public Qt3DCore::QAspectJob
{
public:
- explicit GenericLambdaJob(T callable)
+ explicit GenericLambdaJob(T callable, JobTypes::JobType type = JobTypes::GenericLambda)
: Qt3DCore::QAspectJob()
, m_callable(callable)
{
- SET_JOB_RUN_STAT_TYPE(this, JobTypes::GenericLambda, 0);
+ SET_JOB_RUN_STAT_TYPE(this, type, 0);
}
// QAspectJob interface
diff --git a/src/render/jobs/job_common_p.h b/src/render/jobs/job_common_p.h
index 3266e0f6d..a5a8bb8e2 100644
--- a/src/render/jobs/job_common_p.h
+++ b/src/render/jobs/job_common_p.h
@@ -84,7 +84,15 @@ namespace JobTypes {
LightGathering,
UpdateWorldBoundingVolume,
FrameSubmissionPart2,
+ DirtyBufferGathering,
+ DirtyTextureGathering,
+ DirtyShaderGathering,
SendRenderCapture,
+ SyncRenderViewCommandBuilding,
+ SyncRenderViewInitialization,
+ SyncRenderViewCommandBuilder,
+ SyncFrustumCulling,
+ ClearBufferDrawIndex
};
} // JobTypes
diff --git a/src/render/jobs/renderviewjobutils_p.h b/src/render/jobs/renderviewjobutils_p.h
index c08083494..ad86685a9 100644
--- a/src/render/jobs/renderviewjobutils_p.h
+++ b/src/render/jobs/renderviewjobutils_p.h
@@ -116,7 +116,6 @@ struct ParameterInfo
bool operator<(const int otherNameId) const Q_DECL_NOEXCEPT;
bool operator<(const ParameterInfo &other) const Q_DECL_NOEXCEPT;
};
-QT3D_DECLARE_TYPEINFO_2(Qt3DRender, Render, ParameterInfo, Q_MOVABLE_TYPE)
typedef QVector<ParameterInfo> ParameterInfoList;
struct RenderPassParameterData
diff --git a/src/render/materialsystem/shaderdata.cpp b/src/render/materialsystem/shaderdata.cpp
index e7c8a1c37..fec1e66ac 100644
--- a/src/render/materialsystem/shaderdata.cpp
+++ b/src/render/materialsystem/shaderdata.cpp
@@ -113,7 +113,7 @@ void ShaderData::initializeFromPeer(const QNodeCreatedChangeBasePtr &change)
const QHash<QString, QVariant>::iterator end = m_originalProperties.end();
while (it != end) {
- if (static_cast<QMetaType::Type>(it.value().type()) == QMetaType::QVector3D) {
+ if (it.value().type() == QVariant::Vector3D) {
// if there is a matching QShaderData::TransformType propertyTransformed
QVariant value = m_originalProperties.value(it.key() + QLatin1String("Transformed"));
// if that's the case, we apply a space transformation to the property
diff --git a/src/render/texture/qtexture.cpp b/src/render/texture/qtexture.cpp
index 13e6a04ab..af7f35d48 100644
--- a/src/render/texture/qtexture.cpp
+++ b/src/render/texture/qtexture.cpp
@@ -623,7 +623,7 @@ QTextureImageDataPtr setDdsFile(const QString &source)
} // anonynous
-QTextureImageDataPtr TextureLoadingHelper::loadTextureData(const QUrl &url, bool allow3D)
+QTextureImageDataPtr TextureLoadingHelper::loadTextureData(const QUrl &url, bool allow3D, bool mirrored)
{
QTextureImageDataPtr textureData;
if (url.isLocalFile() || url.scheme() == QLatin1String("qrc")) {
@@ -640,7 +640,7 @@ QTextureImageDataPtr TextureLoadingHelper::loadTextureData(const QUrl &url, bool
QImage img;
if (img.load(source)) {
textureData = QTextureImageDataPtr::create();
- textureData->setImage(img.mirrored());
+ textureData->setImage(mirrored ? img.mirrored() : img);
}
break;
}
@@ -656,7 +656,7 @@ QTextureDataPtr QTextureFromSourceGenerator::operator ()()
QTextureDataPtr generatedData = QTextureDataPtr::create();
m_status = QAbstractTexture::Loading;
- const QTextureImageDataPtr textureData = TextureLoadingHelper::loadTextureData(m_url, true);
+ const QTextureImageDataPtr textureData = TextureLoadingHelper::loadTextureData(m_url, true, m_mirrored);
if (textureData && textureData->data().length() > 0) {
generatedData->setTarget(static_cast<QAbstractTexture::Target>(textureData->target()));
@@ -676,6 +676,7 @@ QTextureDataPtr QTextureFromSourceGenerator::operator ()()
QTextureLoaderPrivate::QTextureLoaderPrivate()
: QAbstractTexturePrivate()
+ , m_mirrored(true)
{
}
@@ -922,6 +923,12 @@ QUrl QTextureLoader::source() const
return d->m_source;
}
+bool QTextureLoader::isMirrored() const
+{
+ Q_D(const QTextureLoader);
+ return d->m_mirrored;
+}
+
/*!
* Sets the texture loader source to \a source.
* \param source
@@ -931,19 +938,67 @@ void QTextureLoader::setSource(const QUrl& source)
Q_D(QTextureLoader);
if (source != d->m_source) {
d->m_source = source;
- d->m_dataFunctor.reset(new QTextureFromSourceGenerator(source));
+ d->m_dataFunctor.reset(new QTextureFromSourceGenerator(source, d->m_mirrored));
emit sourceChanged(source);
}
}
/*!
+ \property Qt3DRender::QTextureLoader::mirrored
+
+ This property specifies whether the texture should be mirrored when loaded. This
+ is a convenience to avoid having to manipulate images to match the origin of
+ the texture coordinates used by the rendering API. By default this property
+ is set to true. This has no effect when using compressed texture formats.
+
+ \note OpenGL specifies the origin of texture coordinates from the lower left
+ hand corner whereas DirectX uses the the upper left hand corner.
+
+ \note When using cube map texture you'll probably want mirroring disabled as
+ the cube map sampler takes a direction rather than regular texture
+ coordinates.
+*/
+
+/*!
+ \qmlproperty bool Qt3DRender::QTextureLoader::mirrored
+
+ This property specifies whether the texture should be mirrored when loaded. This
+ is a convenience to avoid having to manipulate images to match the origin of
+ the texture coordinates used by the rendering API. By default this property
+ is set to true. This has no effect when using compressed texture formats.
+
+ \note OpenGL specifies the origin of texture coordinates from the lower left
+ hand corner whereas DirectX uses the the upper left hand corner.
+
+ \note When using cube map texture you'll probably want mirroring disabled as
+ the cube map sampler takes a direction rather than regular texture
+ coordinates.
+*/
+
+/*!
+ Sets mirroring to \a mirrored.
+ \note This internally triggers a call to update the data generator.
+ */
+void QTextureLoader::setMirrored(bool mirrored)
+{
+ Q_D(QTextureLoader);
+ if (mirrored != d->m_mirrored) {
+ d->m_mirrored = mirrored;
+ d->m_dataFunctor.reset(new QTextureFromSourceGenerator(d->m_source, d->m_mirrored));
+ emit mirroredChanged(mirrored);
+ }
+}
+
+/*!
* Takes in a TextureGenerator via \a other and
* \return whether generators have the same source.
*/
bool QTextureFromSourceGenerator::operator ==(const QTextureGenerator &other) const
{
const QTextureFromSourceGenerator *otherFunctor = functor_cast<QTextureFromSourceGenerator>(&other);
- return (otherFunctor != Q_NULLPTR && otherFunctor->m_url == m_url);
+ return (otherFunctor != nullptr &&
+ otherFunctor->m_url == m_url &&
+ otherFunctor->m_mirrored == m_mirrored);
}
/*!
@@ -951,10 +1006,11 @@ bool QTextureFromSourceGenerator::operator ==(const QTextureGenerator &other) co
* instance with \a url.
* \param url
*/
-QTextureFromSourceGenerator::QTextureFromSourceGenerator(const QUrl &url)
+QTextureFromSourceGenerator::QTextureFromSourceGenerator(const QUrl &url, bool mirrored)
: QTextureGenerator()
, m_url(url)
, m_status(QAbstractTexture::None)
+ , m_mirrored(mirrored)
{
}
diff --git a/src/render/texture/qtexture.h b/src/render/texture/qtexture.h
index 4d687dc6d..24d19fbcf 100644
--- a/src/render/texture/qtexture.h
+++ b/src/render/texture/qtexture.h
@@ -149,18 +149,21 @@ class QT3DRENDERSHARED_EXPORT QTextureLoader : public QAbstractTexture
{
Q_OBJECT
Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
-
+ Q_PROPERTY(bool mirrored READ isMirrored WRITE setMirrored NOTIFY mirroredChanged)
public:
explicit QTextureLoader(Qt3DCore::QNode *parent = nullptr);
~QTextureLoader();
QUrl source() const;
+ bool isMirrored() const;
public Q_SLOTS:
void setSource(const QUrl &source);
+ void setMirrored(bool mirrored);
Q_SIGNALS:
void sourceChanged(const QUrl &source);
+ void mirroredChanged(bool mirrored);
private:
Q_DECLARE_PRIVATE(QTextureLoader)
diff --git a/src/render/texture/qtexture_p.h b/src/render/texture/qtexture_p.h
index d80e048f7..21fe93e2b 100644
--- a/src/render/texture/qtexture_p.h
+++ b/src/render/texture/qtexture_p.h
@@ -64,12 +64,13 @@ public:
QTextureLoaderPrivate();
QUrl m_source;
+ bool m_mirrored;
};
class QTextureFromSourceGenerator : public QTextureGenerator
{
public:
- explicit QTextureFromSourceGenerator(const QUrl &url);
+ explicit QTextureFromSourceGenerator(const QUrl &url, bool mirrored);
QTextureDataPtr operator ()() Q_DECL_OVERRIDE;
bool operator ==(const QTextureGenerator &other) const Q_DECL_OVERRIDE;
inline QAbstractTexture::Status status() const { return m_status; }
@@ -79,12 +80,13 @@ public:
private:
QUrl m_url;
QAbstractTexture::Status m_status;
+ bool m_mirrored;
};
class Q_AUTOTEST_EXPORT TextureLoadingHelper
{
public:
- static QTextureImageDataPtr loadTextureData(const QUrl &source, bool allow3D);
+ static QTextureImageDataPtr loadTextureData(const QUrl &source, bool allow3D, bool mirrored);
};
} // namespace Qt3DRender
diff --git a/src/render/texture/qtextureimage.cpp b/src/render/texture/qtextureimage.cpp
index dbe0ff05c..73459bdf6 100644
--- a/src/render/texture/qtextureimage.cpp
+++ b/src/render/texture/qtextureimage.cpp
@@ -155,8 +155,31 @@ QTextureImage::Status QTextureImage::status() const
}
/*!
+ * \return whether mirroring is enabled or not.
+ */
+bool QTextureImage::isMirrored() const
+{
+ Q_D(const QTextureImage);
+ return d->m_mirrored;
+}
+
+/*!
+ \property Qt3DRender::QTextureImage::source
+
+ This property holds the source url from which data for the texture
+ image will be loaded.
+*/
+
+/*!
+ \qmlproperty url Qt3D.Render::TextureImage::source
+
+ This property holds the source url from which data for the texture
+ image will be loaded.
+*/
+
+/*!
Sets the source url of the texture image to \a source.
- \note This triggers a call to update()
+ \note This internally triggers a call to update the data generator.
*/
void QTextureImage::setSource(const QUrl &source)
{
@@ -169,8 +192,54 @@ void QTextureImage::setSource(const QUrl &source)
}
/*!
- Sets the status to \a status.
- \param status
+ \property Qt3DRender::QTextureImage::mirrored
+
+ This property specifies whether the image should be mirrored when loaded. This
+ is a convenience to avoid having to manipulate images to match the origin of
+ the texture coordinates used by the rendering API. By default this property
+ is set to true. This has no effect when using compressed texture formats.
+
+ \note OpenGL specifies the origin of texture coordinates from the lower left
+ hand corner whereas DirectX uses the the upper left hand corner.
+
+ \note When using cube map texture you'll probably want mirroring disabled as
+ the cube map sampler takes a direction rather than regular texture
+ coordinates.
+*/
+
+/*!
+ \qmlproperty bool Qt3DRender::QTextureImage::mirrored
+
+ This property specifies whether the image should be mirrored when loaded. This
+ is a convenience to avoid having to manipulate images to match the origin of
+ the texture coordinates used by the rendering API. By default this property
+ is set to true. This has no effect when using compressed texture formats.
+
+ \note OpenGL specifies the origin of texture coordinates from the lower left
+ hand corner whereas DirectX uses the the upper left hand corner.
+
+ \note When using cube map texture you'll probably want mirroring disabled as
+ the cube map sampler takes a direction rather than regular texture
+ coordinates.
+*/
+
+/*!
+ Sets mirroring to \a mirrored.
+ \note This internally triggers a call to update the data generator.
+ */
+void QTextureImage::setMirrored(bool mirrored)
+{
+ Q_D(QTextureImage);
+ if (mirrored != d->m_mirrored) {
+ d->m_mirrored = mirrored;
+ emit mirroredChanged(mirrored);
+ notifyDataGeneratorChanged();
+ }
+}
+
+/*!
+ * Sets the status to \a status.
+ * \param status
*/
void QTextureImage::setStatus(Status status)
{
@@ -187,7 +256,7 @@ void QTextureImage::setStatus(Status status)
*/
QTextureImageDataGeneratorPtr QTextureImage::dataGenerator() const
{
- return QTextureImageDataGeneratorPtr(new QImageTextureDataFunctor(source()));
+ return QTextureImageDataGeneratorPtr(new QImageTextureDataFunctor(source(), isMirrored()));
}
/*!
@@ -206,10 +275,11 @@ void QTextureImage::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
The constructor creates a new QImageTextureDataFunctor::QImageTextureDataFunctor
instance with the specified \a url.
*/
-QImageTextureDataFunctor::QImageTextureDataFunctor(const QUrl &url)
+QImageTextureDataFunctor::QImageTextureDataFunctor(const QUrl &url, bool mirrored)
: QTextureImageDataGenerator()
, m_url(url)
, m_status(QTextureImage::None)
+ , m_mirrored(mirrored)
{
if (url.isLocalFile()) {
QFileInfo info(url.toLocalFile());
@@ -222,7 +292,7 @@ QTextureImageDataPtr QImageTextureDataFunctor::operator ()()
// We assume that a texture image is going to contain a single image data
// For compressed dds or ktx textures a warning should be issued if
// there are layers or 3D textures
- return TextureLoadingHelper::loadTextureData(m_url, false);
+ return TextureLoadingHelper::loadTextureData(m_url, false, m_mirrored);
}
bool QImageTextureDataFunctor::operator ==(const QTextureImageDataGenerator &other) const
@@ -230,7 +300,10 @@ bool QImageTextureDataFunctor::operator ==(const QTextureImageDataGenerator &oth
const QImageTextureDataFunctor *otherFunctor = functor_cast<QImageTextureDataFunctor>(&other);
// if its the same URL, but different modification times, its not the same image.
- return (otherFunctor != Q_NULLPTR && otherFunctor->m_url == m_url && otherFunctor->m_lastModified == m_lastModified);
+ return (otherFunctor != nullptr &&
+ otherFunctor->m_url == m_url &&
+ otherFunctor->m_lastModified == m_lastModified &&
+ otherFunctor->m_mirrored == m_mirrored);
}
} // namespace Qt3DRender
diff --git a/src/render/texture/qtextureimage.h b/src/render/texture/qtextureimage.h
index f614ebdab..c8d0121f8 100644
--- a/src/render/texture/qtextureimage.h
+++ b/src/render/texture/qtextureimage.h
@@ -54,6 +54,7 @@ class QT3DRENDERSHARED_EXPORT QTextureImage : public QAbstractTextureImage
Q_OBJECT
Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+ Q_PROPERTY(bool mirrored READ isMirrored WRITE setMirrored NOTIFY mirroredChanged)
public:
explicit QTextureImage(Qt3DCore::QNode *parent = nullptr);
@@ -69,13 +70,16 @@ public:
QUrl source() const;
Status status() const;
+ bool isMirrored() const;
public Q_SLOTS:
void setSource(const QUrl &source);
+ void setMirrored(bool mirrored);
Q_SIGNALS:
void sourceChanged(const QUrl &source);
void statusChanged(Status status);
+ void mirroredChanged(bool mirrored);
protected:
void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) Q_DECL_OVERRIDE;
diff --git a/src/render/texture/qtextureimage_p.h b/src/render/texture/qtextureimage_p.h
index 23ab57acb..cebd9a951 100644
--- a/src/render/texture/qtextureimage_p.h
+++ b/src/render/texture/qtextureimage_p.h
@@ -68,6 +68,7 @@ public:
QTextureImagePrivate()
: QAbstractTextureImagePrivate()
, m_status(QTextureImage::Loading)
+ , m_mirrored(true)
{
}
@@ -75,12 +76,13 @@ public:
QUrl m_source;
QTextureImage::Status m_status;
+ bool m_mirrored;
};
class QImageTextureDataFunctor : public QTextureImageDataGenerator
{
public:
- QImageTextureDataFunctor(const QUrl &url);
+ explicit QImageTextureDataFunctor(const QUrl &url, bool mirrored);
// Will be executed from within a QAspectJob
QTextureImageDataPtr operator ()() Q_DECL_FINAL;
bool operator ==(const QTextureImageDataGenerator &other) const Q_DECL_FINAL;
@@ -91,6 +93,7 @@ private:
QUrl m_url;
QDateTime m_lastModified;
QTextureImage::Status m_status;
+ bool m_mirrored;
};
} // namespace Qt3DRender
diff --git a/src/render/texture/texture_p.h b/src/render/texture/texture_p.h
index 491ac448b..4f0f25564 100644
--- a/src/render/texture/texture_p.h
+++ b/src/render/texture/texture_p.h
@@ -82,7 +82,7 @@ public:
~Texture();
void cleanup();
- QOpenGLTexture* getOrCreateGLTexture() ;
+ QOpenGLTexture *getOrCreateGLTexture();
GLint textureId();
diff --git a/tests/auto/core/handlemanager/tst_handlemanager.cpp b/tests/auto/core/handlemanager/tst_handlemanager.cpp
index 3198b54a9..f4879a3df 100644
--- a/tests/auto/core/handlemanager/tst_handlemanager.cpp
+++ b/tests/auto/core/handlemanager/tst_handlemanager.cpp
@@ -75,7 +75,7 @@ void tst_HandleManager::correctPointer()
{
// GIVEN
Qt3DCore::QHandleManager<SimpleResource> manager;
- SimpleResource *p1 = (SimpleResource *)0xdeadbeef;
+ SimpleResource *p1 = (SimpleResource *)(quintptr)0xdeadbeef;
// WHEN
const Handle h = manager.acquire(p1);
@@ -93,9 +93,9 @@ void tst_HandleManager::correctPointers()
// GIVEN
Qt3DCore::QHandleManager<SimpleResource> manager;
SimpleResource *p[3];
- p[0] = (SimpleResource *)0xdeadbeef;
- p[1] = (SimpleResource *)0x11111111;
- p[2] = (SimpleResource *)0x22222222;
+ p[0] = (SimpleResource *)(quintptr)0xdeadbeef;
+ p[1] = (SimpleResource *)(quintptr)0x11111111;
+ p[2] = (SimpleResource *)(quintptr)0x22222222;
// WHEN
for (int i = 0; i < 3; ++i) {
@@ -211,7 +211,7 @@ void tst_HandleManager::resetRemovesAllEntries()
// WHEN
for (int i = 0; i < 100; ++i) {
- SimpleResource *p = (SimpleResource *) 0xdead0000 + i;
+ SimpleResource *p = (SimpleResource *)(quintptr)(0xdead0000 + i);
const Handle h = manager.acquire(p);
bool ok = false;
@@ -240,7 +240,7 @@ void tst_HandleManager::maximumEntries()
// WHEN
for (int i = 0; i < (int)Handle::maxIndex(); ++i) {
- SimpleResource *p = (SimpleResource *) 0xdead0000 + i;
+ SimpleResource *p = (SimpleResource *)(quintptr)(0xdead0000 + i);
const Handle h = manager.acquire(p);
bool ok = false;
@@ -264,7 +264,7 @@ void tst_HandleManager::checkNoCounterOverflow()
// GIVEN
const int indexBits = 16;
Qt3DCore::QHandleManager<SimpleResource, indexBits> manager;
- SimpleResource *p = (SimpleResource *) 0xdead0000;
+ SimpleResource *p = (SimpleResource *)(quintptr)0xdead0000;
Qt3DCore::QHandle<SimpleResource, indexBits> h = manager.acquire(p);
// THEN
diff --git a/tests/auto/core/nodes/tst_nodes.cpp b/tests/auto/core/nodes/tst_nodes.cpp
index 695a93640..c221c5115 100644
--- a/tests/auto/core/nodes/tst_nodes.cpp
+++ b/tests/auto/core/nodes/tst_nodes.cpp
@@ -130,7 +130,7 @@ public:
void sceneChangeEventWithLock(const Qt3DCore::QSceneChangeList &e) Q_DECL_OVERRIDE
{
- for (uint i = 0, m = e.size(); i < m; ++i) {
+ for (size_t i = 0, m = e.size(); i < m; ++i) {
events << ChangeRecord(e.at(i), false);
}
}
diff --git a/tests/auto/core/qframeallocator/tst_qframeallocator.cpp b/tests/auto/core/qframeallocator/tst_qframeallocator.cpp
index 76d4d15ce..a098792ee 100644
--- a/tests/auto/core/qframeallocator/tst_qframeallocator.cpp
+++ b/tests/auto/core/qframeallocator/tst_qframeallocator.cpp
@@ -294,8 +294,8 @@ void tst_QFrameAllocator::containsCheckQFrameChunk()
ptrs << c.allocate(16);
}
- QVERIFY(!c.contains((void *)0xffffffff, 16));
- QVERIFY(!c2.contains((void *)0xffffffff, 16));
+ QVERIFY(!c.contains((void *)(quintptr)0xffffffff, 16));
+ QVERIFY(!c2.contains((void *)(quintptr)0xffffffff, 16));
QVERIFY(c.contains(ptrs.first(), 16));
QVERIFY(!c2.contains(ptrs.first(), 16));
QVERIFY(c.contains(ptrs.last(), 16));
@@ -305,7 +305,7 @@ void tst_QFrameAllocator::containsCheckQFrameChunk()
ptrs << c2.allocate(16);
}
- QVERIFY(!c.contains((void *)0xffffffff, 16));
+ QVERIFY(!c.contains((void *)(quintptr)0xffffffff, 16));
QVERIFY(!c.contains(ptrs.last(), 16));
QVERIFY(c.contains(ptrs.first(), 16));
QVERIFY(c2.contains(ptrs.last(), 16));
diff --git a/tests/auto/core/qtransform/tst_qtransform.cpp b/tests/auto/core/qtransform/tst_qtransform.cpp
index ee63255b8..f5527ebf5 100644
--- a/tests/auto/core/qtransform/tst_qtransform.cpp
+++ b/tests/auto/core/qtransform/tst_qtransform.cpp
@@ -66,15 +66,15 @@ private Q_SLOTS:
QTest::newRow("defaultConstructed") << defaultConstructed;
Qt3DCore::QTransform *matrixPropertySet = new Qt3DCore::QTransform();
- matrixPropertySet->setMatrix(Qt3DCore::QTransform::rotateAround(QVector3D(0.1877, 0.6868, 0.3884), 45.0, QVector3D(0, 0, 1)));
+ matrixPropertySet->setMatrix(Qt3DCore::QTransform::rotateAround(QVector3D(0.1877f, 0.6868f, 0.3884f), 45.0f, QVector3D(0.0f, 0.0f, 1.0f)));
QTest::newRow("matrixPropertySet") << matrixPropertySet;
Qt3DCore::QTransform *translationSet = new Qt3DCore::QTransform();
- translationSet->setTranslation(QVector3D(0.1877, 0.6868, 0.3884));
+ translationSet->setTranslation(QVector3D(0.1877f, 0.6868f, 0.3884f));
QTest::newRow("translationSet") << translationSet;
Qt3DCore::QTransform *scaleSet = new Qt3DCore::QTransform();
- scaleSet->setScale3D(QVector3D(0.1, 0.6, 0.3));
+ scaleSet->setScale3D(QVector3D(0.1f, 0.6f, 0.3f));
QTest::newRow("scaleSet") << scaleSet;
Qt3DCore::QTransform *rotationSet = new Qt3DCore::QTransform();
@@ -326,7 +326,7 @@ private Q_SLOTS:
// GIVEN
Qt3DCore::QTransform t;
Qt3DCore::QTransform t2;
- QMatrix4x4 m = Qt3DCore::QTransform::rotateAround(QVector3D(0.1877, 0.6868, 0.3884), 45.0, QVector3D(0, 0, 1));
+ QMatrix4x4 m = Qt3DCore::QTransform::rotateAround(QVector3D(0.1877f, 0.6868f, 0.3884f), 45.0f, QVector3D(0.0f, 0.0f, 1.0f));
// WHEN
t.setMatrix(m);
diff --git a/tests/auto/extras/common/common.pri b/tests/auto/extras/common/common.pri
new file mode 100644
index 000000000..4f73c65b5
--- /dev/null
+++ b/tests/auto/extras/common/common.pri
@@ -0,0 +1,6 @@
+HEADERS += \
+ $$PWD/geometrytesthelper.h
+
+INCLUDEPATH += $$PWD
+
+QT += core-private 3drender
diff --git a/tests/auto/extras/common/geometrytesthelper.h b/tests/auto/extras/common/geometrytesthelper.h
new file mode 100644
index 000000000..48e674cd9
--- /dev/null
+++ b/tests/auto/extras/common/geometrytesthelper.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** 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:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef GEOMETRYTESTHELPER_H
+#define GEOMETRYTESTHELPER_H
+
+#include <Qt3DRender/qattribute.h>
+#include <Qt3DRender/qbuffer.h>
+#include <Qt3DRender/qbufferdatagenerator.h>
+#include <Qt3DRender/qgeometry.h>
+
+inline void generateGeometry(Qt3DRender::QGeometry &geometry)
+{
+ // Get all attributes
+ const QVector<Qt3DRender::QAttribute *> attributes = geometry.attributes();
+
+ // Get all unique data generators from the buffers referenced by the attributes
+ QHash<Qt3DRender::QBufferDataGeneratorPtr, Qt3DRender::QBuffer *> dataGenerators;
+ for (const auto attribute : attributes) {
+ const auto dataGenerator = attribute->buffer()->dataGenerator();
+ if (!dataGenerators.contains(dataGenerator))
+ dataGenerators.insert(dataGenerator, attribute->buffer());
+ }
+
+ // Generate data for each buffer
+ const auto end = dataGenerators.end();
+ for (auto it = dataGenerators.begin(); it != end; ++it) {
+ Qt3DRender::QBufferDataGeneratorPtr dataGenerator = it.key();
+ const QByteArray data = (*dataGenerator)();
+
+ Qt3DRender::QBuffer *buffer = it.value();
+ buffer->setData(data);
+ }
+}
+
+template<typename IndexType>
+IndexType extractIndexData(Qt3DRender::QAttribute *attribute, int index)
+{
+ // Get the raw data
+ const IndexType *typedData = reinterpret_cast<const IndexType *>(attribute->buffer()->data().constData());
+
+ // Offset into the data taking stride and offset into account
+ const IndexType indexValue = *(typedData + index);
+ return indexValue;
+}
+
+template<typename VertexType, typename IndexType>
+VertexType extractVertexData(Qt3DRender::QAttribute *attribute, IndexType index)
+{
+ // Get the raw data
+ const char *rawData = attribute->buffer()->data().constData();
+
+ // Offset into the data taking stride and offset into account
+ const char *vertexData = rawData + (index * attribute->byteStride() + attribute->byteOffset());
+
+ // Construct vertex from the typed data
+ VertexType vertex;
+ const Qt3DRender::QAttribute::VertexBaseType type = attribute->vertexBaseType();
+ switch (type)
+ {
+ case Qt3DRender::QAttribute::Float: {
+ const float *typedVertexData = reinterpret_cast<const float *>(vertexData);
+ const int components = attribute->vertexSize();
+ for (int i = 0; i < components; ++i)
+ vertex[i] = typedVertexData[i];
+ break;
+
+ // TODO: Handle other types as needed
+ }
+
+ default:
+ qWarning() << "Unhandled type";
+ Q_UNREACHABLE();
+ break;
+ }
+
+ return vertex;
+}
+
+#endif // GEOMETRYTESTHELPER_H
diff --git a/tests/auto/extras/extras.pro b/tests/auto/extras/extras.pro
index 3bba4d37b..381924d7b 100644
--- a/tests/auto/extras/extras.pro
+++ b/tests/auto/extras/extras.pro
@@ -1,4 +1,5 @@
TEMPLATE = subdirs
SUBDIRS = \
- qcuboidgeometry
+ qcuboidgeometry \
+ qtorusgeometry
diff --git a/tests/auto/extras/qcuboidgeometry/qcuboidgeometry.pro b/tests/auto/extras/qcuboidgeometry/qcuboidgeometry.pro
index 7208f1c7b..1e55fffad 100644
--- a/tests/auto/extras/qcuboidgeometry/qcuboidgeometry.pro
+++ b/tests/auto/extras/qcuboidgeometry/qcuboidgeometry.pro
@@ -8,3 +8,5 @@ CONFIG += testcase
SOURCES += \
tst_qcuboidgeometry.cpp
+
+include(../common/common.pri)
diff --git a/tests/auto/extras/qcuboidgeometry/tst_qcuboidgeometry.cpp b/tests/auto/extras/qcuboidgeometry/tst_qcuboidgeometry.cpp
index fa1657732..973a1d613 100644
--- a/tests/auto/extras/qcuboidgeometry/tst_qcuboidgeometry.cpp
+++ b/tests/auto/extras/qcuboidgeometry/tst_qcuboidgeometry.cpp
@@ -40,77 +40,7 @@
#include <QtCore/qsharedpointer.h>
#include <QSignalSpy>
-namespace {
-
-void generateGeometry(Qt3DRender::QGeometry &geometry)
-{
- // Get all attributes
- const QVector<Qt3DRender::QAttribute *> attributes = geometry.attributes();
-
- // Get all unique data generators from the buffers referenced by the attributes
- QHash<Qt3DRender::QBufferDataGeneratorPtr, Qt3DRender::QBuffer *> dataGenerators;
- for (const auto attribute : attributes) {
- const auto dataGenerator = attribute->buffer()->dataGenerator();
- if (!dataGenerators.contains(dataGenerator))
- dataGenerators.insert(dataGenerator, attribute->buffer());
- }
-
- // Generate data for each buffer
- const auto end = dataGenerators.end();
- for (auto it = dataGenerators.begin(); it != end; ++it) {
- Qt3DRender::QBufferDataGeneratorPtr dataGenerator = it.key();
- const QByteArray data = (*dataGenerator)();
-
- Qt3DRender::QBuffer *buffer = it.value();
- buffer->setData(data);
- }
-}
-
-template<typename IndexType>
-IndexType extractIndexData(Qt3DRender::QAttribute *attribute, int index)
-{
- // Get the raw data
- const IndexType *typedData = reinterpret_cast<const IndexType *>(attribute->buffer()->data().constData());
-
- // Offset into the data taking stride and offset into account
- const IndexType indexValue = *(typedData + index);
- return indexValue;
-}
-
-template<typename VertexType, typename IndexType>
-VertexType extractVertexData(Qt3DRender::QAttribute *attribute, IndexType index)
-{
- // Get the raw data
- const char *rawData = attribute->buffer()->data().constData();
-
- // Offset into the data taking stride and offset into account
- const char *vertexData = rawData + (index * attribute->byteStride() + attribute->byteOffset());
-
- // Construct vertex from the typed data
- VertexType vertex;
- const Qt3DRender::QAttribute::VertexBaseType type = attribute->vertexBaseType();
- switch (type)
- {
- case Qt3DRender::QAttribute::Float: {
- const float *typedVertexData = reinterpret_cast<const float *>(vertexData);
- const int components = attribute->vertexSize();
- for (int i = 0; i < components; ++i)
- vertex[i] = typedVertexData[i];
- break;
-
- // TODO: Handle other types as needed
- }
-
- default:
- qWarning() << "Unhandled type";
- Q_UNREACHABLE();
- break;
- }
-
- return vertex;
-}
-
-}
+#include "geometrytesthelper.h"
class tst_QCuboidGeometry : public QObject
{
diff --git a/tests/auto/extras/qtorusgeometry/qtorusgeometry.pro b/tests/auto/extras/qtorusgeometry/qtorusgeometry.pro
new file mode 100644
index 000000000..e20e447dc
--- /dev/null
+++ b/tests/auto/extras/qtorusgeometry/qtorusgeometry.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_qtorusgeometry
+
+QT += 3dextras testlib
+
+CONFIG += testcase
+
+SOURCES += \
+ tst_qtorusgeometry.cpp
+
+include(../common/common.pri)
diff --git a/tests/auto/extras/qtorusgeometry/tst_qtorusgeometry.cpp b/tests/auto/extras/qtorusgeometry/tst_qtorusgeometry.cpp
new file mode 100644
index 000000000..28fe76ae9
--- /dev/null
+++ b/tests/auto/extras/qtorusgeometry/tst_qtorusgeometry.cpp
@@ -0,0 +1,366 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 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:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QTest>
+#include <QObject>
+#include <Qt3DExtras/qtorusgeometry.h>
+#include <Qt3DRender/qattribute.h>
+#include <Qt3DRender/qbuffer.h>
+#include <Qt3DRender/qbufferdatagenerator.h>
+#include <QtGui/qopenglcontext.h>
+#include <QtGui/qvector2d.h>
+#include <QtGui/qvector3d.h>
+#include <QtGui/qvector4d.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qsharedpointer.h>
+#include <QSignalSpy>
+#include <qmath.h>
+
+#include "geometrytesthelper.h"
+
+class tst_QTorusGeometry : public QObject
+{
+ Q_OBJECT
+private Q_SLOTS:
+ void defaultConstruction()
+ {
+ // WHEN
+ Qt3DExtras::QTorusGeometry geometry;
+
+ // THEN
+ QCOMPARE(geometry.rings(), 16);
+ QCOMPARE(geometry.slices(), 16);
+ QCOMPARE(geometry.radius(), 1.0f);
+ QCOMPARE(geometry.minorRadius(), 1.0f);
+ QVERIFY(geometry.positionAttribute() != nullptr);
+ QCOMPARE(geometry.positionAttribute()->name(), Qt3DRender::QAttribute::defaultPositionAttributeName());
+ QVERIFY(geometry.normalAttribute() != nullptr);
+ QCOMPARE(geometry.normalAttribute()->name(), Qt3DRender::QAttribute::defaultNormalAttributeName());
+ QVERIFY(geometry.texCoordAttribute() != nullptr);
+ QCOMPARE(geometry.texCoordAttribute()->name(), Qt3DRender::QAttribute::defaultTextureCoordinateAttributeName());
+ // TODO: Expose tangent attribute in Qt 5.8 and see below
+// QVERIFY(geometry.tangentAttribute() != nullptr);
+// QCOMPARE(geometry.tangentAttribute()->name(), Qt3DRender::QAttribute::defaultTangentAttributeName());
+ QVERIFY(geometry.indexAttribute() != nullptr);
+ }
+
+ void properties()
+ {
+ // GIVEN
+ Qt3DExtras::QTorusGeometry geometry;
+
+ {
+ // WHEN
+ QSignalSpy spy(&geometry, SIGNAL(ringsChanged(int)));
+ const int newValue = 20;
+ geometry.setRings(newValue);
+
+ // THEN
+ QCOMPARE(geometry.rings(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ geometry.setRings(newValue);
+
+ // THEN
+ QCOMPARE(geometry.rings(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+
+ {
+ // WHEN
+ QSignalSpy spy(&geometry, SIGNAL(slicesChanged(int)));
+ const int newValue = 2.0f;
+ geometry.setSlices(newValue);
+
+ // THEN
+ QCOMPARE(geometry.slices(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ geometry.setSlices(newValue);
+
+ // THEN
+ QCOMPARE(geometry.slices(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+
+ {
+ // WHEN
+ QSignalSpy spy(&geometry, SIGNAL(radiusChanged(float)));
+ const float newValue = 2.0f;
+ geometry.setRadius(newValue);
+
+ // THEN
+ QCOMPARE(geometry.radius(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ geometry.setRadius(newValue);
+
+ // THEN
+ QCOMPARE(geometry.radius(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+
+ {
+ // WHEN
+ QSignalSpy spy(&geometry, SIGNAL(minorRadiusChanged(float)));
+ const float newValue = 0.25f;
+ geometry.setMinorRadius(newValue);
+
+ // THEN
+ QCOMPARE(geometry.minorRadius(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ geometry.setMinorRadius(newValue);
+
+ // THEN
+ QCOMPARE(geometry.minorRadius(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ }
+
+ void generatedGeometryShouldBeConsistent_data()
+ {
+ QTest::addColumn<int>("rings");
+ QTest::addColumn<int>("slices");
+ QTest::addColumn<float>("radius");
+ QTest::addColumn<float>("minorRadius");
+ QTest::addColumn<int>("triangleIndex");
+ QTest::addColumn<QVector<quint16>>("indices");
+ QTest::addColumn<QVector<QVector3D>>("positions");
+ QTest::addColumn<QVector<QVector3D>>("normals");
+ QTest::addColumn<QVector<QVector2D>>("texCoords");
+ QTest::addColumn<QVector<QVector4D>>("tangents");
+
+ {
+ // Torus properties
+ const int rings = 8;
+ const int slices = 8;
+ const float radius = 2.0f;
+ const float minorRadius = 0.5f;
+
+ // Angular factors for the vertices:
+ // u iterates around the major radius
+ // v iterates around the minor radius (around each ring)
+ const float du = float(2.0 * M_PI / rings);
+ const float dv = float(2.0 * M_PI / slices);
+ const float u0 = 0.0f;
+ const float u1 = du;
+ const float v0 = 0.0f;
+ const float v1 = dv;
+
+ const float cosu0 = float(qCos(u0));
+ const float sinu0 = float(qSin(u0));
+ const float cosu1 = float(qCos(u1));
+ const float sinu1 = float(qSin(u1));
+
+ const float cosv0 = float(qCos(v0 + M_PI)); // Seam is on inner edge
+ const float sinv0 = float(qSin(v0));
+ const float cosv1 = float(qCos(v1 + M_PI));
+ const float sinv1 = float(qSin(v1));
+
+ // The triangle and indices
+ const int triangleIndex = 0;
+ const auto indices = (QVector<quint16>() << 0 << 1 << 9);
+
+ // Calculate attributes for vertices A, B, and C of the triangle
+ const float rA = radius + minorRadius * cosv0;
+ const float rB = radius + minorRadius * cosv1;
+ const float rC = radius + minorRadius * cosv0;
+
+ const auto posA = QVector3D(rA * cosu0, rA * sinu0, minorRadius * sinv0);
+ const auto posB = QVector3D(rB * cosu0, rB * sinu0, minorRadius * sinv1);
+ const auto posC = QVector3D(rC * cosu1, rC * sinu1, minorRadius * sinv0);
+ const auto positions = (QVector<QVector3D>() << posA << posB << posC);
+
+ const auto nA = QVector3D(cosv0 * cosu0, cosv0 * sinu0, sinv0).normalized();
+ const auto nB = QVector3D(cosv1 * cosu0, cosv1 * sinu0, sinv1).normalized();
+ const auto nC = QVector3D(cosv0 * cosu1, cosv0 * sinu1, sinv0).normalized();
+ const auto normals = (QVector<QVector3D>() << nA << nB << nC);
+
+ const auto tcA = QVector2D(u0, v0) / float(2.0 * M_PI);
+ const auto tcB = QVector2D(u0, v1) / float(2.0 * M_PI);
+ const auto tcC = QVector2D(u1, v0) / float(2.0 * M_PI);
+ const auto texCoords = (QVector<QVector2D>() << tcA << tcB << tcC);
+
+ const auto tA = QVector4D(-sinu0, cosu0, 0.0f, 1.0f);
+ const auto tB = QVector4D(-sinu0, cosu0, 0.0f, 1.0f);
+ const auto tC = QVector4D(-sinu1, cosu1, 0.0f, 1.0f);
+ const auto tangents = (QVector<QVector4D>() << tA << tB << tC);
+
+ // Add the row
+ QTest::newRow("8rings_8slices_firstTriangle")
+ << rings << slices << radius << minorRadius
+ << triangleIndex
+ << indices << positions << normals << texCoords << tangents;
+ }
+
+ {
+ // Note: The vertices used in this test case are different than the
+ // ones above. So, we cannot abstract this into a function easily.
+ // Here we use the 2nd triangle in a rectangular face, the test above
+ // uses the first triangle in the rectangular face.
+
+ // Torus properties
+ const int rings = 8;
+ const int slices = 8;
+ const float radius = 2.0f;
+ const float minorRadius = 0.5f;
+
+ // Angular factors for the vertices:
+ // u iterates around the major radius
+ // v iterates around the minor radius (around each ring)
+ const float du = float(2.0 * M_PI / rings);
+ const float dv = float(2.0 * M_PI / slices);
+ const float u0 = 7.0f * du;
+ const float u1 = float(2.0 * M_PI);
+ const float v0 = 7.0f * dv;
+ const float v1 = float(2.0 * M_PI);
+
+ const float cosu0 = float(qCos(u0));
+ const float sinu0 = float(qSin(u0));
+ const float cosu1 = float(qCos(u1));
+ const float sinu1 = float(qSin(u1));
+
+ const float cosv0 = float(qCos(v0 + M_PI)); // Seam is on inner edge
+ const float sinv0 = float(qSin(v0));
+ const float cosv1 = float(qCos(v1 + M_PI));
+ const float sinv1 = float(qSin(v1));
+
+ // The triangle and indices
+ const int triangleIndex = 127;
+ const auto indices = (QVector<quint16>() << 71 << 80 << 79);
+
+ // Calculate attributes for vertices A, B, and C of the triangle
+ const float rA = radius + minorRadius * cosv1;
+ const float rB = radius + minorRadius * cosv1;
+ const float rC = radius + minorRadius * cosv0;
+
+ const auto posA = QVector3D(rA * cosu0, rA * sinu0, minorRadius * sinv1);
+ const auto posB = QVector3D(rB * cosu1, rB * sinu1, minorRadius * sinv1);
+ const auto posC = QVector3D(rC * cosu1, rC * sinu1, minorRadius * sinv0);
+ const auto positions = (QVector<QVector3D>() << posA << posB << posC);
+
+ const auto nA = QVector3D(cosv1 * cosu0, cosv1 * sinu0, sinv1).normalized();
+ const auto nB = QVector3D(cosv1 * cosu1, cosv1 * sinu1, sinv1).normalized();
+ const auto nC = QVector3D(cosv0 * cosu1, cosv0 * sinu1, sinv0).normalized();
+ const auto normals = (QVector<QVector3D>() << nA << nB << nC);
+
+ const auto tcA = QVector2D(u0, v1) / float(2.0 * M_PI);
+ const auto tcB = QVector2D(u1, v1) / float(2.0 * M_PI);
+ const auto tcC = QVector2D(u1, v0) / float(2.0 * M_PI);
+ const auto texCoords = (QVector<QVector2D>() << tcA << tcB << tcC);
+
+ const auto tA = QVector4D(-sinu0, cosu1, 0.0f, 1.0f);
+ const auto tB = QVector4D(-sinu1, cosu1, 0.0f, 1.0f);
+ const auto tC = QVector4D(-sinu1, cosu1, 0.0f, 1.0f);
+ const auto tangents = (QVector<QVector4D>() << tA << tB << tC);
+
+ // Add the row
+ QTest::newRow("8rings_8slices_lastTriangle")
+ << rings << slices << radius << minorRadius
+ << triangleIndex
+ << indices << positions << normals << texCoords << tangents;
+ }
+ }
+
+ void generatedGeometryShouldBeConsistent()
+ {
+ // GIVEN
+ Qt3DExtras::QTorusGeometry geometry;
+ const QVector<Qt3DRender::QAttribute *> attributes = geometry.attributes();
+ Qt3DRender::QAttribute *positionAttribute = geometry.positionAttribute();
+ Qt3DRender::QAttribute *normalAttribute = geometry.normalAttribute();
+ Qt3DRender::QAttribute *texCoordAttribute = geometry.texCoordAttribute();
+// Qt3DRender::QAttribute *tangentAttribute = geometry.tangentAttribute();
+ Qt3DRender::QAttribute *indexAttribute = geometry.indexAttribute();
+
+ // WHEN
+ QFETCH(int, rings);
+ QFETCH(int, slices);
+ QFETCH(float, radius);
+ QFETCH(float, minorRadius);
+ geometry.setRings(rings);
+ geometry.setSlices(slices);
+ geometry.setRadius(radius);
+ geometry.setMinorRadius(minorRadius);
+
+ generateGeometry(geometry);
+
+ // THEN
+
+ // Check buffer of each attribute is valid and actually has some data
+ for (const auto &attribute : attributes) {
+ Qt3DRender::QBuffer *buffer = attribute->buffer();
+ QVERIFY(buffer != nullptr);
+ QVERIFY(buffer->data().size() != 0);
+ }
+
+ // Check some data in the buffers
+
+ // Check specific indices and vertex attributes of triangle under test
+ QFETCH(int, triangleIndex);
+ QFETCH(QVector<quint16>, indices);
+ QFETCH(QVector<QVector3D>, positions);
+ QFETCH(QVector<QVector3D>, normals);
+ QFETCH(QVector<QVector2D>, texCoords);
+// QFETCH(QVector<QVector4D>, tangents);
+
+ int i = 0;
+ for (auto index : indices) {
+ const auto testIndex = extractIndexData<quint16>(indexAttribute, 3 * triangleIndex + i);
+ QCOMPARE(testIndex, indices.at(i));
+
+ const auto position = extractVertexData<QVector3D, quint32>(positionAttribute, index);
+ QVERIFY(qFuzzyCompare(position, positions.at(i)));
+
+ const auto normal = extractVertexData<QVector3D, quint32>(normalAttribute, index);
+ QVERIFY(qFuzzyCompare(normal, normals.at(i)));
+
+ const auto texCoord = extractVertexData<QVector2D, quint32>(texCoordAttribute, index);
+ QVERIFY(qFuzzyCompare(texCoord, texCoords.at(i)));
+
+// const auto tangent = extractVertexData<QVector4D, quint32>(tangentAttribute, index);
+// QVERIFY(qFuzzyCompare(tangent, tangents.at(i)));
+
+ ++i;
+ }
+ }
+};
+
+
+QTEST_APPLESS_MAIN(tst_QTorusGeometry)
+
+#include "tst_qtorusgeometry.moc"
diff --git a/tests/auto/input/input.pro b/tests/auto/input/input.pro
index 05668c036..cf0af12cb 100644
--- a/tests/auto/input/input.pro
+++ b/tests/auto/input/input.pro
@@ -19,5 +19,6 @@ qtConfig(private_tests) {
keyboardhandler \
qaxisaccumulator \
inputsequence \
- inputchord
+ inputchord \
+ qabstractphysicaldevicebackendnode
}
diff --git a/tests/auto/input/qabstractphysicaldevicebackendnode/qabstractphysicaldevicebackendnode.pro b/tests/auto/input/qabstractphysicaldevicebackendnode/qabstractphysicaldevicebackendnode.pro
new file mode 100644
index 000000000..dc1734c41
--- /dev/null
+++ b/tests/auto/input/qabstractphysicaldevicebackendnode/qabstractphysicaldevicebackendnode.pro
@@ -0,0 +1,11 @@
+TEMPLATE = app
+
+TARGET = tst_qabstractphysicaldevicebackendnode
+
+QT += 3dcore 3dcore-private 3dinput 3dinput-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_qabstractphysicaldevicebackendnode.cpp
+
+include(../commons/commons.pri)
diff --git a/tests/auto/input/qabstractphysicaldevicebackendnode/tst_qabstractphysicaldevicebackendnode.cpp b/tests/auto/input/qabstractphysicaldevicebackendnode/tst_qabstractphysicaldevicebackendnode.cpp
new file mode 100644
index 000000000..0cf37fe95
--- /dev/null
+++ b/tests/auto/input/qabstractphysicaldevicebackendnode/tst_qabstractphysicaldevicebackendnode.cpp
@@ -0,0 +1,246 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Paul Lemire <paul.lemire350@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DInput/private/qabstractphysicaldevicebackendnode_p.h>
+#include <Qt3DInput/private/qabstractphysicaldevicebackendnode_p_p.h>
+#include <Qt3DInput/private/inputhandler_p.h>
+#include <Qt3DInput/qaxissetting.h>
+#include <Qt3DInput/qinputaspect.h>
+#include <Qt3DInput/private/qinputaspect_p.h>
+#include <Qt3DInput/private/inputmanagers_p.h>
+#include <Qt3DInput/private/axissetting_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/qpropertynodeaddedchange.h>
+#include <Qt3DCore/qpropertynoderemovedchange.h>
+#include "testdevice.h"
+
+class TestPhysicalDeviceBackendNode : public Qt3DInput::QAbstractPhysicalDeviceBackendNode
+{
+public:
+ TestPhysicalDeviceBackendNode(Qt3DCore::QBackendNode::Mode mode = Qt3DCore::QBackendNode::ReadOnly)
+ : Qt3DInput::QAbstractPhysicalDeviceBackendNode(mode)
+ {}
+
+ float axisValue(int axisIdentifier) const Q_DECL_OVERRIDE
+ {
+ if (axisIdentifier == 883)
+ return 883.0f;
+ return 0.0f;
+ }
+
+ bool isButtonPressed(int buttonIdentifier) const Q_DECL_OVERRIDE
+ {
+ if (buttonIdentifier == 454)
+ return true;
+ return false;
+ }
+
+};
+
+class tst_QAbstractPhysicalDeviceBackendNode : public Qt3DCore::QBackendNodeTester
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkInitialState()
+ {
+ // GIVEN
+ TestPhysicalDeviceBackendNode backendQAbstractPhysicalDeviceBackendNode;
+
+ // THEN
+ QCOMPARE(backendQAbstractPhysicalDeviceBackendNode.isEnabled(), false);
+ QVERIFY(backendQAbstractPhysicalDeviceBackendNode.inputAspect() == nullptr);
+ QVERIFY(backendQAbstractPhysicalDeviceBackendNode.peerId().isNull());
+ }
+
+ void checkAxisValue()
+ {
+ // GIVEN
+ TestPhysicalDeviceBackendNode backendQAbstractPhysicalDeviceBackendNode;
+
+ // WHEN
+ float axisValue = backendQAbstractPhysicalDeviceBackendNode.axisValue(883);
+ // THEN
+ QCOMPARE(axisValue, 883.0f);
+
+ // WHEN
+ axisValue = backendQAbstractPhysicalDeviceBackendNode.axisValue(454);
+ // THEN
+ QCOMPARE(axisValue, 0.0f);
+ }
+
+ void checkButtonPressed()
+ {
+ // GIVEN
+ TestPhysicalDeviceBackendNode backendQAbstractPhysicalDeviceBackendNode;
+
+ // WHEN
+ bool buttonPressed = backendQAbstractPhysicalDeviceBackendNode.isButtonPressed(883);
+ // THEN
+ QCOMPARE(buttonPressed, false);
+
+ // WHEN
+ buttonPressed = backendQAbstractPhysicalDeviceBackendNode.isButtonPressed(454);
+ // THEN
+ QCOMPARE(buttonPressed, true);
+ }
+
+ void checkCleanupState()
+ {
+ // GIVEN
+ TestPhysicalDeviceBackendNode backendQAbstractPhysicalDeviceBackendNode;
+ Qt3DInput::QInputAspect aspect;
+
+ // WHEN
+ backendQAbstractPhysicalDeviceBackendNode.setEnabled(true);
+ backendQAbstractPhysicalDeviceBackendNode.setInputAspect(&aspect);
+
+ // THEN
+ QCOMPARE(backendQAbstractPhysicalDeviceBackendNode.inputAspect(), &aspect);
+
+ // WHEN
+ backendQAbstractPhysicalDeviceBackendNode.cleanup();
+
+ // THEN
+ QCOMPARE(backendQAbstractPhysicalDeviceBackendNode.isEnabled(), false);
+ QVERIFY(backendQAbstractPhysicalDeviceBackendNode.inputAspect() == nullptr);
+ }
+
+ void checkInitializeFromPeer()
+ {
+ // GIVEN
+ TestDevice physicalDeviceNode;
+
+ {
+ // WHEN
+ TestPhysicalDeviceBackendNode backendQAbstractPhysicalDeviceBackendNode;
+ simulateInitialization(&physicalDeviceNode, &backendQAbstractPhysicalDeviceBackendNode);
+
+ // THEN
+ QCOMPARE(backendQAbstractPhysicalDeviceBackendNode.isEnabled(), true);
+ QCOMPARE(backendQAbstractPhysicalDeviceBackendNode.peerId(), physicalDeviceNode.id());
+ }
+ {
+ // WHEN
+ TestPhysicalDeviceBackendNode backendQAbstractPhysicalDeviceBackendNode;
+ physicalDeviceNode.setEnabled(false);
+ simulateInitialization(&physicalDeviceNode, &backendQAbstractPhysicalDeviceBackendNode);
+
+ // THEN
+ QCOMPARE(backendQAbstractPhysicalDeviceBackendNode.peerId(), physicalDeviceNode.id());
+ QCOMPARE(backendQAbstractPhysicalDeviceBackendNode.isEnabled(), false);
+ }
+ }
+
+ void checkSceneChangeEvents()
+ {
+ // GIVEN
+ TestPhysicalDeviceBackendNode backendQAbstractPhysicalDeviceBackendNode;
+ Qt3DInput::QInputAspect aspect;
+ backendQAbstractPhysicalDeviceBackendNode.setInputAspect(&aspect);
+
+ {
+ // WHEN
+ const bool newValue = false;
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("enabled");
+ change->setValue(newValue);
+ backendQAbstractPhysicalDeviceBackendNode.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendQAbstractPhysicalDeviceBackendNode.isEnabled(), newValue);
+ }
+
+ {
+ Qt3DInput::QAxisSetting settings1;
+ Qt3DInput::QAxisSetting settings2;
+
+ settings1.setAxes(QVector<int>() << 883);
+ settings2.setAxes(QVector<int>() << 454);
+ Qt3DInput::QAbstractPhysicalDeviceBackendNodePrivate *priv = static_cast<Qt3DInput::QAbstractPhysicalDeviceBackendNodePrivate *>(
+ Qt3DCore::QBackendNodePrivate::get(&backendQAbstractPhysicalDeviceBackendNode));
+
+ // Create backend resource
+ {
+ Qt3DInput::QInputAspectPrivate *aspectPrivate = static_cast<Qt3DInput::QInputAspectPrivate *>(Qt3DCore::QAbstractAspectPrivate::get(&aspect));
+ Qt3DInput::Input::InputHandler *handler = aspectPrivate->m_inputHandler.data();
+ Qt3DInput::Input::AxisSetting *backendSetting1 = handler->axisSettingManager()->getOrCreateResource(settings1.id());
+ Qt3DInput::Input::AxisSetting *backendSetting2 = handler->axisSettingManager()->getOrCreateResource(settings2.id());
+ simulateInitialization(&settings1, backendSetting1);
+ simulateInitialization(&settings2, backendSetting2);
+ }
+
+ // Adding AxisSettings
+ {
+ // WHEN
+ auto change = Qt3DCore::QPropertyNodeAddedChangePtr::create(Qt3DCore::QNodeId(), &settings1);
+ change->setPropertyName("axisSettings");
+ backendQAbstractPhysicalDeviceBackendNode.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(priv->m_axisSettings.size(), 1);
+
+ // WHEN
+ change = Qt3DCore::QPropertyNodeAddedChangePtr::create(Qt3DCore::QNodeId(), &settings2);
+ change->setPropertyName("axisSettings");
+ backendQAbstractPhysicalDeviceBackendNode.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(priv->m_axisSettings.size(), 2);
+ }
+ // Removing AxisSettings
+ {
+ // WHEN
+ auto change = Qt3DCore::QPropertyNodeRemovedChangePtr::create(Qt3DCore::QNodeId(), &settings1);
+ change->setPropertyName("axisSettings");
+ backendQAbstractPhysicalDeviceBackendNode.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(priv->m_axisSettings.size(), 1);
+
+ // WHEN
+ change = Qt3DCore::QPropertyNodeRemovedChangePtr::create(Qt3DCore::QNodeId(), &settings2);
+ change->setPropertyName("axisSettings");
+ backendQAbstractPhysicalDeviceBackendNode.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(priv->m_axisSettings.size(), 0);
+ }
+
+ }
+ }
+
+};
+
+QTEST_MAIN(tst_QAbstractPhysicalDeviceBackendNode)
+
+#include "tst_qabstractphysicaldevicebackendnode.moc"
diff --git a/tests/auto/input/qbuttonaxisinput/tst_qbuttonaxisinput.cpp b/tests/auto/input/qbuttonaxisinput/tst_qbuttonaxisinput.cpp
index 1a0459958..618c75d42 100644
--- a/tests/auto/input/qbuttonaxisinput/tst_qbuttonaxisinput.cpp
+++ b/tests/auto/input/qbuttonaxisinput/tst_qbuttonaxisinput.cpp
@@ -49,6 +49,18 @@ public:
}
private Q_SLOTS:
+ void shouldHaveDefaultState()
+ {
+ // GIVEN
+ Qt3DInput::QButtonAxisInput axisInput;
+
+ // THEN
+ QVERIFY(axisInput.buttons().isEmpty());
+ QCOMPARE(axisInput.scale(), 1.0f);
+ QCOMPARE(axisInput.acceleration(), -1.0f);
+ QCOMPARE(axisInput.deceleration(), -1.0f);
+ }
+
void checkCloning_data()
{
QTest::addColumn<Qt3DInput::QButtonAxisInput *>("axisInput");
diff --git a/tests/auto/render/ddstextures/tst_ddstextures.cpp b/tests/auto/render/ddstextures/tst_ddstextures.cpp
index 1428d8a6d..4d9a1fb32 100644
--- a/tests/auto/render/ddstextures/tst_ddstextures.cpp
+++ b/tests/auto/render/ddstextures/tst_ddstextures.cpp
@@ -78,7 +78,7 @@ void tst_DdsTextures::ddsImageData()
for (unsigned i = 0; i < sizeof(textures)/sizeof(*textures); i++) {
const TextureInfo *texture = &textures[i];
- Qt3DRender::QTextureImageDataPtr data = Qt3DRender::TextureLoadingHelper::loadTextureData(QUrl::fromLocalFile(QFINDTESTDATA(texture->source)), true);
+ Qt3DRender::QTextureImageDataPtr data = Qt3DRender::TextureLoadingHelper::loadTextureData(QUrl::fromLocalFile(QFINDTESTDATA(texture->source)), true, false);
QVERIFY(data);
QCOMPARE(data->width(), texture->width);
diff --git a/tests/auto/render/framegraphnode/tst_framegraphnode.cpp b/tests/auto/render/framegraphnode/tst_framegraphnode.cpp
index f3f3dbff1..07ff4c0d9 100644
--- a/tests/auto/render/framegraphnode/tst_framegraphnode.cpp
+++ b/tests/auto/render/framegraphnode/tst_framegraphnode.cpp
@@ -29,6 +29,11 @@
#include <Qt3DRender/private/framegraphnode_p.h>
#include <QtTest/QTest>
#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DCore/qpropertynodeaddedchange.h>
+#include <Qt3DCore/qpropertynoderemovedchange.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include "testrenderer.h"
class MyFrameGraphNode : public Qt3DRender::Render::FrameGraphNode
{
@@ -37,9 +42,15 @@ public:
{
FrameGraphNode::setEnabled(enabled);
}
+};
-protected:
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &) Q_DECL_FINAL {}
+class MyQFrameGraphNode : public Qt3DRender::QFrameGraphNode
+{
+ Q_OBJECT
+public:
+ MyQFrameGraphNode(Qt3DCore::QNode *parent = nullptr)
+ : Qt3DRender::QFrameGraphNode(parent)
+ {}
};
class tst_FrameGraphNode : public QObject
@@ -167,8 +178,116 @@ private Q_SLOTS:
QCOMPARE(parent1->childrenIds().count(), 0);
QCOMPARE(parent1->children().count(), parent1->childrenIds().count());
}
+
+ void checkSetParent()
+ {
+ // GIVEN
+ QScopedPointer<Qt3DRender::Render::FrameGraphManager> manager(new Qt3DRender::Render::FrameGraphManager());
+ const Qt3DCore::QNodeId parent1Id = Qt3DCore::QNodeId::createId();
+ const Qt3DCore::QNodeId parent2Id = Qt3DCore::QNodeId::createId();
+ const Qt3DCore::QNodeId childId = Qt3DCore::QNodeId::createId();
+
+ Qt3DRender::Render::FrameGraphNode *parent1 = new MyFrameGraphNode();
+ Qt3DRender::Render::FrameGraphNode *parent2 = new MyFrameGraphNode();
+ Qt3DRender::Render::FrameGraphNode *child = new MyFrameGraphNode();
+
+ setIdInternal(parent1, parent1Id);
+ setIdInternal(parent2, parent2Id);
+ setIdInternal(child, childId);
+
+ manager->appendNode(parent1Id, parent1);
+ manager->appendNode(parent2Id, parent2);
+ manager->appendNode(childId, child);
+
+ parent1->setFrameGraphManager(manager.data());
+ parent2->setFrameGraphManager(manager.data());
+ child->setFrameGraphManager(manager.data());
+
+ // THEN
+ QCOMPARE(parent1->peerId(), parent1Id);
+ QCOMPARE(parent2->peerId(), parent2Id);
+ QCOMPARE(child->peerId(), childId);
+
+ QVERIFY(child->parentId().isNull());
+ QCOMPARE(parent1->childrenIds().size(), 0);
+ QCOMPARE(parent2->childrenIds().size(), 0);
+
+ // WHEN
+ child->setParentId(parent1Id);
+
+ // THEN
+ QCOMPARE(child->parentId(), parent1Id);
+ QCOMPARE(parent1->childrenIds().size(), 1);
+ QCOMPARE(parent2->childrenIds().size(), 0);
+
+ // WHEN
+ child->setParentId(parent2Id);
+
+ // THEN
+ QCOMPARE(child->parentId(), parent2Id);
+ QCOMPARE(parent1->childrenIds().size(), 0);
+ QCOMPARE(parent2->childrenIds().size(), 1);
+
+ // WHEN
+ child->setParentId(Qt3DCore::QNodeId());
+
+ // THEN
+ QVERIFY(child->parentId().isNull());
+ QCOMPARE(parent1->childrenIds().size(), 0);
+ QCOMPARE(parent2->childrenIds().size(), 0);
+ }
+
+ void checkSceneChangeEvents()
+ {
+ // GIVEN
+ const Qt3DCore::QNodeId fgNode1Id = Qt3DCore::QNodeId::createId();
+
+ Qt3DRender::Render::FrameGraphNode *backendFGNode = new MyFrameGraphNode();
+ Qt3DRender::QFrameGraphNode *frontendFGChild = new MyQFrameGraphNode();
+ Qt3DRender::Render::FrameGraphNode *backendFGChild = new MyFrameGraphNode();
+
+ QScopedPointer<Qt3DRender::Render::FrameGraphManager> manager(new Qt3DRender::Render::FrameGraphManager());
+
+ TestRenderer renderer;
+
+ backendFGNode->setRenderer(&renderer);
+
+ setIdInternal(backendFGNode, fgNode1Id);
+ setIdInternal(backendFGChild, frontendFGChild->id());
+
+ manager->appendNode(fgNode1Id, backendFGNode);
+ manager->appendNode(frontendFGChild->id(), backendFGChild);
+
+ backendFGNode->setFrameGraphManager(manager.data());
+ backendFGChild->setFrameGraphManager(manager.data());
+
+
+ // To geneate the type_info in the QNodePrivate of frontendFGChild
+ Qt3DCore::QNodeCreatedChangeGenerator generator(frontendFGChild);
+
+ QCOMPARE(backendFGNode->childrenIds().size(), 0);
+
+ {
+ // WHEN
+ const auto change = Qt3DCore::QPropertyNodeAddedChangePtr::create(Qt3DCore::QNodeId(), frontendFGChild);
+ backendFGNode->sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendFGNode->childrenIds().size(), 1);
+ QCOMPARE(backendFGNode->childrenIds().first(), frontendFGChild->id());
+ }
+ {
+ // WHEN
+ const auto change = Qt3DCore::QPropertyNodeRemovedChangePtr::create(Qt3DCore::QNodeId(), frontendFGChild);
+ backendFGNode->sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendFGNode->childrenIds().size(), 0);
+ }
+ }
+
};
-QTEST_APPLESS_MAIN(tst_FrameGraphNode)
+QTEST_MAIN(tst_FrameGraphNode)
#include "tst_framegraphnode.moc"
diff --git a/tests/auto/render/graphicshelpergl2/graphicshelpergl2.pro b/tests/auto/render/graphicshelpergl2/graphicshelpergl2.pro
new file mode 100644
index 000000000..b27060635
--- /dev/null
+++ b/tests/auto/render/graphicshelpergl2/graphicshelpergl2.pro
@@ -0,0 +1,13 @@
+TEMPLATE = app
+
+TARGET = tst_graphicshelpergl2
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib openglextensions
+
+CONFIG += testcase
+
+SOURCES += \
+ tst_graphicshelpergl2.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/graphicshelpergl2/tst_graphicshelpergl2.cpp b/tests/auto/render/graphicshelpergl2/tst_graphicshelpergl2.cpp
new file mode 100644
index 000000000..579aae971
--- /dev/null
+++ b/tests/auto/render/graphicshelpergl2/tst_graphicshelpergl2.cpp
@@ -0,0 +1,1435 @@
+/****************************************************************************
+**
+** 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:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QTest>
+#include <Qt3DRender/qrendertargetoutput.h>
+#include <Qt3DRender/private/uniform_p.h>
+#include <Qt3DRender/private/graphicshelpergl2_p.h>
+#include <Qt3DRender/private/attachmentpack_p.h>
+#include <QtOpenGLExtensions/QOpenGLExtensions>
+#include <QOpenGLContext>
+#include <QOpenGLFunctions_2_0>
+#include <QOpenGLShaderProgram>
+#include <QSurfaceFormat>
+
+#ifndef QT_OPENGL_ES_2
+
+#define TEST_SHOULD_BE_PERFORMED 1
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt3DRender;
+using namespace Qt3DRender::Render;
+
+namespace {
+
+const QByteArray vertCode = QByteArrayLiteral(
+ "#version 120\n" \
+ "attribute vec3 vertexPosition;\n" \
+ "attribute vec2 vertexTexCoord;\n" \
+ "varying vec2 texCoord;\n" \
+ "void main()\n" \
+ "{\n" \
+ " texCoord = vertexTexCoord;\n" \
+ " gl_Position = vec4(vertexPosition, 1.0);\n" \
+ "}\n");
+
+const QByteArray fragCodeUniformsFloat = QByteArrayLiteral(
+ "#version 120\n" \
+ "uniform float multiplier;\n" \
+ "uniform vec2 multiplierVec2;\n" \
+ "uniform vec3 multiplierVec3;\n" \
+ "uniform vec4 multiplierVec4;\n" \
+ "void main()\n" \
+ "{\n" \
+ " vec4 randomMult = multiplierVec4 + vec4(multiplierVec3, 0.0) + vec4(multiplierVec2, 0.0, 0.0);\n" \
+ " gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0) * randomMult * multiplier;\n" \
+ "}\n");
+
+const QByteArray fragCodeUniformsInt = QByteArrayLiteral(
+ "#version 120\n" \
+ "uniform int multiplier;\n" \
+ "uniform ivec2 multiplierVec2;\n" \
+ "uniform ivec3 multiplierVec3;\n" \
+ "uniform ivec4 multiplierVec4;\n" \
+ "void main()\n" \
+ "{\n" \
+ " ivec4 randomMult = multiplierVec4 + ivec4(multiplierVec3, 0) + ivec4(multiplierVec2, 0, 0);\n" \
+ " gl_FragColor = ivec4(1, 0, 0, 1) * randomMult * multiplier;\n" \
+ "}\n");
+
+const QByteArray fragCodeUniformsFloatMatrices = QByteArrayLiteral(
+ "#version 120\n" \
+ "uniform mat2 m2;\n" \
+ "uniform mat2x3 m23;\n" \
+ "uniform mat3x2 m32;\n" \
+ "uniform mat2x4 m24;\n" \
+ "uniform mat4x2 m42;\n" \
+ "uniform mat3 m3;\n" \
+ "uniform mat3x4 m34;\n" \
+ "uniform mat4x3 m43;\n" \
+ "uniform mat4 m4;\n" \
+ "void main()\n" \
+ "{\n" \
+ " float lengthSum = m2[0][0] + m23[0][0] + m32[0][0] + m24[0][0] + m42[0][0] + m3[0][0] + m34[0][0] + m43[0][0] + m4[0][0];\n" \
+ " gl_FragColor = vec4(1, 0, 0, 1) * lengthSum;\n" \
+ "}\n");
+
+
+const QByteArray fragCodeSamplers = QByteArrayLiteral(
+ "#version 120\n" \
+ "varying vec2 texCoord;\n" \
+ "uniform sampler1D s1;\n" \
+ "uniform sampler2D s2;\n" \
+ "uniform sampler3D s3;\n" \
+ "uniform samplerCube scube;\n" \
+ "void main()\n" \
+ "{\n" \
+ " gl_FragColor = vec4(1, 0, 0, 1) *" \
+ " texture1D(s1, texCoord.x) *" \
+ " texture2D(s2, texCoord) *" \
+ " texture3D(s3, vec3(texCoord, 0.0)) *" \
+ " textureCube(scube, vec3(texCoord, 0));\n" \
+ "}\n");
+
+} // anonymous
+
+class tst_GraphicsHelperGL2 : public QObject
+{
+ Q_OBJECT
+private Q_SLOTS:
+
+ void init()
+ {
+ m_window.reset(new QWindow);
+ m_window->setSurfaceType(QWindow::OpenGLSurface);
+ m_window->setGeometry(0, 0, 10, 10);
+ m_window->create();
+
+ QSurfaceFormat format;
+ format.setVersion(2, 0);
+ format.setProfile(QSurfaceFormat::NoProfile);
+ format.setDepthBufferSize(24);
+ format.setSamples(4);
+ format.setStencilBufferSize(8);
+ m_window->setFormat(format);
+ m_glContext.setFormat(format);
+
+ if (!m_glContext.create()) {
+ qWarning() << "Failed to create OpenGL context";
+ return;
+ }
+
+ if (!m_glContext.makeCurrent(m_window.data())) {
+ qWarning() << "Failed to make OpenGL context current";
+ return;
+ }
+
+ if ((m_func = m_glContext.versionFunctions<QOpenGLFunctions_2_0>()) != nullptr) {
+ if (m_glContext.hasExtension(QByteArrayLiteral("GL_ARB_framebuffer_object"))) {
+ m_fboFuncs = new QOpenGLExtension_ARB_framebuffer_object();
+ m_fboFuncs->initializeOpenGLFunctions();
+ }
+ m_glHelper.initializeHelper(&m_glContext, m_func);
+ m_initializationSuccessful = true;
+ }
+ }
+
+ void alphaTest()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ // Deprecated
+ }
+
+ void bindBufferBase()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // Not supported by GL2
+ }
+
+ void bindFragDataLocation()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ // Not supported by GL2
+ }
+
+ void bindFrameBufferAttachment()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ if (!m_fboFuncs)
+ QSKIP("FBO not supported by OpenGL 2.0");
+
+ // GIVEN
+ GLuint fboId;
+ m_fboFuncs->glGenFramebuffers(1, &fboId);
+
+ Attachment attachment;
+ attachment.m_point = QRenderTargetOutput::Color0;
+
+ // THEN
+ QVERIFY(fboId != 0);
+
+ // WHEN
+ m_fboFuncs->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId);
+
+ QOpenGLTexture texture(QOpenGLTexture::Target2D);
+ texture.setSize(512, 512);
+ texture.setFormat(QOpenGLTexture::RGBA32F);
+ texture.setMinificationFilter(QOpenGLTexture::Linear);
+ texture.setMagnificationFilter(QOpenGLTexture::Linear);
+ texture.setWrapMode(QOpenGLTexture::ClampToEdge);
+ if (!texture.create())
+ qWarning() << "Texture creation failed";
+ texture.allocateStorage();
+ QVERIFY(texture.isStorageAllocated());
+ GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ m_glHelper.bindFrameBufferAttachment(&texture, attachment);
+
+ // THEN
+ GLenum status = m_fboFuncs->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ QVERIFY(status == GL_FRAMEBUFFER_COMPLETE);
+
+ error = m_func->glGetError();
+ QVERIFY(error == 0);
+ GLint textureAttachmentId = 0;
+ m_fboFuncs->glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
+ &textureAttachmentId);
+ QCOMPARE(GLuint(textureAttachmentId), texture.textureId());
+
+ // Restore state
+ m_fboFuncs->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ m_fboFuncs->glDeleteFramebuffers(1, &fboId);
+ }
+
+ void bindFrameBufferObject()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ if (!m_fboFuncs)
+ QSKIP("FBO not supported by OpenGL 2.0");
+
+ // GIVEN
+ GLuint fboId;
+ m_fboFuncs->glGenFramebuffers(1, &fboId);
+
+ // THEN
+ QVERIFY(fboId != 0);
+
+ // WHEN
+ m_glHelper.bindFrameBufferObject(fboId);
+
+ // THEN
+ const GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ GLint boundindFBOId = 0;
+ m_func->glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &boundindFBOId);
+ QVERIFY(GLuint(boundindFBOId) == fboId);
+
+ // Cleanup
+ m_fboFuncs->glDeleteFramebuffers(1, &fboId);
+ }
+
+ void bindShaderStorageBlock()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ // Not supported by GL2
+ }
+
+ void bindUniformBlock()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ // Not supported by GL2
+ }
+
+ void blendEquation()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // GIVEN
+ GLint equation = 0;
+ m_func->glGetIntegerv(GL_BLEND_EQUATION_RGB, &equation);
+ QCOMPARE(equation, GL_FUNC_ADD);
+
+ // WHEN
+ m_glHelper.blendEquation(GL_FUNC_REVERSE_SUBTRACT);
+
+ // THEN
+ m_func->glGetIntegerv(GL_BLEND_EQUATION_RGB, &equation);
+ QCOMPARE(equation, GL_FUNC_REVERSE_SUBTRACT);
+ }
+
+ void blendFunci()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ // Not supported by GL2
+ }
+
+ void blendFuncSeparatei()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ // Not supported by GL2
+ }
+
+ void boundFrameBufferObject()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ if (!m_fboFuncs)
+ QSKIP("FBO not supported by OpenGL 2.0");
+
+ // GIVEN
+ GLuint fboId;
+ m_fboFuncs->glGenFramebuffers(1, &fboId);
+
+ // WHEN
+ m_fboFuncs->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId);
+
+ // THEN
+ GLint boundBuffer = 0;
+ m_func->glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &boundBuffer);
+ QCOMPARE(GLuint(boundBuffer), fboId);
+
+ // THEN
+ QCOMPARE(m_glHelper.boundFrameBufferObject(), fboId);
+
+ // Reset state
+ m_fboFuncs->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ m_fboFuncs->glDeleteFramebuffers(1, &fboId);
+ }
+
+ void checkFrameBufferComplete()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ if (!m_fboFuncs)
+ QSKIP("FBO not supported by OpenGL 2.0");
+
+ // GIVEN
+ GLuint fboId;
+ m_fboFuncs->glGenFramebuffers(1, &fboId);
+
+ Attachment attachment;
+ attachment.m_point = QRenderTargetOutput::Color0;
+
+ m_fboFuncs->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId);
+
+ QOpenGLTexture texture(QOpenGLTexture::Target2D);
+ texture.setSize(512, 512);
+ texture.setFormat(QOpenGLTexture::RGBA8U);
+ texture.setMinificationFilter(QOpenGLTexture::Linear);
+ texture.setMagnificationFilter(QOpenGLTexture::Linear);
+ texture.create();
+ texture.allocateStorage();
+ m_glHelper.bindFrameBufferAttachment(&texture, attachment);
+
+ // THEN
+ GLenum status = m_fboFuncs->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ QVERIFY(status == GL_FRAMEBUFFER_COMPLETE);
+
+ QVERIFY(m_glHelper.checkFrameBufferComplete());
+
+ // Restore
+ m_fboFuncs->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ m_fboFuncs->glDeleteFramebuffers(1, &fboId);
+ }
+
+ void clearBufferf()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ // Not supported by GL2
+ }
+
+ void createFrameBufferObject()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ if (!m_fboFuncs)
+ QSKIP("FBO not supported by OpenGL 2.0");
+
+ // WHEN
+ const GLuint fboId = m_glHelper.createFrameBufferObject();
+
+ // THEN
+ QVERIFY(fboId != 0);
+
+ // Restore
+ m_fboFuncs->glDeleteFramebuffers(1, &fboId);
+ }
+
+ void depthMask()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // GIVEN
+ GLboolean depthWritingEnabled = false;
+ m_func->glGetBooleanv(GL_DEPTH_WRITEMASK, &depthWritingEnabled);
+
+ // THEN
+ QVERIFY(depthWritingEnabled);
+
+ // WHEN
+ m_glHelper.depthMask(GL_FALSE);
+
+ // THEN
+ m_func->glGetBooleanv(GL_DEPTH_WRITEMASK, &depthWritingEnabled);
+ QVERIFY(!depthWritingEnabled);
+
+ // WHEN
+ m_glHelper.depthMask(GL_TRUE);
+
+ // THEN
+ m_func->glGetBooleanv(GL_DEPTH_WRITEMASK, &depthWritingEnabled);
+ QVERIFY(depthWritingEnabled);
+ }
+
+ void depthTest()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // GIVEN
+ m_func->glDisable(GL_DEPTH_TEST);
+ m_func->glDepthFunc(GL_LESS);
+
+ // WHEN
+ m_glHelper.depthTest(GL_LEQUAL);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_DEPTH_TEST));
+ GLint depthMode = 0;
+ m_func->glGetIntegerv(GL_DEPTH_FUNC, &depthMode);
+ QCOMPARE(depthMode, GL_LEQUAL);
+
+ // WHEN
+ m_glHelper.depthTest(GL_LESS);
+ QVERIFY(m_func->glIsEnabled(GL_DEPTH_TEST));
+ m_func->glGetIntegerv(GL_DEPTH_FUNC, &depthMode);
+ QCOMPARE(depthMode, GL_LESS);
+ }
+
+ void disableClipPlane()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // GIVEN
+ m_func->glEnable(GL_CLIP_DISTANCE0 + 5);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_CLIP_DISTANCE0 + 5));
+
+ // WHEN
+ m_glHelper.disableClipPlane(5);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_CLIP_DISTANCE0 + 5));
+ }
+
+ void disablei()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ // Not supported by GL2
+ }
+
+ void disablePrimitiveRestart()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ // Not supported by GL2
+ }
+
+ void drawBuffers()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ if (!m_fboFuncs)
+ QSKIP("FBO not supported by OpenGL 2.0");
+
+ // GIVEN
+ GLuint fboId;
+ m_fboFuncs->glGenFramebuffers(1, &fboId);
+
+ // THEN
+ QVERIFY(fboId != 0);
+
+ // WHEN
+ m_fboFuncs->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId);
+ QOpenGLTexture *textures[4];
+
+ // Create 4 attachments
+ for (int i = 0; i < 4; ++i) {
+ Attachment attachment;
+ attachment.m_point = static_cast<QRenderTargetOutput::AttachmentPoint>(i);
+
+ QOpenGLTexture *texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
+ textures[i] = texture;
+ texture->setSize(512, 512);
+ texture->setFormat(QOpenGLTexture::RGBA32F);
+ texture->setMinificationFilter(QOpenGLTexture::Linear);
+ texture->setMagnificationFilter(QOpenGLTexture::Linear);
+ texture->setWrapMode(QOpenGLTexture::ClampToEdge);
+ if (!texture->create())
+ qWarning() << "Texture creation failed";
+ texture->allocateStorage();
+ QVERIFY(texture->isStorageAllocated());
+ GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ m_glHelper.bindFrameBufferAttachment(texture, attachment);
+ }
+ // THEN
+ GLenum status = m_fboFuncs->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ QVERIFY(status == GL_FRAMEBUFFER_COMPLETE);
+
+ // WHEN
+ GLenum bufferEnum = GL_COLOR_ATTACHMENT4;
+ m_func->glDrawBuffers(1, &bufferEnum);
+
+ // THEN
+ GLint enumValue = -1;
+ m_func->glGetIntegerv(GL_DRAW_BUFFER0, &enumValue);
+ QCOMPARE(enumValue, GL_COLOR_ATTACHMENT4);
+
+ // WHEN
+ GLint newBufferEnum = 2;
+ m_glHelper.drawBuffers(1, &newBufferEnum);
+
+ // THEN
+ m_func->glGetIntegerv(GL_DRAW_BUFFER0, &enumValue);
+ QCOMPARE(enumValue, GL_COLOR_ATTACHMENT0 + newBufferEnum);
+
+ // WHEN
+ newBufferEnum = 0;
+ m_glHelper.drawBuffers(1, &newBufferEnum);
+
+ // THEN
+ m_func->glGetIntegerv(GL_DRAW_BUFFER0, &enumValue);
+ QCOMPARE(enumValue, GL_COLOR_ATTACHMENT0 + newBufferEnum);
+
+ // Restore
+ m_fboFuncs->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ m_fboFuncs->glDeleteFramebuffers(1, &fboId);
+ for (int i = 0; i < 4; ++i)
+ delete textures[i];
+ }
+
+ void enableClipPlane()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // GIVEN
+ m_func->glDisable(GL_CLIP_DISTANCE0 + 4);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_CLIP_DISTANCE0 + 4));
+
+ // WHEN
+ m_glHelper.enableClipPlane(4);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_CLIP_DISTANCE0 + 4));
+ }
+
+ void enablei()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ // Not supported by GL2
+ }
+
+ void enablePrimitiveRestart()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ // Not supported by GL2
+ }
+
+ void frontFace()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // GIVEN
+ m_func->glFrontFace(GL_CW);
+
+ // THEN
+ GLint face = 0;
+ m_func->glGetIntegerv(GL_FRONT_FACE, &face);
+ QCOMPARE(face, GL_CW);
+
+ // WHEN
+ m_glHelper.frontFace(GL_CCW);
+
+ // THEN
+ m_func->glGetIntegerv(GL_FRONT_FACE, &face);
+ QCOMPARE(face, GL_CCW);
+ }
+
+ void getRenderBufferDimensions()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ // Not supported by GL2
+ }
+
+ void getTextureDimensions()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // GIVEN
+ QOpenGLTexture texture(QOpenGLTexture::Target2D);
+ texture.setSize(512, 512);
+ texture.setFormat(QOpenGLTexture::RGBA8U);
+ texture.setMinificationFilter(QOpenGLTexture::Linear);
+ texture.setMagnificationFilter(QOpenGLTexture::Linear);
+ texture.create();
+ texture.allocateStorage();
+
+ // WHEN
+ const QSize dimensions = m_glHelper.getTextureDimensions(texture.textureId(), GL_TEXTURE_2D);
+
+ // THEN
+ QCOMPARE(dimensions, QSize(512, 512));
+ }
+
+ void pointSize()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // WHEN
+ m_glHelper.pointSize(false, 0.5f);
+ // THEN
+ GLfloat size = 0.0f;
+ m_func->glGetFloatv(GL_POINT_SIZE, &size);
+ QCOMPARE(size, 0.5f);
+ }
+
+ void maxClipPlaneCount()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // GIVEN
+ GLint maxCount = -1;
+ m_func->glGetIntegerv(GL_MAX_CLIP_PLANES, &maxCount);
+
+ // THEN
+ QCOMPARE(maxCount, m_glHelper.maxClipPlaneCount());
+ }
+
+ void programUniformBlock()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // Not supported by GL2
+ }
+
+ void programAttributesAndLocations()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeSamplers);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ QVector<ShaderAttribute> activeAttributes = m_glHelper.programAttributesAndLocations(shaderProgram.programId());
+
+ // THEN
+ QCOMPARE(activeAttributes.size(), 2);
+ std::sort(activeAttributes.begin(), activeAttributes.end(), [] (const ShaderAttribute &a, const ShaderAttribute &b) { return a.m_name < b.m_name; });
+
+ const ShaderAttribute attribute1 = activeAttributes.at(0);
+ QCOMPARE(attribute1.m_name, QStringLiteral("vertexPosition"));
+ QCOMPARE(attribute1.m_size, 1);
+ QCOMPARE(attribute1.m_location, shaderProgram.attributeLocation("vertexPosition"));
+ QCOMPARE(attribute1.m_type, GLenum(GL_FLOAT_VEC3));
+
+ const ShaderAttribute attribute2 = activeAttributes.at(1);
+ QCOMPARE(attribute2.m_name, QStringLiteral("vertexTexCoord"));
+ QCOMPARE(attribute2.m_size, 1);
+ QCOMPARE(attribute2.m_location, shaderProgram.attributeLocation("vertexTexCoord"));
+ QCOMPARE(attribute2.m_type, GLenum(GL_FLOAT_VEC2));
+ }
+
+ void programUniformsAndLocations()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloat);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ QVector<ShaderUniform> activeUniforms = m_glHelper.programUniformsAndLocations(shaderProgram.programId());
+
+ // THEN
+ QCOMPARE(activeUniforms.size(), 4);
+ std::sort(activeUniforms.begin(), activeUniforms.end(), [] (const ShaderUniform &a, const ShaderUniform &b) { return a.m_name < b.m_name; });
+
+ const ShaderUniform uniform1 = activeUniforms.at(0);
+ QCOMPARE(uniform1.m_location, shaderProgram.uniformLocation("multiplier"));
+ QCOMPARE(uniform1.m_offset, -1);
+ QCOMPARE(uniform1.m_blockIndex, -1);
+ QCOMPARE(uniform1.m_arrayStride, -1);
+ QCOMPARE(uniform1.m_matrixStride, -1);
+ QCOMPARE(uniform1.m_size, 1);
+ QCOMPARE(uniform1.m_type, GLenum(GL_FLOAT));
+ QCOMPARE(uniform1.m_name, QStringLiteral("multiplier"));
+
+ const ShaderUniform uniform2 = activeUniforms.at(1);
+ QCOMPARE(uniform2.m_location, shaderProgram.uniformLocation("multiplierVec2"));
+ QCOMPARE(uniform2.m_offset, -1);
+ QCOMPARE(uniform2.m_blockIndex, -1);
+ QCOMPARE(uniform2.m_arrayStride, -1);
+ QCOMPARE(uniform2.m_matrixStride, -1);
+ QCOMPARE(uniform2.m_size, 1);
+ QCOMPARE(uniform2.m_type, GLenum(GL_FLOAT_VEC2));
+ QCOMPARE(uniform2.m_name, QStringLiteral("multiplierVec2"));
+
+ const ShaderUniform uniform3 = activeUniforms.at(2);
+ QCOMPARE(uniform3.m_location, shaderProgram.uniformLocation("multiplierVec3"));
+ QCOMPARE(uniform3.m_offset, -1);
+ QCOMPARE(uniform3.m_blockIndex, -1);
+ QCOMPARE(uniform3.m_arrayStride, -1);
+ QCOMPARE(uniform3.m_matrixStride, -1);
+ QCOMPARE(uniform3.m_size, 1);
+ QCOMPARE(uniform3.m_type, GLenum(GL_FLOAT_VEC3));
+ QCOMPARE(uniform3.m_name, QStringLiteral("multiplierVec3"));
+
+ const ShaderUniform uniform4 = activeUniforms.at(3);
+ QCOMPARE(uniform4.m_location, shaderProgram.uniformLocation("multiplierVec4"));
+ QCOMPARE(uniform4.m_offset, -1);
+ QCOMPARE(uniform4.m_blockIndex, -1);
+ QCOMPARE(uniform4.m_arrayStride, -1);
+ QCOMPARE(uniform4.m_matrixStride, -1);
+ QCOMPARE(uniform4.m_size, 1);
+ QCOMPARE(uniform4.m_type, GLenum(GL_FLOAT_VEC4));
+ QCOMPARE(uniform4.m_name, QStringLiteral("multiplierVec4"));
+ }
+
+ void programShaderStorageBlock()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ // Not supported by GL2
+ }
+
+ void releaseFrameBufferObject()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ if (!m_fboFuncs)
+ QSKIP("FBO not supported by OpenGL 2.0");
+ // GIVEN
+ GLuint fboId;
+ m_fboFuncs->glGenFramebuffers(1, &fboId);
+
+ // THEN
+ QVERIFY(fboId != 0);
+
+ // WHEN
+ m_glHelper.releaseFrameBufferObject(fboId);
+
+ // THEN
+ QVERIFY(!m_fboFuncs->glIsFramebuffer(fboId));
+ }
+
+ void setMSAAEnabled()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // GIVEN
+ m_func->glDisable(GL_MULTISAMPLE);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_MULTISAMPLE));
+
+ // WHEN
+ m_glHelper.setMSAAEnabled(true);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_MULTISAMPLE));
+
+ // WHEN
+ m_glHelper.setMSAAEnabled(false);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_MULTISAMPLE));
+ }
+
+ void setAlphaCoverageEnabled()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // GIVEN
+ m_func->glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE));
+
+ // WHEN
+ m_glHelper.setAlphaCoverageEnabled(true);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE));
+
+ // WHEN
+ m_glHelper.setAlphaCoverageEnabled(false);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE));
+ }
+
+ void setClipPlane()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // Deprecated in 3.3 core
+ }
+
+ void setSeamlessCubemap()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ // Not supported in GL2
+ }
+
+ void setVerticesPerPatch()
+ {
+ // Not supported in GL2
+ }
+
+#define SUPPORTS_FEATURE(Feature, IsSupported) \
+ QVERIFY(m_glHelper.supportsFeature(Feature) == IsSupported);
+
+ void supportsFeature()
+ {
+ SUPPORTS_FEATURE(GraphicsHelperInterface::MRT, (m_fboFuncs != nullptr));
+ SUPPORTS_FEATURE(GraphicsHelperInterface::UniformBufferObject, false);
+ SUPPORTS_FEATURE(GraphicsHelperInterface::BindableFragmentOutputs, false);
+ SUPPORTS_FEATURE(GraphicsHelperInterface::PrimitiveRestart, false);
+ SUPPORTS_FEATURE(GraphicsHelperInterface::RenderBufferDimensionRetrieval, false);
+ SUPPORTS_FEATURE(GraphicsHelperInterface::TextureDimensionRetrieval, true);
+ SUPPORTS_FEATURE(GraphicsHelperInterface::UniformBufferObject, false);
+ SUPPORTS_FEATURE(GraphicsHelperInterface::ShaderStorageObject, false);
+ SUPPORTS_FEATURE(GraphicsHelperInterface::Compute, false);
+ SUPPORTS_FEATURE(GraphicsHelperInterface::DrawBuffersBlend, false);
+ SUPPORTS_FEATURE(GraphicsHelperInterface::Tessellation, false);
+ }
+
+
+#define ADD_UNIFORM_ENTRY(FragShader, Name, Type, ComponentSize, ExpectedRawSize) \
+ QTest::newRow(#FragShader"_"#Type) << FragShader << QStringLiteral(Name) << Type << ComponentSize << ExpectedRawSize;
+
+ void uniformsByteSize_data()
+ {
+ QTest::addColumn<QByteArray>("fragShader");
+ QTest::addColumn<QString>("name");
+ QTest::addColumn<int>("type");
+ QTest::addColumn<int>("componentSize");
+ QTest::addColumn<int>("expectedByteSize");
+
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloat, "multiplier", GL_FLOAT, 1, 4);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloat, "multiplierVec2", GL_FLOAT_VEC2, 1, 4 * 2);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloat, "multiplierVec3",GL_FLOAT_VEC3, 1, 4 * 3);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloat, "multiplierVec4", GL_FLOAT_VEC4, 1, 4 * 4);
+
+ ADD_UNIFORM_ENTRY(fragCodeUniformsInt, "multiplier", GL_INT, 1, 4);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsInt, "multiplierVec2", GL_INT_VEC2, 1, 4 * 2);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsInt, "multiplierVec3", GL_INT_VEC3, 1, 4 * 3);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsInt, "multiplierVec4", GL_INT_VEC4, 1, 4 * 4);
+
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m2", GL_FLOAT_MAT2, 1, 4 * 2 * 2);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m3", GL_FLOAT_MAT3, 1, 4 * 3 * 3);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m4", GL_FLOAT_MAT4, 1, 4 * 4 * 4);
+
+ ADD_UNIFORM_ENTRY(fragCodeSamplers, "s1", GL_SAMPLER_1D, 1, 4);
+ ADD_UNIFORM_ENTRY(fragCodeSamplers, "s2", GL_SAMPLER_2D, 1, 4);
+ ADD_UNIFORM_ENTRY(fragCodeSamplers, "s3", GL_SAMPLER_3D, 1, 4);
+ ADD_UNIFORM_ENTRY(fragCodeSamplers, "scube", GL_SAMPLER_CUBE, 1, 4);
+ }
+
+ void uniformsByteSize()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // GIVEN
+ QFETCH(QByteArray, fragShader);
+ QFETCH(QString, name);
+ QFETCH(int, type);
+ QFETCH(int, componentSize);
+ QFETCH(int, expectedByteSize);
+
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragShader);
+ QVERIFY(shaderProgram.link());
+
+ GLint location = shaderProgram.uniformLocation(name);
+ // WHEN
+ const QVector<ShaderUniform> activeUniforms = m_glHelper.programUniformsAndLocations(shaderProgram.programId());
+ ShaderUniform matchingUniform;
+ for (const ShaderUniform &u : activeUniforms) {
+ if (u.m_location == location) {
+ matchingUniform = u;
+ break;
+ }
+ }
+
+ // THEN
+ QCOMPARE(matchingUniform.m_location, location);
+ QCOMPARE(matchingUniform.m_type, GLuint(type));
+ QCOMPARE(matchingUniform.m_size, componentSize);
+
+ // WHEN
+ const int computedRawByteSize = m_glHelper.uniformByteSize(matchingUniform);
+
+ // THEN
+ QCOMPARE(expectedByteSize, computedRawByteSize);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void useProgram()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloat);
+
+ // THEN
+ QVERIFY(shaderProgram.link());
+
+ GLint currentProg = 0;
+ m_func->glGetIntegerv(GL_CURRENT_PROGRAM, &currentProg);
+ QVERIFY(currentProg == 0);
+
+ // WHEN
+ m_glHelper.useProgram(shaderProgram.programId());
+
+ // THEN
+ m_func->glGetIntegerv(GL_CURRENT_PROGRAM, &currentProg);
+ QCOMPARE(GLuint(currentProg), shaderProgram.programId());
+
+ // WHEN
+ m_glHelper.useProgram(0);
+
+ // THEN
+ m_func->glGetIntegerv(GL_CURRENT_PROGRAM, &currentProg);
+ QVERIFY(currentProg == 0);
+ }
+
+ void vertexAttribDivisor()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ // Not available in 3.2
+ }
+
+ void glUniform1fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloat);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat value = 883.0f;
+ const GLint location = shaderProgram.uniformLocation("multiplier");
+ m_glHelper.glUniform1fv(location, 1, &value);
+
+ // THEN
+ GLfloat setValue = 0.0f;
+ m_func->glGetUniformfv(shaderProgram.programId(), location, &setValue);
+ QCOMPARE(value, setValue);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform2fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloat);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[2] = { 383.0f, 427.0f };
+ const GLint location = shaderProgram.uniformLocation("multiplierVec2");
+ m_glHelper.glUniform2fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[2] = { 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 2; ++i)
+ QCOMPARE(setValues[i], values[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform3fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloat);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[3] = { 572.0f, 1340.0f, 1584.0f };
+ const GLint location = shaderProgram.uniformLocation("multiplierVec3");
+ m_glHelper.glUniform3fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[3] = { 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 3; ++i)
+ QCOMPARE(setValues[i], values[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform4fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloat);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[4] = { 454.0f, 350.0f, 883.0f, 355.0f };
+ const GLint location = shaderProgram.uniformLocation("multiplierVec4");
+ m_glHelper.glUniform4fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 4; ++i)
+ QCOMPARE(setValues[i], values[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform1iv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsInt);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLint value = 883;
+ const GLint location = shaderProgram.uniformLocation("multiplier");
+ m_glHelper.glUniform1iv(location, 1, &value);
+
+ // THEN
+ GLint setValue = 0;
+ m_func->glGetUniformiv(shaderProgram.programId(), location, &setValue);
+ QCOMPARE(value, setValue);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform2iv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsInt);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLint values[2] = { 383, 427 };
+ const GLint location = shaderProgram.uniformLocation("multiplierVec2");
+ m_glHelper.glUniform2iv(location, 1, values);
+
+ // THEN
+ GLint setValues[2] = { 0, 0 };
+ m_func->glGetUniformiv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 2; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform3iv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsInt);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLint values[3] = { 572, 1340, 1584 };
+ const GLint location = shaderProgram.uniformLocation("multiplierVec3");
+ m_glHelper.glUniform3iv(location, 1, values);
+
+ // THEN
+ GLint setValues[3] = { 0, 0, 0 };
+ m_func->glGetUniformiv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 3; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform4iv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsInt);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLint values[4] = { 454, 350, 883, 355 };
+ const GLint location = shaderProgram.uniformLocation("multiplierVec4");
+ m_glHelper.glUniform4iv(location, 1, values);
+
+ // THEN
+ GLint setValues[4] = { 0, 0, 0, 0 };
+ m_func->glGetUniformiv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 4; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform1uiv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ // Not supported by GL2
+ }
+
+ void glUniform2uiv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ // Not supported by GL2
+ }
+
+ void glUniform3uiv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ // Not supported by GL2
+ }
+
+ void glUniform4uiv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ // Not supported by GL2
+ }
+
+ void glUniformMatrix2fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[4] = { 454.0f, 350.0f, 883.0f, 355.0f };
+ const GLint location = shaderProgram.uniformLocation("m2");
+ m_glHelper.glUniformMatrix2fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 4; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix3fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[9] = { 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f, 1200.0f, 427.0f, 396.0f };
+ const GLint location = shaderProgram.uniformLocation("m3");
+ m_glHelper.glUniformMatrix3fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[9] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 9; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix4fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[16] = { 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f, 1200.0f, 427.0f, 396.0f, 1603.0f, 55.0f, 5.7, 383.0f, 6.2f, 5.3f, 327.0f };
+ const GLint location = shaderProgram.uniformLocation("m4");
+ m_glHelper.glUniformMatrix4fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[16] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 16; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix2x3fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ // Not supported by GL2
+ }
+
+ void glUniformMatrix3x2fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ // Not supported by GL2
+ }
+
+ void glUniformMatrix2x4fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ // Not supported by GL2
+ }
+
+ void glUniformMatrix4x2fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ // Not supported by GL2
+ }
+
+ void glUniformMatrix3x4fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ // Not supported by GL2
+ }
+
+ void glUniformMatrix4x3fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ // Not supported by GL2
+ }
+
+#define ADD_GL_TYPE_ENTRY(Type, Expected) \
+ QTest::newRow(#Type) << Type << Expected;
+
+ void uniformTypeFromGLType_data()
+ {
+ QTest::addColumn<int>("glType");
+ QTest::addColumn<UniformType>("expected");
+
+ ADD_GL_TYPE_ENTRY(GL_FLOAT, UniformType::Float);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC2, UniformType::Vec2);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC3, UniformType::Vec3);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC3, UniformType::Vec3);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC2, UniformType::Vec2);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC3, UniformType::Vec3);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC3, UniformType::Vec3);
+ ADD_GL_TYPE_ENTRY(GL_INT, UniformType::Int);
+ ADD_GL_TYPE_ENTRY(GL_INT_VEC2, UniformType::IVec2);
+ ADD_GL_TYPE_ENTRY(GL_INT_VEC3, UniformType::IVec3);
+ ADD_GL_TYPE_ENTRY(GL_INT_VEC4, UniformType::IVec4);
+ ADD_GL_TYPE_ENTRY(GL_BOOL, UniformType::Bool);
+ ADD_GL_TYPE_ENTRY(GL_BOOL_VEC2, UniformType::BVec2);
+ ADD_GL_TYPE_ENTRY(GL_BOOL_VEC3, UniformType::BVec3);
+ ADD_GL_TYPE_ENTRY(GL_BOOL_VEC4, UniformType::BVec4);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT2, UniformType::Mat2);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT3, UniformType::Mat3);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT4, UniformType::Mat4);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_1D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_1D_SHADOW, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_2D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_2D_SHADOW, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_3D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_CUBE, UniformType::Sampler);
+ }
+
+ void uniformTypeFromGLType()
+ {
+ // GIVEN
+ QFETCH(int, glType);
+ QFETCH(UniformType, expected);
+
+ // WHEN
+ UniformType computed = m_glHelper.uniformTypeFromGLType(glType);
+
+ // THEN
+ QCOMPARE(computed, expected);
+ }
+
+private:
+ QScopedPointer<QWindow> m_window;
+ QOpenGLContext m_glContext;
+ GraphicsHelperGL2 m_glHelper;
+ QOpenGLFunctions_2_0 *m_func = nullptr;
+ QOpenGLExtension_ARB_framebuffer_object *m_fboFuncs = nullptr;
+ bool m_initializationSuccessful = false;
+};
+
+QT_END_NAMESPACE
+
+#endif
+
+
+QT_BEGIN_NAMESPACE
+QTEST_ADD_GPU_BLACKLIST_SUPPORT_DEFS
+QT_END_NAMESPACE
+
+int main(int argc, char *argv[])
+{
+#ifdef TEST_SHOULD_BE_PERFORMED
+ QGuiApplication app(argc, argv);
+ app.setAttribute(Qt::AA_Use96Dpi, true);
+ QTEST_ADD_GPU_BLACKLIST_SUPPORT
+ tst_GraphicsHelperGL2 tc;
+ QTEST_SET_MAIN_SOURCE_PATH
+ return QTest::qExec(&tc, argc, argv);
+#endif
+ return 0;
+}
+
+#ifdef TEST_SHOULD_BE_PERFORMED
+#include "tst_graphicshelpergl2.moc"
+#endif
diff --git a/tests/auto/render/graphicshelpergl3_2/graphicshelpergl3_2.pro b/tests/auto/render/graphicshelpergl3_2/graphicshelpergl3_2.pro
new file mode 100644
index 000000000..5d8bf60fd
--- /dev/null
+++ b/tests/auto/render/graphicshelpergl3_2/graphicshelpergl3_2.pro
@@ -0,0 +1,13 @@
+TEMPLATE = app
+
+TARGET = tst_graphicshelpergl3_2
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += \
+ tst_graphicshelpergl3_2.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/graphicshelpergl3_2/tst_graphicshelpergl3_2.cpp b/tests/auto/render/graphicshelpergl3_2/tst_graphicshelpergl3_2.cpp
new file mode 100644
index 000000000..e4b9bca39
--- /dev/null
+++ b/tests/auto/render/graphicshelpergl3_2/tst_graphicshelpergl3_2.cpp
@@ -0,0 +1,1969 @@
+/****************************************************************************
+**
+** 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:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QTest>
+#include <Qt3DRender/qrendertargetoutput.h>
+#include <Qt3DRender/private/uniform_p.h>
+#include <Qt3DRender/private/graphicshelpergl3_2_p.h>
+#include <Qt3DRender/private/attachmentpack_p.h>
+#include <QOpenGLFunctions_3_2_Core>
+#include <QOpenGLShaderProgram>
+#include <QSurfaceFormat>
+
+#if !defined(QT_OPENGL_ES_2) && defined(QT_OPENGL_3_2)
+
+#define TEST_SHOULD_BE_PERFORMED 1
+
+using namespace Qt3DRender;
+using namespace Qt3DRender::Render;
+
+namespace {
+
+const QByteArray vertCode = QByteArrayLiteral(
+ "#version 150 core\n" \
+ "in vec3 vertexPosition;\n" \
+ "in vec2 vertexTexCoord;\n" \
+ "out vec2 texCoord;\n" \
+ "void main()\n" \
+ "{\n" \
+ " texCoord = vertexTexCoord;\n" \
+ " gl_Position = vec4(vertexPosition, 1.0);\n" \
+ "}\n");
+
+const QByteArray vertCodeUniformBuffer = QByteArrayLiteral(
+ "#version 150 core\n" \
+ "in vec3 vertexPosition;\n" \
+ "in vec2 vertexTexCoord;\n" \
+ "in int vertexColorIndex;\n" \
+ "out vec2 texCoord;\n" \
+ "flat out int colorIndex;\n" \
+ "void main()\n" \
+ "{\n" \
+ " texCoord = vertexTexCoord;\n" \
+ " colorIndex = vertexColorIndex;\n" \
+ " gl_Position = vec4(vertexPosition, 1.0);\n" \
+ "}\n");
+
+const QByteArray fragCodeFragOutputs = QByteArrayLiteral(
+ "#version 150 core\n" \
+ "out vec4 color;\n" \
+ "out vec2 temp;\n" \
+ "void main()\n" \
+ "{\n" \
+ " color = vec4(1.0, 0.0, 0.0, 1.0);\n" \
+ " temp = vec2(1.0, 0.3);\n" \
+ "}\n");
+
+const QByteArray fragCodeUniformsFloat = QByteArrayLiteral(
+ "#version 150 core\n" \
+ "out vec4 color;\n" \
+ "uniform float multiplier;\n" \
+ "uniform vec2 multiplierVec2;\n" \
+ "uniform vec3 multiplierVec3;\n" \
+ "uniform vec4 multiplierVec4;\n" \
+ "void main()\n" \
+ "{\n" \
+ " vec4 randomMult = multiplierVec4 + vec4(multiplierVec3, 0.0) + vec4(multiplierVec2, 0.0, 0.0);\n" \
+ " color = vec4(1.0, 0.0, 0.0, 1.0) * randomMult * multiplier;\n" \
+ "}\n");
+
+const QByteArray fragCodeUniformsInt = QByteArrayLiteral(
+ "#version 150 core\n" \
+ "out vec4 color;\n" \
+ "uniform int multiplier;\n" \
+ "uniform ivec2 multiplierVec2;\n" \
+ "uniform ivec3 multiplierVec3;\n" \
+ "uniform ivec4 multiplierVec4;\n" \
+ "void main()\n" \
+ "{\n" \
+ " ivec4 randomMult = multiplierVec4 + ivec4(multiplierVec3, 0) + ivec4(multiplierVec2, 0, 0);\n" \
+ " color = ivec4(1, 0, 0, 1) * randomMult * multiplier;\n" \
+ "}\n");
+
+const QByteArray fragCodeUniformsUInt = QByteArrayLiteral(
+ "#version 150 core\n" \
+ "out vec4 color;\n" \
+ "uniform uint multiplier;\n" \
+ "uniform uvec2 multiplierVec2;\n" \
+ "uniform uvec3 multiplierVec3;\n" \
+ "uniform uvec4 multiplierVec4;\n" \
+ "void main()\n" \
+ "{\n" \
+ " uvec4 randomMult = multiplierVec4 + uvec4(multiplierVec3, 0) + uvec4(multiplierVec2, 0, 0);\n" \
+ " color = uvec4(1, 0, 0, 1) * randomMult * multiplier;\n" \
+ "}\n");
+
+const QByteArray fragCodeUniformsFloatMatrices = QByteArrayLiteral(
+ "#version 150 core\n" \
+ "out vec4 color;\n" \
+ "uniform mat2 m2;\n" \
+ "uniform mat2x3 m23;\n" \
+ "uniform mat3x2 m32;\n" \
+ "uniform mat2x4 m24;\n" \
+ "uniform mat4x2 m42;\n" \
+ "uniform mat3 m3;\n" \
+ "uniform mat3x4 m34;\n" \
+ "uniform mat4x3 m43;\n" \
+ "uniform mat4 m4;\n" \
+ "void main()\n" \
+ "{\n" \
+ " float lengthSum = m2[0][0] + m23[0][0] + m32[0][0] + m24[0][0] + m42[0][0] + m3[0][0] + m34[0][0] + m43[0][0] + m4[0][0];\n" \
+ " color = vec4(1, 0, 0, 1) * lengthSum;\n" \
+ "}\n");
+
+const QByteArray fragCodeUniformBuffer = QByteArrayLiteral(
+ "#version 150 core\n" \
+ "out vec4 color;\n" \
+ "flat in int colorIndex;\n" \
+ "uniform ColorArray\n" \
+ "{\n" \
+ " vec4 colors[256];\n" \
+ "};\n" \
+ "void main()\n" \
+ "{\n" \
+ " color = colors[colorIndex];\n" \
+ "}\n");
+
+const QByteArray fragCodeSamplers = QByteArrayLiteral(
+ "#version 150 core\n" \
+ "in vec2 texCoord;\n" \
+ "out vec4 color;\n" \
+ "uniform sampler1D s1;\n" \
+ "uniform sampler2D s2;\n" \
+ "uniform sampler2DArray s2a;\n" \
+ "uniform sampler3D s3;\n" \
+ "uniform samplerCube scube;\n" \
+ "uniform sampler2DRect srect;\n" \
+ "void main()\n" \
+ "{\n" \
+ " color = vec4(1, 0, 0, 1) *" \
+ " texture(s1, texCoord.x) *" \
+ " texture(s2, texCoord) *" \
+ " texture(s2a, vec3(texCoord, 0.0)) *" \
+ " texture(s3, vec3(texCoord, 0.0)) *" \
+ " texture(scube, vec3(texCoord, 0)) *" \
+ " texture(srect, texCoord);\n" \
+ "}\n");
+
+} // anonymous
+
+class tst_GraphicsHelperGL3_2 : public QObject
+{
+ Q_OBJECT
+private Q_SLOTS:
+
+ void init()
+ {
+ m_window.reset(new QWindow);
+ m_window->setSurfaceType(QWindow::OpenGLSurface);
+ m_window->setGeometry(0, 0, 10, 10);
+ m_window->create();
+
+ QSurfaceFormat format;
+ format.setVersion(3, 2);
+ format.setProfile(QSurfaceFormat::CoreProfile);
+ format.setDepthBufferSize(24);
+ format.setSamples(4);
+ format.setStencilBufferSize(8);
+ m_window->setFormat(format);
+ m_glContext.setFormat(format);
+
+ if (!m_glContext.create()) {
+ qWarning() << "Failed to create OpenGL context";
+ return;
+ }
+
+ if (!m_glContext.makeCurrent(m_window.data())) {
+ qWarning() << "Failed to make OpenGL context current";
+ return;
+ }
+
+ if ((m_func = m_glContext.versionFunctions<QOpenGLFunctions_3_2_Core>()) != nullptr) {
+ m_glHelper.initializeHelper(&m_glContext, m_func);
+ m_initializationSuccessful = true;
+ }
+ }
+
+ void alphaTest()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+ // Deprecated
+ }
+
+ void bindBufferBase()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ GLuint bufferId = 0;
+ // WHEN
+ m_func->glGenBuffers(1, &bufferId);
+ // THEN
+ QVERIFY(bufferId != 0);
+
+
+ // WHEN
+ m_func->glBindBuffer(GL_UNIFORM_BUFFER, bufferId);
+ m_glHelper.bindBufferBase(GL_UNIFORM_BUFFER, 2, bufferId);
+ // THEN
+ const GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ GLint boundToPointBufferId = 0;
+ m_func->glGetIntegeri_v(GL_UNIFORM_BUFFER_BINDING, 2, &boundToPointBufferId);
+ QVERIFY(boundToPointBufferId == GLint(bufferId));
+
+ // Restore to sane state
+ m_func->glBindBuffer(GL_UNIFORM_BUFFER, 0);
+ m_func->glDeleteBuffers(1, &bufferId);
+ }
+
+ void bindFragDataLocation()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeFragOutputs);
+
+ // WHEN
+ QHash<QString, int> fragLocations;
+ fragLocations.insert(QStringLiteral("temp"), 2);
+ fragLocations.insert(QStringLiteral("color"), 1);
+ m_glHelper.bindFragDataLocation(shaderProgram.programId(), fragLocations);
+
+ // THEN
+ QVERIFY(shaderProgram.link());
+ const GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ const GLint tempLocation = m_func->glGetFragDataLocation(shaderProgram.programId(), "temp");
+ const GLint colorLocation = m_func->glGetFragDataLocation(shaderProgram.programId(), "color");
+ QCOMPARE(tempLocation, 2);
+ QCOMPARE(colorLocation, 1);
+ }
+
+ void bindFrameBufferAttachment()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ GLuint fboId;
+ m_func->glGenFramebuffers(1, &fboId);
+
+ Attachment attachment;
+ attachment.m_point = QRenderTargetOutput::Color0;
+
+ // THEN
+ QVERIFY(fboId != 0);
+
+ // WHEN
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId);
+
+ QOpenGLTexture texture(QOpenGLTexture::Target2D);
+ texture.setSize(512, 512);
+ texture.setFormat(QOpenGLTexture::RGBA32F);
+ texture.setMinificationFilter(QOpenGLTexture::Linear);
+ texture.setMagnificationFilter(QOpenGLTexture::Linear);
+ texture.setWrapMode(QOpenGLTexture::ClampToEdge);
+ if (!texture.create())
+ qWarning() << "Texture creation failed";
+ texture.allocateStorage();
+ QVERIFY(texture.isStorageAllocated());
+ GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ m_glHelper.bindFrameBufferAttachment(&texture, attachment);
+
+ // THEN
+ GLenum status = m_func->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ QVERIFY(status == GL_FRAMEBUFFER_COMPLETE);
+
+ error = m_func->glGetError();
+ QVERIFY(error == 0);
+ GLint textureAttachmentId = 0;
+ m_func->glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
+ &textureAttachmentId);
+ QCOMPARE(GLuint(textureAttachmentId), texture.textureId());
+
+ // Restore state
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ m_func->glDeleteFramebuffers(1, &fboId);
+ }
+
+ void bindFrameBufferObject()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ GLuint fboId;
+ m_func->glGenFramebuffers(1, &fboId);
+
+ // THEN
+ QVERIFY(fboId != 0);
+
+ // WHEN
+ m_glHelper.bindFrameBufferObject(fboId);
+
+ // THEN
+ const GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ GLint boundindFBOId = 0;
+ m_func->glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &boundindFBOId);
+ QVERIFY(GLuint(boundindFBOId) == fboId);
+
+ // Cleanup
+ m_func->glDeleteFramebuffers(1, &fboId);
+ }
+
+ void bindShaderStorageBlock()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+ // Not supported in OpenGL 3.2
+ }
+
+ void bindUniformBlock()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCodeUniformBuffer);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformBuffer);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ GLint index = m_func->glGetUniformBlockIndex(shaderProgram.programId(), "ColorArray");
+ m_glHelper.bindUniformBlock(shaderProgram.programId(), index, 1);
+
+ // THEN
+ const GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ }
+
+ void blendEquation()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ GLint equation = 0;
+ m_func->glGetIntegerv(GL_BLEND_EQUATION_RGB, &equation);
+ QCOMPARE(equation, GL_FUNC_ADD);
+
+ // WHEN
+ m_glHelper.blendEquation(GL_FUNC_REVERSE_SUBTRACT);
+
+ // THEN
+ m_func->glGetIntegerv(GL_BLEND_EQUATION_RGB, &equation);
+ QCOMPARE(equation, GL_FUNC_REVERSE_SUBTRACT);
+ }
+
+ void blendFunci()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+ // Not supported by OpenGL 3.2
+ }
+
+ void blendFuncSeparatei()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // Not supported by OpenGL 3.2
+ }
+
+ void boundFrameBufferObject()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ GLuint fboId;
+ m_func->glGenFramebuffers(1, &fboId);
+
+ // WHEN
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId);
+
+ // THEN
+ GLint boundBuffer = 0;
+ m_func->glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &boundBuffer);
+ QCOMPARE(GLuint(boundBuffer), fboId);
+
+ // THEN
+ QCOMPARE(m_glHelper.boundFrameBufferObject(), fboId);
+
+ // Reset state
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ m_func->glDeleteFramebuffers(1, &fboId);
+ }
+
+ void checkFrameBufferComplete()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+ // GIVEN
+ GLuint fboId;
+ m_func->glGenFramebuffers(1, &fboId);
+
+ Attachment attachment;
+ attachment.m_point = QRenderTargetOutput::Color0;
+
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId);
+
+ QOpenGLTexture texture(QOpenGLTexture::Target2D);
+ texture.setSize(512, 512);
+ texture.setFormat(QOpenGLTexture::RGBA8U);
+ texture.setMinificationFilter(QOpenGLTexture::Linear);
+ texture.setMagnificationFilter(QOpenGLTexture::Linear);
+ texture.create();
+ texture.allocateStorage();
+ m_glHelper.bindFrameBufferAttachment(&texture, attachment);
+
+ // THEN
+ GLenum status = m_func->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ QVERIFY(status == GL_FRAMEBUFFER_COMPLETE);
+
+ QVERIFY(m_glHelper.checkFrameBufferComplete());
+
+ // Restore
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ m_func->glDeleteFramebuffers(1, &fboId);
+ }
+
+ void clearBufferf()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ // GIVEN
+ GLuint fboId;
+ m_func->glGenFramebuffers(1, &fboId);
+
+ // THEN
+ QVERIFY(fboId != 0);
+
+ // WHEN
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId);
+ // Create 4 attachments
+ QOpenGLTexture *textures[4];
+ for (int i = 0; i < 4; ++i) {
+ Attachment attachment;
+ attachment.m_point = static_cast<QRenderTargetOutput::AttachmentPoint>(i);
+
+ QOpenGLTexture *texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
+ textures[i] = texture;
+ texture->setSize(512, 512);
+ texture->setFormat(QOpenGLTexture::RGBA32F);
+ texture->setMinificationFilter(QOpenGLTexture::Linear);
+ texture->setMagnificationFilter(QOpenGLTexture::Linear);
+ texture->setWrapMode(QOpenGLTexture::ClampToEdge);
+ if (!texture->create())
+ qWarning() << "Texture creation failed";
+ texture->allocateStorage();
+ QVERIFY(texture->isStorageAllocated());
+ GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ m_glHelper.bindFrameBufferAttachment(texture, attachment);
+ }
+
+ GLenum status = m_func->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ QVERIFY(status == GL_FRAMEBUFFER_COMPLETE);
+
+ // Set Draw buffers
+ GLenum clearBufferEnum = GL_COLOR_ATTACHMENT3;
+ m_func->glDrawBuffers(1, &clearBufferEnum);
+
+ const GLint bufferIndex = 0; // index of the element in the draw buffers
+ GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+
+ // WHEN
+ const QVector4D clearValue1 = QVector4D(0.5f, 0.2f, 0.4f, 0.8f);
+ m_func->glClearBufferfv(GL_COLOR, bufferIndex, reinterpret_cast<const float *>(&clearValue1));
+ error = m_func->glGetError();
+ QVERIFY(error == 0);
+
+ // THEN
+ QVector<QVector4D> colors(512 * 512);
+ textures[3]->bind();
+ m_func->glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, colors.data());
+ textures[3]->release();
+ for (const QVector4D c : colors)
+ QVERIFY(c == clearValue1);
+
+
+ // WHEN
+ const QVector4D clearValue2 = QVector4D(0.4f, 0.5f, 0.4f, 1.0f);
+ m_glHelper.clearBufferf(bufferIndex, clearValue2);
+
+ // THEN
+ textures[3]->bind();
+ m_func->glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, colors.data());
+ textures[3]->release();
+ for (const QVector4D c : colors)
+ QVERIFY(c == clearValue2);
+
+ // Restore
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ m_func->glDeleteFramebuffers(1, &fboId);
+ for (int i = 0; i < 4; ++i)
+ delete textures[i];
+ }
+
+ void createFrameBufferObject()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // WHEN
+ const GLuint fboId = m_glHelper.createFrameBufferObject();
+
+ // THEN
+ QVERIFY(fboId != 0);
+
+ // Restore
+ m_func->glDeleteFramebuffers(1, &fboId);
+ }
+
+ void depthMask()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ GLboolean depthWritingEnabled = false;
+ m_func->glGetBooleanv(GL_DEPTH_WRITEMASK, &depthWritingEnabled);
+
+ // THEN
+ QVERIFY(depthWritingEnabled);
+
+ // WHEN
+ m_glHelper.depthMask(GL_FALSE);
+
+ // THEN
+ m_func->glGetBooleanv(GL_DEPTH_WRITEMASK, &depthWritingEnabled);
+ QVERIFY(!depthWritingEnabled);
+
+ // WHEN
+ m_glHelper.depthMask(GL_TRUE);
+
+ // THEN
+ m_func->glGetBooleanv(GL_DEPTH_WRITEMASK, &depthWritingEnabled);
+ QVERIFY(depthWritingEnabled);
+ }
+
+ void depthTest()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ m_func->glDisable(GL_DEPTH_TEST);
+ m_func->glDepthFunc(GL_LESS);
+
+ // WHEN
+ m_glHelper.depthTest(GL_LEQUAL);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_DEPTH_TEST));
+ GLint depthMode = 0;
+ m_func->glGetIntegerv(GL_DEPTH_FUNC, &depthMode);
+ QCOMPARE(depthMode, GL_LEQUAL);
+
+ // WHEN
+ m_glHelper.depthTest(GL_LESS);
+ QVERIFY(m_func->glIsEnabled(GL_DEPTH_TEST));
+ m_func->glGetIntegerv(GL_DEPTH_FUNC, &depthMode);
+ QCOMPARE(depthMode, GL_LESS);
+ }
+
+ void disableClipPlane()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ m_func->glEnable(GL_CLIP_DISTANCE0 + 5);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_CLIP_DISTANCE0 + 5));
+
+ // WHEN
+ m_glHelper.disableClipPlane(5);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_CLIP_DISTANCE0 + 5));
+ }
+
+ void disablei()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ m_func->glEnablei(GL_BLEND, 2);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabledi(GL_BLEND, 2));
+
+ // WHEN
+ m_glHelper.disablei(GL_BLEND, 2);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabledi(GL_BLEND, 2));
+ }
+
+ void disablePrimitiveRestart()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ m_func->glEnable(GL_PRIMITIVE_RESTART);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_PRIMITIVE_RESTART));
+
+ // WHEN
+ m_glHelper.disablePrimitiveRestart();
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_PRIMITIVE_RESTART));
+ }
+
+ void drawBuffers()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ GLuint fboId;
+ m_func->glGenFramebuffers(1, &fboId);
+
+ // THEN
+ QVERIFY(fboId != 0);
+
+ // WHEN
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId);
+ QOpenGLTexture *textures[4];
+
+ // Create 4 attachments
+ for (int i = 0; i < 4; ++i) {
+ Attachment attachment;
+ attachment.m_point = static_cast<QRenderTargetOutput::AttachmentPoint>(i);
+
+ QOpenGLTexture *texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
+ textures[i] = texture;
+ texture->setSize(512, 512);
+ texture->setFormat(QOpenGLTexture::RGBA32F);
+ texture->setMinificationFilter(QOpenGLTexture::Linear);
+ texture->setMagnificationFilter(QOpenGLTexture::Linear);
+ texture->setWrapMode(QOpenGLTexture::ClampToEdge);
+ if (!texture->create())
+ qWarning() << "Texture creation failed";
+ texture->allocateStorage();
+ QVERIFY(texture->isStorageAllocated());
+ GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ m_glHelper.bindFrameBufferAttachment(texture, attachment);
+ }
+ // THEN
+ GLenum status = m_func->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ QVERIFY(status == GL_FRAMEBUFFER_COMPLETE);
+
+ // WHEN
+ GLenum bufferEnum = GL_COLOR_ATTACHMENT4;
+ m_func->glDrawBuffers(1, &bufferEnum);
+
+ // THEN
+ GLint enumValue = -1;
+ m_func->glGetIntegerv(GL_DRAW_BUFFER0, &enumValue);
+ QCOMPARE(enumValue, GL_COLOR_ATTACHMENT4);
+
+ // WHEN
+ GLint newBufferEnum = 2;
+ m_glHelper.drawBuffers(1, &newBufferEnum);
+
+ // THEN
+ m_func->glGetIntegerv(GL_DRAW_BUFFER0, &enumValue);
+ QCOMPARE(enumValue, GL_COLOR_ATTACHMENT0 + newBufferEnum);
+
+ // WHEN
+ newBufferEnum = 0;
+ m_glHelper.drawBuffers(1, &newBufferEnum);
+
+ // THEN
+ m_func->glGetIntegerv(GL_DRAW_BUFFER0, &enumValue);
+ QCOMPARE(enumValue, GL_COLOR_ATTACHMENT0 + newBufferEnum);
+
+ // Restore
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ m_func->glDeleteFramebuffers(1, &fboId);
+ for (int i = 0; i < 4; ++i)
+ delete textures[i];
+ }
+
+ void enableClipPlane()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ m_func->glDisable(GL_CLIP_DISTANCE0 + 4);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_CLIP_DISTANCE0 + 4));
+
+ // WHEN
+ m_glHelper.enableClipPlane(4);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_CLIP_DISTANCE0 + 4));
+ }
+
+ void enablei()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ m_func->glDisablei(GL_BLEND, 4);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabledi(GL_BLEND, 4));
+
+ // WHEN
+ m_glHelper.enablei(GL_BLEND, 4);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabledi(GL_BLEND, 4));
+ }
+
+ void enablePrimitiveRestart()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ m_func->glDisable(GL_PRIMITIVE_RESTART);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_PRIMITIVE_RESTART));
+
+ // WHEN
+ m_glHelper.enablePrimitiveRestart(883);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_PRIMITIVE_RESTART));
+ GLint restartIndex = 0;
+ m_func->glGetIntegerv(GL_PRIMITIVE_RESTART_INDEX, &restartIndex);
+ QCOMPARE(restartIndex, 883);
+
+ // Restore
+ m_func->glDisable(GL_PRIMITIVE_RESTART);
+ }
+
+ void frontFace()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ m_func->glFrontFace(GL_CW);
+
+ // THEN
+ GLint face = 0;
+ m_func->glGetIntegerv(GL_FRONT_FACE, &face);
+ QCOMPARE(face, GL_CW);
+
+ // WHEN
+ m_glHelper.frontFace(GL_CCW);
+
+ // THEN
+ m_func->glGetIntegerv(GL_FRONT_FACE, &face);
+ QCOMPARE(face, GL_CCW);
+ }
+
+ void getRenderBufferDimensions()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ GLuint renderBufferId = 0;
+ m_func->glGenRenderbuffers(1, &renderBufferId);
+ QVERIFY(renderBufferId != 0);
+
+ // WHEN
+ m_func->glBindRenderbuffer(GL_RENDERBUFFER, renderBufferId);
+ m_func->glRenderbufferStorage(GL_RENDERBUFFER, GL_SRGB8_ALPHA8, 512, 512);
+ m_func->glBindRenderbuffer(GL_RENDERBUFFER, 0);
+ const QSize dimensions = m_glHelper.getRenderBufferDimensions(renderBufferId);
+
+ // THEN
+ QCOMPARE(dimensions, QSize(512, 512));
+
+ // Restore
+ m_func->glDeleteRenderbuffers(1, &renderBufferId);
+ }
+
+ void getTextureDimensions()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QOpenGLTexture texture(QOpenGLTexture::Target2D);
+ texture.setSize(512, 512);
+ texture.setFormat(QOpenGLTexture::RGBA8U);
+ texture.setMinificationFilter(QOpenGLTexture::Linear);
+ texture.setMagnificationFilter(QOpenGLTexture::Linear);
+ texture.create();
+ texture.allocateStorage();
+
+ // WHEN
+ const QSize dimensions = m_glHelper.getTextureDimensions(texture.textureId(), GL_TEXTURE_2D);
+
+ // THEN
+ QCOMPARE(dimensions, QSize(512, 512));
+ }
+
+ void pointSize()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ m_func->glEnable(GL_PROGRAM_POINT_SIZE);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_PROGRAM_POINT_SIZE));
+ GLfloat size = 0;
+ m_func->glGetFloatv(GL_POINT_SIZE, &size);
+ QCOMPARE(size, 1.0f);
+
+ // WHEN
+ m_glHelper.pointSize(false, 0.5f);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_PROGRAM_POINT_SIZE));
+ m_func->glGetFloatv(GL_POINT_SIZE, &size);
+ QCOMPARE(size, 0.5f);
+ }
+
+ void maxClipPlaneCount()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ GLint maxCount = -1;
+ m_func->glGetIntegerv(GL_MAX_CLIP_PLANES, &maxCount);
+
+ // THEN
+ QCOMPARE(maxCount, m_glHelper.maxClipPlaneCount());
+ }
+
+ void programUniformBlock()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCodeUniformBuffer);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformBuffer);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ const QVector<ShaderUniformBlock> activeUniformBlocks = m_glHelper.programUniformBlocks(shaderProgram.programId());
+
+ // THEN
+ QCOMPARE(activeUniformBlocks.size(), 1);
+ const ShaderUniformBlock uniformBlock = activeUniformBlocks.first();
+
+ QCOMPARE(uniformBlock.m_activeUniformsCount, 1);
+ QCOMPARE(uniformBlock.m_name, QStringLiteral("ColorArray"));
+
+ GLint blockIndex = m_func->glGetUniformBlockIndex(shaderProgram.programId(), "ColorArray");
+ GLint blockBinding = -1;
+ m_func->glGetActiveUniformBlockiv(shaderProgram.programId(), blockIndex, GL_UNIFORM_BLOCK_BINDING, &blockBinding);
+ QCOMPARE(blockIndex, uniformBlock.m_index);
+ QCOMPARE(blockBinding, uniformBlock.m_binding);
+ }
+
+ void programAttributesAndLocations()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeSamplers);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ QVector<ShaderAttribute> activeAttributes = m_glHelper.programAttributesAndLocations(shaderProgram.programId());
+
+ // THEN
+ QCOMPARE(activeAttributes.size(), 2);
+ std::sort(activeAttributes.begin(), activeAttributes.end(), [] (const ShaderAttribute &a, const ShaderAttribute &b) { return a.m_name < b.m_name; });
+
+ const ShaderAttribute attribute1 = activeAttributes.at(0);
+ QCOMPARE(attribute1.m_name, QStringLiteral("vertexPosition"));
+ QCOMPARE(attribute1.m_size, 1);
+ QCOMPARE(attribute1.m_location, shaderProgram.attributeLocation("vertexPosition"));
+ QCOMPARE(attribute1.m_type, GLenum(GL_FLOAT_VEC3));
+
+ const ShaderAttribute attribute2 = activeAttributes.at(1);
+ QCOMPARE(attribute2.m_name, QStringLiteral("vertexTexCoord"));
+ QCOMPARE(attribute2.m_size, 1);
+ QCOMPARE(attribute2.m_location, shaderProgram.attributeLocation("vertexTexCoord"));
+ QCOMPARE(attribute2.m_type, GLenum(GL_FLOAT_VEC2));
+ }
+
+ void programUniformsAndLocations()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloat);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ QVector<ShaderUniform> activeUniforms = m_glHelper.programUniformsAndLocations(shaderProgram.programId());
+
+ // THEN
+ QCOMPARE(activeUniforms.size(), 4);
+ std::sort(activeUniforms.begin(), activeUniforms.end(), [] (const ShaderUniform &a, const ShaderUniform &b) { return a.m_name < b.m_name; });
+
+ const ShaderUniform uniform1 = activeUniforms.at(0);
+ QCOMPARE(uniform1.m_location, shaderProgram.uniformLocation("multiplier"));
+ QCOMPARE(uniform1.m_offset, -1);
+ QCOMPARE(uniform1.m_blockIndex, -1);
+ QCOMPARE(uniform1.m_arrayStride, -1);
+ QCOMPARE(uniform1.m_matrixStride, -1);
+ QCOMPARE(uniform1.m_size, 1);
+ QCOMPARE(uniform1.m_type, GLenum(GL_FLOAT));
+ QCOMPARE(uniform1.m_name, QStringLiteral("multiplier"));
+
+ const ShaderUniform uniform2 = activeUniforms.at(1);
+ QCOMPARE(uniform2.m_location, shaderProgram.uniformLocation("multiplierVec2"));
+ QCOMPARE(uniform2.m_offset, -1);
+ QCOMPARE(uniform2.m_blockIndex, -1);
+ QCOMPARE(uniform2.m_arrayStride, -1);
+ QCOMPARE(uniform2.m_matrixStride, -1);
+ QCOMPARE(uniform2.m_size, 1);
+ QCOMPARE(uniform2.m_type, GLenum(GL_FLOAT_VEC2));
+ QCOMPARE(uniform2.m_name, QStringLiteral("multiplierVec2"));
+
+ const ShaderUniform uniform3 = activeUniforms.at(2);
+ QCOMPARE(uniform3.m_location, shaderProgram.uniformLocation("multiplierVec3"));
+ QCOMPARE(uniform3.m_offset, -1);
+ QCOMPARE(uniform3.m_blockIndex, -1);
+ QCOMPARE(uniform3.m_arrayStride, -1);
+ QCOMPARE(uniform3.m_matrixStride, -1);
+ QCOMPARE(uniform3.m_size, 1);
+ QCOMPARE(uniform3.m_type, GLenum(GL_FLOAT_VEC3));
+ QCOMPARE(uniform3.m_name, QStringLiteral("multiplierVec3"));
+
+ const ShaderUniform uniform4 = activeUniforms.at(3);
+ QCOMPARE(uniform4.m_location, shaderProgram.uniformLocation("multiplierVec4"));
+ QCOMPARE(uniform4.m_offset, -1);
+ QCOMPARE(uniform4.m_blockIndex, -1);
+ QCOMPARE(uniform4.m_arrayStride, -1);
+ QCOMPARE(uniform4.m_matrixStride, -1);
+ QCOMPARE(uniform4.m_size, 1);
+ QCOMPARE(uniform4.m_type, GLenum(GL_FLOAT_VEC4));
+ QCOMPARE(uniform4.m_name, QStringLiteral("multiplierVec4"));
+ }
+
+ void programShaderStorageBlock()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // Not supported in 3.2
+ }
+
+ void releaseFrameBufferObject()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ GLuint fboId;
+ m_func->glGenFramebuffers(1, &fboId);
+
+ // THEN
+ QVERIFY(fboId != 0);
+
+ // WHEN
+ m_glHelper.releaseFrameBufferObject(fboId);
+
+ // THEN
+ QVERIFY(!m_func->glIsFramebuffer(fboId));
+ }
+
+ void setMSAAEnabled()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ m_func->glDisable(GL_MULTISAMPLE);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_MULTISAMPLE));
+
+ // WHEN
+ m_glHelper.setMSAAEnabled(true);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_MULTISAMPLE));
+
+ // WHEN
+ m_glHelper.setMSAAEnabled(false);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_MULTISAMPLE));
+ }
+
+ void setAlphaCoverageEnabled()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ m_func->glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE));
+
+ // WHEN
+ m_glHelper.setAlphaCoverageEnabled(true);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE));
+
+ // WHEN
+ m_glHelper.setAlphaCoverageEnabled(false);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE));
+ }
+
+ void setClipPlane()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // Deprecated in 3.3 core
+ }
+
+ void setSeamlessCubemap()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ m_func->glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
+ QVERIFY(!m_func->glIsEnabled(GL_TEXTURE_CUBE_MAP_SEAMLESS));
+
+ // WHEN
+ m_glHelper.setSeamlessCubemap(true);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_TEXTURE_CUBE_MAP_SEAMLESS));
+
+ // WHEN
+ m_glHelper.setSeamlessCubemap(false);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_TEXTURE_CUBE_MAP_SEAMLESS));
+ }
+
+ void setVerticesPerPatch()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ m_func->glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_TEXTURE_CUBE_MAP_SEAMLESS));
+
+ // WHEN
+ m_glHelper.setSeamlessCubemap(true);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_TEXTURE_CUBE_MAP_SEAMLESS));
+
+ // WHEN
+ m_glHelper.setSeamlessCubemap(false);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_TEXTURE_CUBE_MAP_SEAMLESS));
+ }
+
+#define SUPPORTS_FEATURE(Feature, IsSupported) \
+ QVERIFY(m_glHelper.supportsFeature(Feature) == IsSupported);
+
+ void supportsFeature()
+ {
+ SUPPORTS_FEATURE(GraphicsHelperInterface::MRT, true);
+ SUPPORTS_FEATURE(GraphicsHelperInterface::UniformBufferObject, true);
+ SUPPORTS_FEATURE(GraphicsHelperInterface::BindableFragmentOutputs, true);
+ SUPPORTS_FEATURE(GraphicsHelperInterface::PrimitiveRestart, true);
+ SUPPORTS_FEATURE(GraphicsHelperInterface::RenderBufferDimensionRetrieval, true);
+ SUPPORTS_FEATURE(GraphicsHelperInterface::TextureDimensionRetrieval, true);
+ SUPPORTS_FEATURE(GraphicsHelperInterface::UniformBufferObject, true);
+ SUPPORTS_FEATURE(GraphicsHelperInterface::ShaderStorageObject, false);
+ SUPPORTS_FEATURE(GraphicsHelperInterface::Compute, false);
+ SUPPORTS_FEATURE(GraphicsHelperInterface::DrawBuffersBlend, false);
+ // Tesselation could be true or false depending on extensions so not tested
+ }
+
+
+#define ADD_UNIFORM_ENTRY(FragShader, Name, Type, ComponentSize, ExpectedRawSize) \
+ QTest::newRow(#FragShader"_"#Type) << FragShader << QStringLiteral(Name) << Type << ComponentSize << ExpectedRawSize;
+
+ void uniformsByteSize_data()
+ {
+ QTest::addColumn<QByteArray>("fragShader");
+ QTest::addColumn<QString>("name");
+ QTest::addColumn<int>("type");
+ QTest::addColumn<int>("componentSize");
+ QTest::addColumn<int>("expectedByteSize");
+
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloat, "multiplier", GL_FLOAT, 1, 4);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloat, "multiplierVec2", GL_FLOAT_VEC2, 1, 4 * 2);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloat, "multiplierVec3",GL_FLOAT_VEC3, 1, 4 * 3);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloat, "multiplierVec4", GL_FLOAT_VEC4, 1, 4 * 4);
+
+ ADD_UNIFORM_ENTRY(fragCodeUniformsInt, "multiplier", GL_INT, 1, 4);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsInt, "multiplierVec2", GL_INT_VEC2, 1, 4 * 2);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsInt, "multiplierVec3", GL_INT_VEC3, 1, 4 * 3);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsInt, "multiplierVec4", GL_INT_VEC4, 1, 4 * 4);
+
+ ADD_UNIFORM_ENTRY(fragCodeUniformsUInt, "multiplier", GL_UNSIGNED_INT, 1, 4);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsUInt, "multiplierVec2", GL_UNSIGNED_INT_VEC2, 1, 4 * 2);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsUInt, "multiplierVec3", GL_UNSIGNED_INT_VEC3, 1, 4 * 3);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsUInt, "multiplierVec4", GL_UNSIGNED_INT_VEC4, 1, 4 * 4);
+
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m2", GL_FLOAT_MAT2, 1, 4 * 2 * 2);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m23", GL_FLOAT_MAT2x3, 1, 4 * 2 * 3);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m32", GL_FLOAT_MAT3x2, 1, 4 * 3 * 2);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m24", GL_FLOAT_MAT2x4, 1, 4 * 2 * 4);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m42", GL_FLOAT_MAT4x2, 1, 4 * 4 * 2);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m3", GL_FLOAT_MAT3, 1, 4 * 3 * 3);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m34", GL_FLOAT_MAT3x4, 1, 4 * 3 * 4);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m43", GL_FLOAT_MAT4x3, 1, 4 * 4 * 3);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m4", GL_FLOAT_MAT4, 1, 4 * 4 * 4);
+
+ ADD_UNIFORM_ENTRY(fragCodeSamplers, "s1", GL_SAMPLER_1D, 1, 4);
+ ADD_UNIFORM_ENTRY(fragCodeSamplers, "s2", GL_SAMPLER_2D, 1, 4);
+ ADD_UNIFORM_ENTRY(fragCodeSamplers, "s2a", GL_SAMPLER_2D_ARRAY, 1, 4);
+ ADD_UNIFORM_ENTRY(fragCodeSamplers, "s3", GL_SAMPLER_3D, 1, 4);
+ ADD_UNIFORM_ENTRY(fragCodeSamplers, "scube", GL_SAMPLER_CUBE, 1, 4);
+ ADD_UNIFORM_ENTRY(fragCodeSamplers, "srect", GL_SAMPLER_2D_RECT, 1, 4);
+ }
+
+ void uniformsByteSize()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QFETCH(QByteArray, fragShader);
+ QFETCH(QString, name);
+ QFETCH(int, type);
+ QFETCH(int, componentSize);
+ QFETCH(int, expectedByteSize);
+
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragShader);
+ QVERIFY(shaderProgram.link());
+
+ GLint location = shaderProgram.uniformLocation(name);
+ // WHEN
+ const QVector<ShaderUniform> activeUniforms = m_glHelper.programUniformsAndLocations(shaderProgram.programId());
+ ShaderUniform matchingUniform;
+ for (const ShaderUniform &u : activeUniforms) {
+ if (u.m_location == location) {
+ matchingUniform = u;
+ break;
+ }
+ }
+
+
+ // THEN
+ QCOMPARE(matchingUniform.m_location, location);
+ QCOMPARE(matchingUniform.m_type, GLuint(type));
+ QCOMPARE(matchingUniform.m_size, componentSize);
+
+ // WHEN
+ const int computedRawByteSize = m_glHelper.uniformByteSize(matchingUniform);
+
+ // THEN
+ QCOMPARE(expectedByteSize, computedRawByteSize);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void useProgram()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeFragOutputs);
+
+ // THEN
+ QVERIFY(shaderProgram.link());
+
+ GLint currentProg = 0;
+ m_func->glGetIntegerv(GL_CURRENT_PROGRAM, &currentProg);
+ QVERIFY(currentProg == 0);
+
+ // WHEN
+ m_glHelper.useProgram(shaderProgram.programId());
+
+ // THEN
+ m_func->glGetIntegerv(GL_CURRENT_PROGRAM, &currentProg);
+ QCOMPARE(GLuint(currentProg), shaderProgram.programId());
+
+ // WHEN
+ m_glHelper.useProgram(0);
+
+ // THEN
+ m_func->glGetIntegerv(GL_CURRENT_PROGRAM, &currentProg);
+ QVERIFY(currentProg == 0);
+ }
+
+ void vertexAttribDivisor()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+ // Not available in 3.2
+ }
+
+ void glUniform1fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloat);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat value = 883.0f;
+ const GLint location = shaderProgram.uniformLocation("multiplier");
+ m_glHelper.glUniform1fv(location, 1, &value);
+
+ // THEN
+ GLfloat setValue = 0.0f;
+ m_func->glGetUniformfv(shaderProgram.programId(), location, &setValue);
+ QCOMPARE(value, setValue);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform2fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloat);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[2] = { 383.0f, 427.0f };
+ const GLint location = shaderProgram.uniformLocation("multiplierVec2");
+ m_glHelper.glUniform2fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[2] = { 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 2; ++i)
+ QCOMPARE(setValues[i], values[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform3fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloat);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[3] = { 572.0f, 1340.0f, 1584.0f };
+ const GLint location = shaderProgram.uniformLocation("multiplierVec3");
+ m_glHelper.glUniform3fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[3] = { 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 3; ++i)
+ QCOMPARE(setValues[i], values[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform4fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloat);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[4] = { 454.0f, 350.0f, 883.0f, 355.0f };
+ const GLint location = shaderProgram.uniformLocation("multiplierVec4");
+ m_glHelper.glUniform4fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 4; ++i)
+ QCOMPARE(setValues[i], values[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform1iv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsInt);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLint value = 883;
+ const GLint location = shaderProgram.uniformLocation("multiplier");
+ m_glHelper.glUniform1iv(location, 1, &value);
+
+ // THEN
+ GLint setValue = 0;
+ m_func->glGetUniformiv(shaderProgram.programId(), location, &setValue);
+ QCOMPARE(value, setValue);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform2iv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsInt);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLint values[2] = { 383, 427 };
+ const GLint location = shaderProgram.uniformLocation("multiplierVec2");
+ m_glHelper.glUniform2iv(location, 1, values);
+
+ // THEN
+ GLint setValues[2] = { 0, 0 };
+ m_func->glGetUniformiv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 2; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform3iv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsInt);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLint values[3] = { 572, 1340, 1584 };
+ const GLint location = shaderProgram.uniformLocation("multiplierVec3");
+ m_glHelper.glUniform3iv(location, 1, values);
+
+ // THEN
+ GLint setValues[3] = { 0, 0, 0 };
+ m_func->glGetUniformiv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 3; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform4iv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsInt);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLint values[4] = { 454, 350, 883, 355 };
+ const GLint location = shaderProgram.uniformLocation("multiplierVec4");
+ m_glHelper.glUniform4iv(location, 1, values);
+
+ // THEN
+ GLint setValues[4] = { 0, 0, 0, 0 };
+ m_func->glGetUniformiv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 4; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform1uiv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsUInt);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLuint value = 883U;
+ const GLint location = shaderProgram.uniformLocation("multiplier");
+ m_glHelper.glUniform1uiv(location, 1, &value);
+
+ // THEN
+ GLuint setValue = 0U;
+ m_func->glGetUniformuiv(shaderProgram.programId(), location, &setValue);
+ QCOMPARE(value, setValue);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform2uiv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsUInt);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLuint values[2] = { 383U, 427U };
+ const GLint location = shaderProgram.uniformLocation("multiplierVec2");
+ m_glHelper.glUniform2uiv(location, 1, values);
+
+ // THEN
+ GLuint setValues[2] = { 0U, 0U };
+ m_func->glGetUniformuiv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 2; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform3uiv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsUInt);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLuint values[3] = { 572U, 1340U, 1584U };
+ const GLint location = shaderProgram.uniformLocation("multiplierVec3");
+ m_glHelper.glUniform3uiv(location, 1, values);
+
+ // THEN
+ GLuint setValues[3] = { 0U, 0U, 0U };
+ m_func->glGetUniformuiv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 3; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform4uiv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsUInt);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLuint values[4] = { 454U, 350U, 883U, 355U };
+ const GLint location = shaderProgram.uniformLocation("multiplierVec4");
+ m_glHelper.glUniform4uiv(location, 1, values);
+
+ // THEN
+ GLuint setValues[4] = { 0U, 0U, 0U, 0U };
+ m_func->glGetUniformuiv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 4; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix2fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[4] = { 454.0f, 350.0f, 883.0f, 355.0f };
+ const GLint location = shaderProgram.uniformLocation("m2");
+ m_glHelper.glUniformMatrix2fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 4; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix3fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[9] = { 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f, 1200.0f, 427.0f, 396.0f };
+ const GLint location = shaderProgram.uniformLocation("m3");
+ m_glHelper.glUniformMatrix3fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[9] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 9; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix4fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[16] = { 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f, 1200.0f, 427.0f, 396.0f, 1603.0f, 55.0f, 5.7, 383.0f, 6.2f, 5.3f, 327.0f };
+ const GLint location = shaderProgram.uniformLocation("m4");
+ m_glHelper.glUniformMatrix4fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[16] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 16; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix2x3fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[6] = { 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f};
+ const GLint location = shaderProgram.uniformLocation("m23");
+ m_glHelper.glUniformMatrix2x3fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[6] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 6; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix3x2fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[6] = { 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f};
+ const GLint location = shaderProgram.uniformLocation("m32");
+ m_glHelper.glUniformMatrix3x2fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[6] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 6; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix2x4fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[8] = { 383.0f, 427.0f, 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f};
+ const GLint location = shaderProgram.uniformLocation("m24");
+ m_glHelper.glUniformMatrix2x4fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[8] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 8; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix4x2fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[8] = { 383.0f, 427.0f, 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f};
+ const GLint location = shaderProgram.uniformLocation("m42");
+ m_glHelper.glUniformMatrix4x2fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[8] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 8; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix3x4fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[12] = { 55.0f, 5.7, 383.0f, 6.2f, 5.3f, 383.0f, 427.0f, 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f};
+ const GLint location = shaderProgram.uniformLocation("m34");
+ m_glHelper.glUniformMatrix3x4fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[12] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 12; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix4x3fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[12] = { 55.0f, 5.7, 383.0f, 6.2f, 383.0f, 427.0f, 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f};
+ const GLint location = shaderProgram.uniformLocation("m43");
+ m_glHelper.glUniformMatrix4x3fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[12] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 12; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+#define ADD_GL_TYPE_ENTRY(Type, Expected) \
+ QTest::newRow(#Type) << Type << Expected;
+
+ void uniformTypeFromGLType_data()
+ {
+ QTest::addColumn<int>("glType");
+ QTest::addColumn<UniformType>("expected");
+
+ ADD_GL_TYPE_ENTRY(GL_FLOAT, UniformType::Float);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC2, UniformType::Vec2);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC3, UniformType::Vec3);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC3, UniformType::Vec3);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC2, UniformType::Vec2);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC3, UniformType::Vec3);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC3, UniformType::Vec3);
+ ADD_GL_TYPE_ENTRY(GL_INT, UniformType::Int);
+ ADD_GL_TYPE_ENTRY(GL_INT_VEC2, UniformType::IVec2);
+ ADD_GL_TYPE_ENTRY(GL_INT_VEC3, UniformType::IVec3);
+ ADD_GL_TYPE_ENTRY(GL_INT_VEC4, UniformType::IVec4);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT, UniformType::UInt);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_VEC2, UniformType::UIVec2);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_VEC3, UniformType::UIVec3);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_VEC4, UniformType::UIVec4);
+ ADD_GL_TYPE_ENTRY(GL_BOOL, UniformType::Bool);
+ ADD_GL_TYPE_ENTRY(GL_BOOL_VEC2, UniformType::BVec2);
+ ADD_GL_TYPE_ENTRY(GL_BOOL_VEC3, UniformType::BVec3);
+ ADD_GL_TYPE_ENTRY(GL_BOOL_VEC4, UniformType::BVec4);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT2, UniformType::Mat2);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT3, UniformType::Mat3);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT4, UniformType::Mat4);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT2x3, UniformType::Mat2x3);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT2x4, UniformType::Mat2x4);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT3x2, UniformType::Mat3x2);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT4x2, UniformType::Mat4x2);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT4x3, UniformType::Mat4x3);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT3x4, UniformType::Mat3x4);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_1D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_1D_ARRAY, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_1D_SHADOW, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_2D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_2D_ARRAY, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_2D_RECT, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_2D_MULTISAMPLE, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_2D_MULTISAMPLE_ARRAY, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_2D_SHADOW, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_2D_ARRAY_SHADOW, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_3D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_CUBE, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_CUBE_SHADOW, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_BUFFER, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_INT_SAMPLER_1D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_INT_SAMPLER_2D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_INT_SAMPLER_3D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_INT_SAMPLER_BUFFER, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_INT_SAMPLER_2D_ARRAY, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_INT_SAMPLER_2D_MULTISAMPLE, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_INT_SAMPLER_CUBE, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_SAMPLER_1D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_SAMPLER_2D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_SAMPLER_3D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_SAMPLER_BUFFER, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_SAMPLER_2D_ARRAY, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_SAMPLER_CUBE, UniformType::Sampler);
+ }
+
+ void uniformTypeFromGLType()
+ {
+ // GIVEN
+ QFETCH(int, glType);
+ QFETCH(UniformType, expected);
+
+ // WHEN
+ UniformType computed = m_glHelper.uniformTypeFromGLType(glType);
+
+ // THEN
+ QCOMPARE(computed, expected);
+ }
+
+private:
+ QScopedPointer<QWindow> m_window;
+ QOpenGLContext m_glContext;
+ GraphicsHelperGL3_2 m_glHelper;
+ QOpenGLFunctions_3_2_Core *m_func = nullptr;
+ bool m_initializationSuccessful = false;
+};
+
+#endif
+
+QT_BEGIN_NAMESPACE
+QTEST_ADD_GPU_BLACKLIST_SUPPORT_DEFS
+QT_END_NAMESPACE
+
+int main(int argc, char *argv[])
+{
+#ifdef TEST_SHOULD_BE_PERFORMED
+ QGuiApplication app(argc, argv);
+ app.setAttribute(Qt::AA_Use96Dpi, true);
+ QTEST_ADD_GPU_BLACKLIST_SUPPORT
+ tst_GraphicsHelperGL3_2 tc;
+ QTEST_SET_MAIN_SOURCE_PATH
+ return QTest::qExec(&tc, argc, argv);
+#endif
+ return 0;
+}
+
+#ifdef TEST_SHOULD_BE_PERFORMED
+#include "tst_graphicshelpergl3_2.moc"
+#endif
diff --git a/tests/auto/render/graphicshelpergl3_3/graphicshelpergl3_3.pro b/tests/auto/render/graphicshelpergl3_3/graphicshelpergl3_3.pro
new file mode 100644
index 000000000..36bda15b2
--- /dev/null
+++ b/tests/auto/render/graphicshelpergl3_3/graphicshelpergl3_3.pro
@@ -0,0 +1,13 @@
+TEMPLATE = app
+
+TARGET = tst_graphicshelpergl3_3
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += \
+ tst_graphicshelpergl3_3.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/graphicshelpergl3_3/tst_graphicshelpergl3_3.cpp b/tests/auto/render/graphicshelpergl3_3/tst_graphicshelpergl3_3.cpp
new file mode 100644
index 000000000..bec5cbc1a
--- /dev/null
+++ b/tests/auto/render/graphicshelpergl3_3/tst_graphicshelpergl3_3.cpp
@@ -0,0 +1,1973 @@
+/****************************************************************************
+**
+** 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:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QTest>
+#include <Qt3DRender/qrendertargetoutput.h>
+#include <Qt3DRender/private/uniform_p.h>
+#include <Qt3DRender/private/graphicshelpergl3_3_p.h>
+#include <Qt3DRender/private/attachmentpack_p.h>
+#include <QOpenGLFunctions_3_3_Core>
+#include <QOpenGLShaderProgram>
+
+#if !defined(QT_OPENGL_ES_2) && defined(QT_OPENGL_3_2)
+
+#define TEST_SHOULD_BE_PERFORMED 1
+
+using namespace Qt3DRender;
+using namespace Qt3DRender::Render;
+
+namespace {
+
+const QByteArray vertCode = QByteArrayLiteral(
+ "#version 330 core\n" \
+ "in vec3 vertexPosition;\n" \
+ "in vec2 vertexTexCoord;\n" \
+ "out vec2 texCoord;\n" \
+ "void main()\n" \
+ "{\n" \
+ " texCoord = vertexTexCoord;\n" \
+ " gl_Position = vec4(vertexPosition, 1.0);\n" \
+ "}\n");
+
+const QByteArray vertCodeUniformBuffer = QByteArrayLiteral(
+ "#version 330 core\n" \
+ "in vec3 vertexPosition;\n" \
+ "in vec2 vertexTexCoord;\n" \
+ "in int vertexColorIndex;\n" \
+ "out vec2 texCoord;\n" \
+ "flat out int colorIndex;\n" \
+ "void main()\n" \
+ "{\n" \
+ " texCoord = vertexTexCoord;\n" \
+ " colorIndex = vertexColorIndex;\n" \
+ " gl_Position = vec4(vertexPosition, 1.0);\n" \
+ "}\n");
+
+const QByteArray fragCodeFragOutputs = QByteArrayLiteral(
+ "#version 330 core\n" \
+ "out vec4 color;\n" \
+ "out vec2 temp;\n" \
+ "void main()\n" \
+ "{\n" \
+ " color = vec4(1.0, 0.0, 0.0, 1.0);\n" \
+ " temp = vec2(1.0, 0.3);\n" \
+ "}\n");
+
+const QByteArray fragCodeUniformsFloat = QByteArrayLiteral(
+ "#version 330 core\n" \
+ "out vec4 color;\n" \
+ "uniform float multiplier;\n" \
+ "uniform vec2 multiplierVec2;\n" \
+ "uniform vec3 multiplierVec3;\n" \
+ "uniform vec4 multiplierVec4;\n" \
+ "void main()\n" \
+ "{\n" \
+ " vec4 randomMult = multiplierVec4 + vec4(multiplierVec3, 0.0) + vec4(multiplierVec2, 0.0, 0.0);\n" \
+ " color = vec4(1.0, 0.0, 0.0, 1.0) * randomMult * multiplier;\n" \
+ "}\n");
+
+const QByteArray fragCodeUniformsInt = QByteArrayLiteral(
+ "#version 330 core\n" \
+ "out ivec4 color;\n" \
+ "uniform int multiplier;\n" \
+ "uniform ivec2 multiplierVec2;\n" \
+ "uniform ivec3 multiplierVec3;\n" \
+ "uniform ivec4 multiplierVec4;\n" \
+ "void main()\n" \
+ "{\n" \
+ " ivec4 randomMult = multiplierVec4 + ivec4(multiplierVec3, 0) + ivec4(multiplierVec2, 0, 0);\n" \
+ " color = ivec4(1, 0, 0, 1) * randomMult * multiplier;\n" \
+ "}\n");
+
+const QByteArray fragCodeUniformsUInt = QByteArrayLiteral(
+ "#version 330 core\n" \
+ "out uvec4 color;\n" \
+ "uniform uint multiplier;\n" \
+ "uniform uvec2 multiplierVec2;\n" \
+ "uniform uvec3 multiplierVec3;\n" \
+ "uniform uvec4 multiplierVec4;\n" \
+ "void main()\n" \
+ "{\n" \
+ " uvec4 randomMult = multiplierVec4 + uvec4(multiplierVec3, 0) + uvec4(multiplierVec2, 0, 0);\n" \
+ " color = uvec4(1, 0, 0, 1) * randomMult * multiplier;\n" \
+ "}\n");
+
+const QByteArray fragCodeUniformsFloatMatrices = QByteArrayLiteral(
+ "#version 330 core\n" \
+ "out vec4 color;\n" \
+ "uniform mat2 m2;\n" \
+ "uniform mat2x3 m23;\n" \
+ "uniform mat3x2 m32;\n" \
+ "uniform mat2x4 m24;\n" \
+ "uniform mat4x2 m42;\n" \
+ "uniform mat3 m3;\n" \
+ "uniform mat3x4 m34;\n" \
+ "uniform mat4x3 m43;\n" \
+ "uniform mat4 m4;\n" \
+ "void main()\n" \
+ "{\n" \
+ " float lengthSum = m2[0][0] + m23[0][0] + m32[0][0] + m24[0][0] + m42[0][0] + m3[0][0] + m34[0][0] + m43[0][0] + m4[0][0];\n" \
+ " color = vec4(1, 0, 0, 1) * lengthSum;\n" \
+ "}\n");
+
+const QByteArray fragCodeUniformBuffer = QByteArrayLiteral(
+ "#version 330 core\n" \
+ "out vec4 color;\n" \
+ "flat in int colorIndex;\n" \
+ "uniform ColorArray\n" \
+ "{\n" \
+ " vec4 colors[256];\n" \
+ "};\n" \
+ "void main()\n" \
+ "{\n" \
+ " color = colors[colorIndex];\n" \
+ "}\n");
+
+const QByteArray fragCodeSamplers = QByteArrayLiteral(
+ "#version 330 core\n" \
+ "in vec2 texCoord;\n" \
+ "out vec4 color;\n" \
+ "uniform sampler1D s1;\n" \
+ "uniform sampler2D s2;\n" \
+ "uniform sampler2DArray s2a;\n" \
+ "uniform sampler3D s3;\n" \
+ "uniform samplerCube scube;\n" \
+ "uniform sampler2DRect srect;\n" \
+ "void main()\n" \
+ "{\n" \
+ " color = vec4(1, 0, 0, 1) *" \
+ " texture(s1, texCoord.x) *" \
+ " texture(s2, texCoord) *" \
+ " texture(s2a, vec3(texCoord, 0.0)) *" \
+ " texture(s3, vec3(texCoord, 0.0)) *" \
+ " texture(scube, vec3(texCoord, 0)) *" \
+ " texture(srect, texCoord);\n" \
+ "}\n");
+
+} // anonymous
+
+class tst_GraphicsHelperGL3_3 : public QObject
+{
+ Q_OBJECT
+private Q_SLOTS:
+
+ void init()
+ {
+ m_window.reset(new QWindow);
+ m_window->setSurfaceType(QWindow::OpenGLSurface);
+ m_window->setGeometry(0, 0, 10, 10);
+
+ QSurfaceFormat format;
+ format.setVersion(3, 3);
+ format.setProfile(QSurfaceFormat::CoreProfile);
+ format.setDepthBufferSize(24);
+ format.setSamples(4);
+ format.setStencilBufferSize(8);
+ m_window->setFormat(format);
+ m_glContext.setFormat(format);
+
+ m_window->create();
+
+ if (!m_glContext.create()) {
+ qWarning() << "Failed to create OpenGL context";
+ return;
+ }
+
+ if (!m_glContext.makeCurrent(m_window.data())) {
+ qWarning() << "Failed to maed OpenGL context current";
+ return;
+ }
+
+ if ((m_func = m_glContext.versionFunctions<QOpenGLFunctions_3_3_Core>()) != nullptr) {
+ m_glHelper.initializeHelper(&m_glContext, m_func);
+ m_initializationSuccessful = true;
+ }
+ }
+
+ void alphaTest()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+ // Deprecated
+ }
+
+ void bindBufferBase()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ GLuint bufferId = 0;
+ // WHEN
+ m_func->glGenBuffers(1, &bufferId);
+ // THEN
+ QVERIFY(bufferId != 0);
+
+
+ // WHEN
+ m_func->glBindBuffer(GL_UNIFORM_BUFFER, bufferId);
+ m_glHelper.bindBufferBase(GL_UNIFORM_BUFFER, 2, bufferId);
+ // THEN
+ const GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ GLint boundToPointBufferId = 0;
+ m_func->glGetIntegeri_v(GL_UNIFORM_BUFFER_BINDING, 2, &boundToPointBufferId);
+ QVERIFY(boundToPointBufferId == GLint(bufferId));
+
+ // Restore to sane state
+ m_func->glBindBuffer(GL_UNIFORM_BUFFER, 0);
+ m_func->glDeleteBuffers(1, &bufferId);
+ }
+
+ void bindFragDataLocation()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeFragOutputs);
+
+ // WHEN
+ QHash<QString, int> fragLocations;
+ fragLocations.insert(QStringLiteral("temp"), 2);
+ fragLocations.insert(QStringLiteral("color"), 1);
+ m_glHelper.bindFragDataLocation(shaderProgram.programId(), fragLocations);
+
+ // THEN
+ QVERIFY(shaderProgram.link());
+ const GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ const GLint tempLocation = m_func->glGetFragDataLocation(shaderProgram.programId(), "temp");
+ const GLint colorLocation = m_func->glGetFragDataLocation(shaderProgram.programId(), "color");
+ QCOMPARE(tempLocation, 2);
+ QCOMPARE(colorLocation, 1);
+ }
+
+ void bindFrameBufferAttachment()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ GLuint fboId;
+ m_func->glGenFramebuffers(1, &fboId);
+
+ Attachment attachment;
+ attachment.m_point = QRenderTargetOutput::Color0;
+
+ GLint maxAttachmentsCount = 0;
+ m_func->glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxAttachmentsCount);
+
+ // THEN
+ QVERIFY(fboId != 0);
+ QVERIFY(maxAttachmentsCount >= 3);
+
+ // WHEN
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId);
+
+ QOpenGLTexture texture(QOpenGLTexture::Target2D);
+ texture.setSize(512, 512);
+ texture.setFormat(QOpenGLTexture::RGBA8U);
+ texture.setMinificationFilter(QOpenGLTexture::Linear);
+ texture.setMagnificationFilter(QOpenGLTexture::Linear);
+ texture.setWrapMode(QOpenGLTexture::ClampToEdge);
+ if (!texture.create())
+ qWarning() << "Texture creation failed";
+ texture.allocateStorage();
+ QVERIFY(texture.isStorageAllocated());
+ GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ m_glHelper.bindFrameBufferAttachment(&texture, attachment);
+
+ // THEN
+ GLenum status = m_func->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ QCOMPARE(int(status), GL_FRAMEBUFFER_COMPLETE);
+
+ error = m_func->glGetError();
+ QVERIFY(error == 0);
+ GLint textureAttachmentId = 0;
+ m_func->glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
+ &textureAttachmentId);
+ QCOMPARE(GLuint(textureAttachmentId), texture.textureId());
+
+ // Restore state
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ m_func->glDeleteFramebuffers(1, &fboId);
+ }
+
+ void bindFrameBufferObject()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ GLuint fboId;
+ m_func->glGenFramebuffers(1, &fboId);
+
+ // THEN
+ QVERIFY(fboId != 0);
+
+ // WHEN
+ m_glHelper.bindFrameBufferObject(fboId);
+
+ // THEN
+ const GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ GLint boundindFBOId = 0;
+ m_func->glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &boundindFBOId);
+ QVERIFY(GLuint(boundindFBOId) == fboId);
+
+ // Cleanup
+ m_func->glDeleteFramebuffers(1, &fboId);
+ }
+
+ void bindShaderStorageBlock()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+ // Not supported in OpenGL 3.3
+ }
+
+ void bindUniformBlock()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCodeUniformBuffer);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformBuffer);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ GLint index = m_func->glGetUniformBlockIndex(shaderProgram.programId(), "ColorArray");
+ m_glHelper.bindUniformBlock(shaderProgram.programId(), index, 1);
+
+ // THEN
+ const GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ }
+
+ void blendEquation()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ GLint equation = 0;
+ m_func->glGetIntegerv(GL_BLEND_EQUATION_RGB, &equation);
+ QCOMPARE(equation, GL_FUNC_ADD);
+
+ // WHEN
+ m_glHelper.blendEquation(GL_FUNC_REVERSE_SUBTRACT);
+
+ // THEN
+ m_func->glGetIntegerv(GL_BLEND_EQUATION_RGB, &equation);
+ QCOMPARE(equation, GL_FUNC_REVERSE_SUBTRACT);
+ }
+
+ void blendFunci()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+ // Not supported by OpenGL 3.3
+ }
+
+ void blendFuncSeparatei()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // Not supported by OpenGL 3.3
+ }
+
+ void boundFrameBufferObject()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ GLuint fboId;
+ m_func->glGenFramebuffers(1, &fboId);
+
+ // WHEN
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId);
+
+ // THEN
+ GLint boundBuffer = 0;
+ m_func->glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &boundBuffer);
+ QCOMPARE(GLuint(boundBuffer), fboId);
+
+ // THEN
+ QCOMPARE(m_glHelper.boundFrameBufferObject(), fboId);
+
+ // Reset state
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ m_func->glDeleteFramebuffers(1, &fboId);
+ }
+
+ void checkFrameBufferComplete()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+ // GIVEN
+ GLuint fboId;
+ m_func->glGenFramebuffers(1, &fboId);
+
+ Attachment attachment;
+ attachment.m_point = QRenderTargetOutput::Color0;
+
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId);
+
+ QOpenGLTexture texture(QOpenGLTexture::Target2D);
+ texture.setSize(512, 512);
+ texture.setFormat(QOpenGLTexture::RGBA8U);
+ texture.setMinificationFilter(QOpenGLTexture::Linear);
+ texture.setMagnificationFilter(QOpenGLTexture::Linear);
+ texture.create();
+ texture.allocateStorage();
+ m_glHelper.bindFrameBufferAttachment(&texture, attachment);
+
+ // THEN
+ GLenum status = m_func->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ QVERIFY(status == GL_FRAMEBUFFER_COMPLETE);
+
+ QVERIFY(m_glHelper.checkFrameBufferComplete());
+
+ // Restore
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ m_func->glDeleteFramebuffers(1, &fboId);
+ }
+
+ void clearBufferf()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ // GIVEN
+ GLuint fboId;
+ m_func->glGenFramebuffers(1, &fboId);
+
+ // THEN
+ QVERIFY(fboId != 0);
+
+ // WHEN
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId);
+ // Create 4 attachments
+ QOpenGLTexture *textures[4];
+ for (int i = 0; i < 4; ++i) {
+ Attachment attachment;
+ attachment.m_point = static_cast<QRenderTargetOutput::AttachmentPoint>(i);
+
+ QOpenGLTexture *texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
+ textures[i] = texture;
+ texture->setSize(512, 512);
+ texture->setFormat(QOpenGLTexture::RGBA32F);
+ texture->setMinificationFilter(QOpenGLTexture::Linear);
+ texture->setMagnificationFilter(QOpenGLTexture::Linear);
+ texture->setWrapMode(QOpenGLTexture::ClampToEdge);
+ if (!texture->create())
+ qWarning() << "Texture creation failed";
+ texture->allocateStorage();
+ QVERIFY(texture->isStorageAllocated());
+ GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ m_glHelper.bindFrameBufferAttachment(texture, attachment);
+ }
+
+ GLenum status = m_func->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ QVERIFY(status == GL_FRAMEBUFFER_COMPLETE);
+
+ // Set Draw buffers
+ GLenum clearBufferEnum = GL_COLOR_ATTACHMENT3;
+ m_func->glDrawBuffers(1, &clearBufferEnum);
+
+ const GLint bufferIndex = 0; // index of the element in the draw buffers
+ GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+
+ // WHEN
+ const QVector4D clearValue1 = QVector4D(0.5f, 0.2f, 0.4f, 0.8f);
+ m_func->glClearBufferfv(GL_COLOR, bufferIndex, reinterpret_cast<const float *>(&clearValue1));
+ error = m_func->glGetError();
+ QVERIFY(error == 0);
+
+ // THEN
+ QVector<QVector4D> colors(512 * 512);
+ textures[3]->bind();
+ m_func->glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, colors.data());
+ textures[3]->release();
+ for (const QVector4D c : colors)
+ QVERIFY(c == clearValue1);
+
+
+ // WHEN
+ const QVector4D clearValue2 = QVector4D(0.4f, 0.5f, 0.4f, 1.0f);
+ m_glHelper.clearBufferf(bufferIndex, clearValue2);
+
+ // THEN
+ textures[3]->bind();
+ m_func->glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, colors.data());
+ textures[3]->release();
+ for (const QVector4D c : colors)
+ QVERIFY(c == clearValue2);
+
+ // Restore
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ m_func->glDeleteFramebuffers(1, &fboId);
+ for (int i = 0; i < 4; ++i)
+ delete textures[i];
+ }
+
+ void createFrameBufferObject()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // WHEN
+ const GLuint fboId = m_glHelper.createFrameBufferObject();
+
+ // THEN
+ QVERIFY(fboId != 0);
+
+ // Restore
+ m_func->glDeleteFramebuffers(1, &fboId);
+ }
+
+ void depthMask()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ GLboolean depthWritingEnabled = false;
+ m_func->glGetBooleanv(GL_DEPTH_WRITEMASK, &depthWritingEnabled);
+
+ // THEN
+ QVERIFY(depthWritingEnabled);
+
+ // WHEN
+ m_glHelper.depthMask(GL_FALSE);
+
+ // THEN
+ m_func->glGetBooleanv(GL_DEPTH_WRITEMASK, &depthWritingEnabled);
+ QVERIFY(!depthWritingEnabled);
+
+ // WHEN
+ m_glHelper.depthMask(GL_TRUE);
+
+ // THEN
+ m_func->glGetBooleanv(GL_DEPTH_WRITEMASK, &depthWritingEnabled);
+ QVERIFY(depthWritingEnabled);
+ }
+
+ void depthTest()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ m_func->glDisable(GL_DEPTH_TEST);
+ m_func->glDepthFunc(GL_LESS);
+
+ // WHEN
+ m_glHelper.depthTest(GL_LEQUAL);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_DEPTH_TEST));
+ GLint depthMode = 0;
+ m_func->glGetIntegerv(GL_DEPTH_FUNC, &depthMode);
+ QCOMPARE(depthMode, GL_LEQUAL);
+
+ // WHEN
+ m_glHelper.depthTest(GL_LESS);
+ QVERIFY(m_func->glIsEnabled(GL_DEPTH_TEST));
+ m_func->glGetIntegerv(GL_DEPTH_FUNC, &depthMode);
+ QCOMPARE(depthMode, GL_LESS);
+ }
+
+ void disableClipPlane()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ m_func->glEnable(GL_CLIP_DISTANCE0 + 5);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_CLIP_DISTANCE0 + 5));
+
+ // WHEN
+ m_glHelper.disableClipPlane(5);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_CLIP_DISTANCE0 + 5));
+ }
+
+ void disablei()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ m_func->glEnablei(GL_BLEND, 2);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabledi(GL_BLEND, 2));
+
+ // WHEN
+ m_glHelper.disablei(GL_BLEND, 2);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabledi(GL_BLEND, 2));
+ }
+
+ void disablePrimitiveRestart()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ m_func->glEnable(GL_PRIMITIVE_RESTART);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_PRIMITIVE_RESTART));
+
+ // WHEN
+ m_glHelper.disablePrimitiveRestart();
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_PRIMITIVE_RESTART));
+ }
+
+ void drawBuffers()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ GLuint fboId;
+ m_func->glGenFramebuffers(1, &fboId);
+
+ // THEN
+ QVERIFY(fboId != 0);
+
+ // WHEN
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId);
+ QOpenGLTexture *textures[4];
+
+ // Create 4 attachments
+ for (int i = 0; i < 4; ++i) {
+ Attachment attachment;
+ attachment.m_point = static_cast<QRenderTargetOutput::AttachmentPoint>(i);
+
+ QOpenGLTexture *texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
+ textures[i] = texture;
+ texture->setSize(512, 512);
+ texture->setFormat(QOpenGLTexture::RGBA32F);
+ texture->setMinificationFilter(QOpenGLTexture::Linear);
+ texture->setMagnificationFilter(QOpenGLTexture::Linear);
+ texture->setWrapMode(QOpenGLTexture::ClampToEdge);
+ if (!texture->create())
+ qWarning() << "Texture creation failed";
+ texture->allocateStorage();
+ QVERIFY(texture->isStorageAllocated());
+ GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ m_glHelper.bindFrameBufferAttachment(texture, attachment);
+ }
+ // THEN
+ GLenum status = m_func->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ QVERIFY(status == GL_FRAMEBUFFER_COMPLETE);
+
+ // WHEN
+ GLenum bufferEnum = GL_COLOR_ATTACHMENT4;
+ m_func->glDrawBuffers(1, &bufferEnum);
+
+ // THEN
+ GLint enumValue = -1;
+ m_func->glGetIntegerv(GL_DRAW_BUFFER0, &enumValue);
+ QCOMPARE(enumValue, GL_COLOR_ATTACHMENT4);
+
+ // WHEN
+ GLint newBufferEnum = 2;
+ m_glHelper.drawBuffers(1, &newBufferEnum);
+
+ // THEN
+ m_func->glGetIntegerv(GL_DRAW_BUFFER0, &enumValue);
+ QCOMPARE(enumValue, GL_COLOR_ATTACHMENT0 + newBufferEnum);
+
+ // WHEN
+ newBufferEnum = 0;
+ m_glHelper.drawBuffers(1, &newBufferEnum);
+
+ // THEN
+ m_func->glGetIntegerv(GL_DRAW_BUFFER0, &enumValue);
+ QCOMPARE(enumValue, GL_COLOR_ATTACHMENT0 + newBufferEnum);
+
+ // Restore
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ m_func->glDeleteFramebuffers(1, &fboId);
+ for (int i = 0; i < 4; ++i)
+ delete textures[i];
+ }
+
+ void enableClipPlane()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ m_func->glDisable(GL_CLIP_DISTANCE0 + 4);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_CLIP_DISTANCE0 + 4));
+
+ // WHEN
+ m_glHelper.enableClipPlane(4);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_CLIP_DISTANCE0 + 4));
+ }
+
+ void enablei()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ m_func->glDisablei(GL_BLEND, 4);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabledi(GL_BLEND, 4));
+
+ // WHEN
+ m_glHelper.enablei(GL_BLEND, 4);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabledi(GL_BLEND, 4));
+ }
+
+ void enablePrimitiveRestart()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ m_func->glDisable(GL_PRIMITIVE_RESTART);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_PRIMITIVE_RESTART));
+
+ // WHEN
+ m_glHelper.enablePrimitiveRestart(883);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_PRIMITIVE_RESTART));
+ GLint restartIndex = 0;
+ m_func->glGetIntegerv(GL_PRIMITIVE_RESTART_INDEX, &restartIndex);
+ QCOMPARE(restartIndex, 883);
+
+ // Restore
+ m_func->glDisable(GL_PRIMITIVE_RESTART);
+ }
+
+ void frontFace()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ m_func->glFrontFace(GL_CW);
+
+ // THEN
+ GLint face = 0;
+ m_func->glGetIntegerv(GL_FRONT_FACE, &face);
+ QCOMPARE(face, GL_CW);
+
+ // WHEN
+ m_glHelper.frontFace(GL_CCW);
+
+ // THEN
+ m_func->glGetIntegerv(GL_FRONT_FACE, &face);
+ QCOMPARE(face, GL_CCW);
+ }
+
+ void getRenderBufferDimensions()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ GLuint renderBufferId = 0;
+ m_func->glGenRenderbuffers(1, &renderBufferId);
+ QVERIFY(renderBufferId != 0);
+
+ // WHEN
+ m_func->glBindRenderbuffer(GL_RENDERBUFFER, renderBufferId);
+ m_func->glRenderbufferStorage(GL_RENDERBUFFER, GL_SRGB8_ALPHA8, 512, 512);
+ m_func->glBindRenderbuffer(GL_RENDERBUFFER, 0);
+ const QSize dimensions = m_glHelper.getRenderBufferDimensions(renderBufferId);
+
+ // THEN
+ QCOMPARE(dimensions, QSize(512, 512));
+
+ // Restore
+ m_func->glDeleteRenderbuffers(1, &renderBufferId);
+ }
+
+ void getTextureDimensions()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLTexture texture(QOpenGLTexture::Target2D);
+ texture.setSize(512, 512);
+ texture.setFormat(QOpenGLTexture::RGBA8U);
+ texture.setMinificationFilter(QOpenGLTexture::Linear);
+ texture.setMagnificationFilter(QOpenGLTexture::Linear);
+ texture.create();
+ texture.allocateStorage();
+
+ // WHEN
+ const QSize dimensions = m_glHelper.getTextureDimensions(texture.textureId(), GL_TEXTURE_2D);
+
+ // THEN
+ QCOMPARE(dimensions, QSize(512, 512));
+ }
+
+ void pointSize()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ m_func->glEnable(GL_PROGRAM_POINT_SIZE);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_PROGRAM_POINT_SIZE));
+ GLfloat size = 0;
+ m_func->glGetFloatv(GL_POINT_SIZE, &size);
+ QCOMPARE(size, 1.0f);
+
+ // WHEN
+ m_glHelper.pointSize(false, 0.5f);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_PROGRAM_POINT_SIZE));
+ m_func->glGetFloatv(GL_POINT_SIZE, &size);
+ QCOMPARE(size, 0.5f);
+ }
+
+ void maxClipPlaneCount()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ GLint maxCount = -1;
+ m_func->glGetIntegerv(GL_MAX_CLIP_PLANES, &maxCount);
+
+ // THEN
+ QCOMPARE(maxCount, m_glHelper.maxClipPlaneCount());
+ }
+
+ void programUniformBlock()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCodeUniformBuffer);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformBuffer);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ const QVector<ShaderUniformBlock> activeUniformBlocks = m_glHelper.programUniformBlocks(shaderProgram.programId());
+
+ // THEN
+ QCOMPARE(activeUniformBlocks.size(), 1);
+ const ShaderUniformBlock uniformBlock = activeUniformBlocks.first();
+
+ QCOMPARE(uniformBlock.m_activeUniformsCount, 1);
+ QCOMPARE(uniformBlock.m_name, QStringLiteral("ColorArray"));
+
+ GLint blockIndex = m_func->glGetUniformBlockIndex(shaderProgram.programId(), "ColorArray");
+ GLint blockBinding = -1;
+ m_func->glGetActiveUniformBlockiv(shaderProgram.programId(), blockIndex, GL_UNIFORM_BLOCK_BINDING, &blockBinding);
+ QCOMPARE(blockIndex, uniformBlock.m_index);
+ QCOMPARE(blockBinding, uniformBlock.m_binding);
+ }
+
+ void programAttributesAndLocations()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeSamplers);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ QVector<ShaderAttribute> activeAttributes = m_glHelper.programAttributesAndLocations(shaderProgram.programId());
+
+ // THEN
+ QCOMPARE(activeAttributes.size(), 2);
+ std::sort(activeAttributes.begin(), activeAttributes.end(), [] (const ShaderAttribute &a, const ShaderAttribute &b) { return a.m_name < b.m_name; });
+
+ const ShaderAttribute attribute1 = activeAttributes.at(0);
+ QCOMPARE(attribute1.m_name, QStringLiteral("vertexPosition"));
+ QCOMPARE(attribute1.m_size, 1);
+ QCOMPARE(attribute1.m_location, shaderProgram.attributeLocation("vertexPosition"));
+ QCOMPARE(attribute1.m_type, GLenum(GL_FLOAT_VEC3));
+
+ const ShaderAttribute attribute2 = activeAttributes.at(1);
+ QCOMPARE(attribute2.m_name, QStringLiteral("vertexTexCoord"));
+ QCOMPARE(attribute2.m_size, 1);
+ QCOMPARE(attribute2.m_location, shaderProgram.attributeLocation("vertexTexCoord"));
+ QCOMPARE(attribute2.m_type, GLenum(GL_FLOAT_VEC2));
+ }
+
+ void programUniformsAndLocations()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloat);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ QVector<ShaderUniform> activeUniforms = m_glHelper.programUniformsAndLocations(shaderProgram.programId());
+
+ // THEN
+ QCOMPARE(activeUniforms.size(), 4);
+ std::sort(activeUniforms.begin(), activeUniforms.end(), [] (const ShaderUniform &a, const ShaderUniform &b) { return a.m_name < b.m_name; });
+
+ const ShaderUniform uniform1 = activeUniforms.at(0);
+ QCOMPARE(uniform1.m_location, shaderProgram.uniformLocation("multiplier"));
+ QCOMPARE(uniform1.m_offset, -1);
+ QCOMPARE(uniform1.m_blockIndex, -1);
+ QCOMPARE(uniform1.m_arrayStride, -1);
+ QCOMPARE(uniform1.m_matrixStride, -1);
+ QCOMPARE(uniform1.m_size, 1);
+ QCOMPARE(uniform1.m_type, GLenum(GL_FLOAT));
+ QCOMPARE(uniform1.m_name, QStringLiteral("multiplier"));
+
+ const ShaderUniform uniform2 = activeUniforms.at(1);
+ QCOMPARE(uniform2.m_location, shaderProgram.uniformLocation("multiplierVec2"));
+ QCOMPARE(uniform2.m_offset, -1);
+ QCOMPARE(uniform2.m_blockIndex, -1);
+ QCOMPARE(uniform2.m_arrayStride, -1);
+ QCOMPARE(uniform2.m_matrixStride, -1);
+ QCOMPARE(uniform2.m_size, 1);
+ QCOMPARE(uniform2.m_type, GLenum(GL_FLOAT_VEC2));
+ QCOMPARE(uniform2.m_name, QStringLiteral("multiplierVec2"));
+
+ const ShaderUniform uniform3 = activeUniforms.at(2);
+ QCOMPARE(uniform3.m_location, shaderProgram.uniformLocation("multiplierVec3"));
+ QCOMPARE(uniform3.m_offset, -1);
+ QCOMPARE(uniform3.m_blockIndex, -1);
+ QCOMPARE(uniform3.m_arrayStride, -1);
+ QCOMPARE(uniform3.m_matrixStride, -1);
+ QCOMPARE(uniform3.m_size, 1);
+ QCOMPARE(uniform3.m_type, GLenum(GL_FLOAT_VEC3));
+ QCOMPARE(uniform3.m_name, QStringLiteral("multiplierVec3"));
+
+ const ShaderUniform uniform4 = activeUniforms.at(3);
+ QCOMPARE(uniform4.m_location, shaderProgram.uniformLocation("multiplierVec4"));
+ QCOMPARE(uniform4.m_offset, -1);
+ QCOMPARE(uniform4.m_blockIndex, -1);
+ QCOMPARE(uniform4.m_arrayStride, -1);
+ QCOMPARE(uniform4.m_matrixStride, -1);
+ QCOMPARE(uniform4.m_size, 1);
+ QCOMPARE(uniform4.m_type, GLenum(GL_FLOAT_VEC4));
+ QCOMPARE(uniform4.m_name, QStringLiteral("multiplierVec4"));
+ }
+
+ void programShaderStorageBlock()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // Not supported in 3.3
+ }
+
+ void releaseFrameBufferObject()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ GLuint fboId;
+ m_func->glGenFramebuffers(1, &fboId);
+
+ // THEN
+ QVERIFY(fboId != 0);
+
+ // WHEN
+ m_glHelper.releaseFrameBufferObject(fboId);
+
+ // THEN
+ QVERIFY(!m_func->glIsFramebuffer(fboId));
+ }
+
+ void setMSAAEnabled()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ m_func->glDisable(GL_MULTISAMPLE);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_MULTISAMPLE));
+
+ // WHEN
+ m_glHelper.setMSAAEnabled(true);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_MULTISAMPLE));
+
+ // WHEN
+ m_glHelper.setMSAAEnabled(false);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_MULTISAMPLE));
+ }
+
+ void setAlphaCoverageEnabled()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ m_func->glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE));
+
+ // WHEN
+ m_glHelper.setAlphaCoverageEnabled(true);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE));
+
+ // WHEN
+ m_glHelper.setAlphaCoverageEnabled(false);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE));
+ }
+
+ void setClipPlane()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // Deprecated in 3.3 core
+ }
+
+ void setSeamlessCubemap()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ m_func->glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
+ QVERIFY(!m_func->glIsEnabled(GL_TEXTURE_CUBE_MAP_SEAMLESS));
+
+ // WHEN
+ m_glHelper.setSeamlessCubemap(true);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_TEXTURE_CUBE_MAP_SEAMLESS));
+
+ // WHEN
+ m_glHelper.setSeamlessCubemap(false);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_TEXTURE_CUBE_MAP_SEAMLESS));
+ }
+
+ void setVerticesPerPatch()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ m_func->glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_TEXTURE_CUBE_MAP_SEAMLESS));
+
+ // WHEN
+ m_glHelper.setSeamlessCubemap(true);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_TEXTURE_CUBE_MAP_SEAMLESS));
+
+ // WHEN
+ m_glHelper.setSeamlessCubemap(false);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_TEXTURE_CUBE_MAP_SEAMLESS));
+ }
+
+#define SUPPORTS_FEATURE(Feature, IsSupported) \
+ QVERIFY(m_glHelper.supportsFeature(Feature) == IsSupported);
+
+ void supportsFeature()
+ {
+ SUPPORTS_FEATURE(GraphicsHelperInterface::MRT, true);
+ SUPPORTS_FEATURE(GraphicsHelperInterface::UniformBufferObject, true);
+ SUPPORTS_FEATURE(GraphicsHelperInterface::BindableFragmentOutputs, true);
+ SUPPORTS_FEATURE(GraphicsHelperInterface::PrimitiveRestart, true);
+ SUPPORTS_FEATURE(GraphicsHelperInterface::RenderBufferDimensionRetrieval, true);
+ SUPPORTS_FEATURE(GraphicsHelperInterface::TextureDimensionRetrieval, true);
+ SUPPORTS_FEATURE(GraphicsHelperInterface::UniformBufferObject, true);
+ SUPPORTS_FEATURE(GraphicsHelperInterface::ShaderStorageObject, false);
+ SUPPORTS_FEATURE(GraphicsHelperInterface::Compute, false);
+ SUPPORTS_FEATURE(GraphicsHelperInterface::DrawBuffersBlend, false);
+ // Tesselation could be true or false depending on extensions so not tested
+ }
+
+
+#define ADD_UNIFORM_ENTRY(FragShader, Name, Type, ComponentSize, ExpectedRawSize) \
+ QTest::newRow(#FragShader"_"#Type) << FragShader << QStringLiteral(Name) << Type << ComponentSize << ExpectedRawSize;
+
+ void uniformsByteSize_data()
+ {
+ QTest::addColumn<QByteArray>("fragShader");
+ QTest::addColumn<QString>("name");
+ QTest::addColumn<int>("type");
+ QTest::addColumn<int>("componentSize");
+ QTest::addColumn<int>("expectedByteSize");
+
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloat, "multiplier", GL_FLOAT, 1, 4);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloat, "multiplierVec2", GL_FLOAT_VEC2, 1, 4 * 2);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloat, "multiplierVec3",GL_FLOAT_VEC3, 1, 4 * 3);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloat, "multiplierVec4", GL_FLOAT_VEC4, 1, 4 * 4);
+
+ ADD_UNIFORM_ENTRY(fragCodeUniformsInt, "multiplier", GL_INT, 1, 4);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsInt, "multiplierVec2", GL_INT_VEC2, 1, 4 * 2);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsInt, "multiplierVec3", GL_INT_VEC3, 1, 4 * 3);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsInt, "multiplierVec4", GL_INT_VEC4, 1, 4 * 4);
+
+ ADD_UNIFORM_ENTRY(fragCodeUniformsUInt, "multiplier", GL_UNSIGNED_INT, 1, 4);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsUInt, "multiplierVec2", GL_UNSIGNED_INT_VEC2, 1, 4 * 2);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsUInt, "multiplierVec3", GL_UNSIGNED_INT_VEC3, 1, 4 * 3);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsUInt, "multiplierVec4", GL_UNSIGNED_INT_VEC4, 1, 4 * 4);
+
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m2", GL_FLOAT_MAT2, 1, 4 * 2 * 2);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m23", GL_FLOAT_MAT2x3, 1, 4 * 2 * 3);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m32", GL_FLOAT_MAT3x2, 1, 4 * 3 * 2);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m24", GL_FLOAT_MAT2x4, 1, 4 * 2 * 4);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m42", GL_FLOAT_MAT4x2, 1, 4 * 4 * 2);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m3", GL_FLOAT_MAT3, 1, 4 * 3 * 3);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m34", GL_FLOAT_MAT3x4, 1, 4 * 3 * 4);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m43", GL_FLOAT_MAT4x3, 1, 4 * 4 * 3);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m4", GL_FLOAT_MAT4, 1, 4 * 4 * 4);
+
+ ADD_UNIFORM_ENTRY(fragCodeSamplers, "s1", GL_SAMPLER_1D, 1, 4);
+ ADD_UNIFORM_ENTRY(fragCodeSamplers, "s2", GL_SAMPLER_2D, 1, 4);
+ ADD_UNIFORM_ENTRY(fragCodeSamplers, "s2a", GL_SAMPLER_2D_ARRAY, 1, 4);
+ ADD_UNIFORM_ENTRY(fragCodeSamplers, "s3", GL_SAMPLER_3D, 1, 4);
+ ADD_UNIFORM_ENTRY(fragCodeSamplers, "scube", GL_SAMPLER_CUBE, 1, 4);
+ ADD_UNIFORM_ENTRY(fragCodeSamplers, "srect", GL_SAMPLER_2D_RECT, 1, 4);
+ }
+
+ void uniformsByteSize()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QFETCH(QByteArray, fragShader);
+ QFETCH(QString, name);
+ QFETCH(int, type);
+ QFETCH(int, componentSize);
+ QFETCH(int, expectedByteSize);
+
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragShader);
+ QVERIFY(shaderProgram.link());
+
+ GLint location = shaderProgram.uniformLocation(name);
+ // WHEN
+ const QVector<ShaderUniform> activeUniforms = m_glHelper.programUniformsAndLocations(shaderProgram.programId());
+ ShaderUniform matchingUniform;
+ for (const ShaderUniform &u : activeUniforms) {
+ if (u.m_location == location) {
+ matchingUniform = u;
+ break;
+ }
+ }
+
+
+ // THEN
+ QCOMPARE(matchingUniform.m_location, location);
+ QCOMPARE(matchingUniform.m_type, GLuint(type));
+ QCOMPARE(matchingUniform.m_size, componentSize);
+
+ // WHEN
+ const int computedRawByteSize = m_glHelper.uniformByteSize(matchingUniform);
+
+ // THEN
+ QCOMPARE(expectedByteSize, computedRawByteSize);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+
+ void useProgram()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeFragOutputs);
+
+ // THEN
+ QVERIFY(shaderProgram.link());
+
+ GLint currentProg = 0;
+ m_func->glGetIntegerv(GL_CURRENT_PROGRAM, &currentProg);
+ QVERIFY(currentProg == 0);
+
+ // WHEN
+ m_glHelper.useProgram(shaderProgram.programId());
+
+ // THEN
+ m_func->glGetIntegerv(GL_CURRENT_PROGRAM, &currentProg);
+ QCOMPARE(GLuint(currentProg), shaderProgram.programId());
+
+ // WHEN
+ m_glHelper.useProgram(0);
+
+ // THEN
+ m_func->glGetIntegerv(GL_CURRENT_PROGRAM, &currentProg);
+ QVERIFY(currentProg == 0);
+ }
+
+ void vertexAttribDivisor()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+ }
+
+ void glUniform1fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloat);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat value = 883.0f;
+ const GLint location = shaderProgram.uniformLocation("multiplier");
+ m_glHelper.glUniform1fv(location, 1, &value);
+
+ // THEN
+ GLfloat setValue = 0.0f;
+ m_func->glGetUniformfv(shaderProgram.programId(), location, &setValue);
+ QCOMPARE(value, setValue);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform2fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloat);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[2] = { 383.0f, 427.0f };
+ const GLint location = shaderProgram.uniformLocation("multiplierVec2");
+ m_glHelper.glUniform2fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[2] = { 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 2; ++i)
+ QCOMPARE(setValues[i], values[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform3fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloat);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[3] = { 572.0f, 1340.0f, 1584.0f };
+ const GLint location = shaderProgram.uniformLocation("multiplierVec3");
+ m_glHelper.glUniform3fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[3] = { 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 3; ++i)
+ QCOMPARE(setValues[i], values[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform4fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloat);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[4] = { 454.0f, 350.0f, 883.0f, 355.0f };
+ const GLint location = shaderProgram.uniformLocation("multiplierVec4");
+ m_glHelper.glUniform4fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 4; ++i)
+ QCOMPARE(setValues[i], values[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform1iv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsInt);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLint value = 883;
+ const GLint location = shaderProgram.uniformLocation("multiplier");
+ m_glHelper.glUniform1iv(location, 1, &value);
+
+ // THEN
+ GLint setValue = 0;
+ m_func->glGetUniformiv(shaderProgram.programId(), location, &setValue);
+ QCOMPARE(value, setValue);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform2iv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsInt);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLint values[2] = { 383, 427 };
+ const GLint location = shaderProgram.uniformLocation("multiplierVec2");
+ m_glHelper.glUniform2iv(location, 1, values);
+
+ // THEN
+ GLint setValues[2] = { 0, 0 };
+ m_func->glGetUniformiv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 2; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform3iv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsInt);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLint values[3] = { 572, 1340, 1584 };
+ const GLint location = shaderProgram.uniformLocation("multiplierVec3");
+ m_glHelper.glUniform3iv(location, 1, values);
+
+ // THEN
+ GLint setValues[3] = { 0, 0, 0 };
+ m_func->glGetUniformiv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 3; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform4iv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsInt);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLint values[4] = { 454, 350, 883, 355 };
+ const GLint location = shaderProgram.uniformLocation("multiplierVec4");
+ m_glHelper.glUniform4iv(location, 1, values);
+
+ // THEN
+ GLint setValues[4] = { 0, 0, 0, 0 };
+ m_func->glGetUniformiv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 4; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform1uiv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsUInt);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLuint value = 883U;
+ const GLint location = shaderProgram.uniformLocation("multiplier");
+ m_glHelper.glUniform1uiv(location, 1, &value);
+
+ // THEN
+ GLuint setValue = 0U;
+ m_func->glGetUniformuiv(shaderProgram.programId(), location, &setValue);
+ QCOMPARE(value, setValue);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform2uiv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsUInt);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLuint values[2] = { 383U, 427U };
+ const GLint location = shaderProgram.uniformLocation("multiplierVec2");
+ m_glHelper.glUniform2uiv(location, 1, values);
+
+ // THEN
+ GLuint setValues[2] = { 0U, 0U };
+ m_func->glGetUniformuiv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 2; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform3uiv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsUInt);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLuint values[3] = { 572U, 1340U, 1584U };
+ const GLint location = shaderProgram.uniformLocation("multiplierVec3");
+ m_glHelper.glUniform3uiv(location, 1, values);
+
+ // THEN
+ GLuint setValues[3] = { 0U, 0U, 0U };
+ m_func->glGetUniformuiv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 3; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform4uiv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsUInt);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLuint values[4] = { 454U, 350U, 883U, 355U };
+ const GLint location = shaderProgram.uniformLocation("multiplierVec4");
+ m_glHelper.glUniform4uiv(location, 1, values);
+
+ // THEN
+ GLuint setValues[4] = { 0U, 0U, 0U, 0U };
+ m_func->glGetUniformuiv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 4; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix2fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[4] = { 454.0f, 350.0f, 883.0f, 355.0f };
+ const GLint location = shaderProgram.uniformLocation("m2");
+ m_glHelper.glUniformMatrix2fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 4; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix3fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[9] = { 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f, 1200.0f, 427.0f, 396.0f };
+ const GLint location = shaderProgram.uniformLocation("m3");
+ m_glHelper.glUniformMatrix3fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[9] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 9; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix4fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[16] = { 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f, 1200.0f, 427.0f, 396.0f, 1603.0f, 55.0f, 5.7, 383.0f, 6.2f, 5.3f, 327.0f };
+ const GLint location = shaderProgram.uniformLocation("m4");
+ m_glHelper.glUniformMatrix4fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[16] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 16; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix2x3fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[6] = { 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f};
+ const GLint location = shaderProgram.uniformLocation("m23");
+ m_glHelper.glUniformMatrix2x3fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[6] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 6; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix3x2fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[6] = { 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f};
+ const GLint location = shaderProgram.uniformLocation("m32");
+ m_glHelper.glUniformMatrix3x2fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[6] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 6; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix2x4fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[8] = { 383.0f, 427.0f, 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f};
+ const GLint location = shaderProgram.uniformLocation("m24");
+ m_glHelper.glUniformMatrix2x4fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[8] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 8; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix4x2fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[8] = { 383.0f, 427.0f, 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f};
+ const GLint location = shaderProgram.uniformLocation("m42");
+ m_glHelper.glUniformMatrix4x2fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[8] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 8; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix3x4fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[12] = { 55.0f, 5.7, 383.0f, 6.2f, 5.3f, 383.0f, 427.0f, 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f};
+ const GLint location = shaderProgram.uniformLocation("m34");
+ m_glHelper.glUniformMatrix3x4fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[12] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 12; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix4x3fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[12] = { 55.0f, 5.7, 383.0f, 6.2f, 383.0f, 427.0f, 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f};
+ const GLint location = shaderProgram.uniformLocation("m43");
+ m_glHelper.glUniformMatrix4x3fv(location, 1, values);
+
+ // THEN
+ GLfloat setValues[12] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), location, setValues);
+ for (int i = 0; i < 12; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+#define ADD_GL_TYPE_ENTRY(Type, Expected) \
+ QTest::newRow(#Type) << Type << Expected;
+
+ void uniformTypeFromGLType_data()
+ {
+ QTest::addColumn<int>("glType");
+ QTest::addColumn<UniformType>("expected");
+
+ ADD_GL_TYPE_ENTRY(GL_FLOAT, UniformType::Float);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC2, UniformType::Vec2);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC3, UniformType::Vec3);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC3, UniformType::Vec3);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC2, UniformType::Vec2);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC3, UniformType::Vec3);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC3, UniformType::Vec3);
+ ADD_GL_TYPE_ENTRY(GL_INT, UniformType::Int);
+ ADD_GL_TYPE_ENTRY(GL_INT_VEC2, UniformType::IVec2);
+ ADD_GL_TYPE_ENTRY(GL_INT_VEC3, UniformType::IVec3);
+ ADD_GL_TYPE_ENTRY(GL_INT_VEC4, UniformType::IVec4);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT, UniformType::UInt);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_VEC2, UniformType::UIVec2);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_VEC3, UniformType::UIVec3);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_VEC4, UniformType::UIVec4);
+ ADD_GL_TYPE_ENTRY(GL_BOOL, UniformType::Bool);
+ ADD_GL_TYPE_ENTRY(GL_BOOL_VEC2, UniformType::BVec2);
+ ADD_GL_TYPE_ENTRY(GL_BOOL_VEC3, UniformType::BVec3);
+ ADD_GL_TYPE_ENTRY(GL_BOOL_VEC4, UniformType::BVec4);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT2, UniformType::Mat2);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT3, UniformType::Mat3);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT4, UniformType::Mat4);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT2x3, UniformType::Mat2x3);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT2x4, UniformType::Mat2x4);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT3x2, UniformType::Mat3x2);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT4x2, UniformType::Mat4x2);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT4x3, UniformType::Mat4x3);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT3x4, UniformType::Mat3x4);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_1D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_1D_ARRAY, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_1D_SHADOW, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_2D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_2D_ARRAY, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_2D_RECT, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_2D_MULTISAMPLE, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_2D_MULTISAMPLE_ARRAY, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_2D_SHADOW, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_2D_ARRAY_SHADOW, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_3D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_CUBE, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_CUBE_SHADOW, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_BUFFER, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_INT_SAMPLER_1D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_INT_SAMPLER_2D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_INT_SAMPLER_3D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_INT_SAMPLER_BUFFER, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_INT_SAMPLER_2D_ARRAY, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_INT_SAMPLER_2D_MULTISAMPLE, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_INT_SAMPLER_CUBE, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_SAMPLER_1D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_SAMPLER_2D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_SAMPLER_3D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_SAMPLER_BUFFER, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_SAMPLER_2D_ARRAY, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_SAMPLER_CUBE, UniformType::Sampler);
+ }
+
+ void uniformTypeFromGLType()
+ {
+ // GIVEN
+ QFETCH(int, glType);
+ QFETCH(UniformType, expected);
+
+ // WHEN
+ UniformType computed = m_glHelper.uniformTypeFromGLType(glType);
+
+ // THEN
+ QCOMPARE(computed, expected);
+ }
+
+private:
+ QScopedPointer<QWindow> m_window;
+ QOpenGLContext m_glContext;
+ GraphicsHelperGL3_3 m_glHelper;
+ QOpenGLFunctions_3_3_Core *m_func = nullptr;
+ bool m_initializationSuccessful = false;
+};
+
+#endif
+
+QT_BEGIN_NAMESPACE
+QTEST_ADD_GPU_BLACKLIST_SUPPORT_DEFS
+QT_END_NAMESPACE
+
+int main(int argc, char *argv[])
+{
+#ifdef TEST_SHOULD_BE_PERFORMED
+ QGuiApplication app(argc, argv);
+ app.setAttribute(Qt::AA_Use96Dpi, true);
+ QTEST_ADD_GPU_BLACKLIST_SUPPORT
+ tst_GraphicsHelperGL3_3 tc;
+ QTEST_SET_MAIN_SOURCE_PATH
+ return QTest::qExec(&tc, argc, argv);
+#endif
+ return 0;
+}
+
+#ifdef TEST_SHOULD_BE_PERFORMED
+#include "tst_graphicshelpergl3_3.moc"
+#endif
diff --git a/tests/auto/render/graphicshelpergl4/graphicshelpergl4.pro b/tests/auto/render/graphicshelpergl4/graphicshelpergl4.pro
new file mode 100644
index 000000000..b20d1afec
--- /dev/null
+++ b/tests/auto/render/graphicshelpergl4/graphicshelpergl4.pro
@@ -0,0 +1,13 @@
+TEMPLATE = app
+
+TARGET = tst_graphicshelpergl4
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += \
+ tst_graphicshelpergl4.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/graphicshelpergl4/tst_graphicshelpergl4.cpp b/tests/auto/render/graphicshelpergl4/tst_graphicshelpergl4.cpp
new file mode 100644
index 000000000..25670c545
--- /dev/null
+++ b/tests/auto/render/graphicshelpergl4/tst_graphicshelpergl4.cpp
@@ -0,0 +1,2047 @@
+/****************************************************************************
+**
+** 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:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QTest>
+#include <Qt3DRender/qrendertargetoutput.h>
+#include <Qt3DRender/private/uniform_p.h>
+#include <Qt3DRender/private/graphicshelpergl4_p.h>
+#include <Qt3DRender/private/attachmentpack_p.h>
+#include <QOpenGLFunctions_4_3_Core>
+#include <QOpenGLShaderProgram>
+#include <QSurfaceFormat>
+
+#if !defined(QT_OPENGL_ES_2) && defined(QT_OPENGL_4_3)
+
+#define TEST_SHOULD_BE_PERFORMED 1
+
+using namespace Qt3DRender;
+using namespace Qt3DRender::Render;
+
+namespace {
+
+const QByteArray vertCode = QByteArrayLiteral(
+ "#version 430 core\n" \
+ "layout(location = 1) in vec3 vertexPosition;\n" \
+ "layout(location = 2) in vec2 vertexTexCoord;\n" \
+ "out vec2 texCoord;\n" \
+ "void main()\n" \
+ "{\n" \
+ " texCoord = vertexTexCoord;\n" \
+ " gl_Position = vec4(vertexPosition, 1.0);\n" \
+ "}\n");
+
+const QByteArray vertCodeUniformBuffer = QByteArrayLiteral(
+ "#version 430 core\n" \
+ "layout(location = 1) in vec3 vertexPosition;\n" \
+ "layout(location = 2) in vec2 vertexTexCoord;\n" \
+ "layout(location = 3) in int vertexColorIndex;\n" \
+ "out vec2 texCoord;\n" \
+ "flat out int colorIndex;\n" \
+ "void main()\n" \
+ "{\n" \
+ " texCoord = vertexTexCoord;\n" \
+ " colorIndex = vertexColorIndex;\n" \
+ " gl_Position = vec4(vertexPosition, 1.0);\n" \
+ "}\n");
+
+const QByteArray fragCodeFragOutputs = QByteArrayLiteral(
+ "#version 430 core\n" \
+ "out vec4 color;\n" \
+ "out vec2 temp;\n" \
+ "void main()\n" \
+ "{\n" \
+ " color = vec4(1.0, 0.0, 0.0, 1.0);\n" \
+ " temp = vec2(1.0, 0.3);\n" \
+ "}\n");
+
+const QByteArray fragCodeUniformsFloat = QByteArrayLiteral(
+ "#version 430 core\n" \
+ "out vec4 color;\n" \
+ "layout(location = 1) uniform float multiplier;\n" \
+ "layout(location = 2) uniform vec2 multiplierVec2;\n" \
+ "layout(location = 3) uniform vec3 multiplierVec3;\n" \
+ "layout(location = 4) uniform vec4 multiplierVec4;\n" \
+ "void main()\n" \
+ "{\n" \
+ " vec4 randomMult = multiplierVec4 + vec4(multiplierVec3, 0.0) + vec4(multiplierVec2, 0.0, 0.0);\n" \
+ " color = vec4(1.0, 0.0, 0.0, 1.0) * randomMult * multiplier;\n" \
+ "}\n");
+
+const QByteArray fragCodeUniformsInt = QByteArrayLiteral(
+ "#version 430 core\n" \
+ "out ivec4 color;\n" \
+ "layout(location = 1) uniform int multiplier;\n" \
+ "layout(location = 2) uniform ivec2 multiplierVec2;\n" \
+ "layout(location = 3) uniform ivec3 multiplierVec3;\n" \
+ "layout(location = 4) uniform ivec4 multiplierVec4;\n" \
+ "void main()\n" \
+ "{\n" \
+ " ivec4 randomMult = multiplierVec4 + ivec4(multiplierVec3, 0) + ivec4(multiplierVec2, 0, 0);\n" \
+ " color = ivec4(1, 0, 0, 1) * randomMult * multiplier;\n" \
+ "}\n");
+
+const QByteArray fragCodeUniformsUInt = QByteArrayLiteral(
+ "#version 430 core\n" \
+ "out uvec4 color;\n" \
+ "layout(location = 1) uniform uint multiplier;\n" \
+ "layout(location = 2) uniform uvec2 multiplierVec2;\n" \
+ "layout(location = 3) uniform uvec3 multiplierVec3;\n" \
+ "layout(location = 4) uniform uvec4 multiplierVec4;\n" \
+ "void main()\n" \
+ "{\n" \
+ " uvec4 randomMult = multiplierVec4 + uvec4(multiplierVec3, 0) + uvec4(multiplierVec2, 0, 0);\n" \
+ " color = uvec4(1, 0, 0, 1) * randomMult * multiplier;\n" \
+ "}\n");
+
+const QByteArray fragCodeUniformsFloatMatrices = QByteArrayLiteral(
+ "#version 430 core\n" \
+ "out vec4 color;\n" \
+ "layout(location = 1) uniform mat2 m2;\n" \
+ "layout(location = 2) uniform mat2x3 m23;\n" \
+ "layout(location = 3) uniform mat3x2 m32;\n" \
+ "layout(location = 4) uniform mat2x4 m24;\n" \
+ "layout(location = 5) uniform mat4x2 m42;\n" \
+ "layout(location = 6) uniform mat3 m3;\n" \
+ "layout(location = 7) uniform mat3x4 m34;\n" \
+ "layout(location = 8) uniform mat4x3 m43;\n" \
+ "layout(location = 9) uniform mat4 m4;\n" \
+ "void main()\n" \
+ "{\n" \
+ " float lengthSum = m2[0][0] + m23[0][0] + m32[0][0] + m24[0][0] + m42[0][0] + m3[0][0] + m34[0][0] + m43[0][0] + m4[0][0];\n" \
+ " color = vec4(1, 0, 0, 1) * lengthSum;\n" \
+ "}\n");
+
+const QByteArray fragCodeUniformBuffer = QByteArrayLiteral(
+ "#version 430 core\n" \
+ "out vec4 color;\n" \
+ "flat in int colorIndex;\n" \
+ "layout(binding = 2, std140) uniform ColorArray\n" \
+ "{\n" \
+ " vec4 colors[256];\n" \
+ "};\n" \
+ "void main()\n" \
+ "{\n" \
+ " color = colors[colorIndex];\n" \
+ "}\n");
+
+const QByteArray fragCodeSamplers = QByteArrayLiteral(
+ "#version 430 core\n" \
+ "in vec2 texCoord;\n" \
+ "out vec4 color;\n" \
+ "layout(location = 1) uniform sampler1D s1;\n" \
+ "layout(location = 2) uniform sampler2D s2;\n" \
+ "layout(location = 3) uniform sampler2DArray s2a;\n" \
+ "layout(location = 4) uniform sampler3D s3;\n" \
+ "layout(location = 5) uniform samplerCube scube;\n" \
+ "layout(location = 6) uniform sampler2DRect srect;\n" \
+ "void main()\n" \
+ "{\n" \
+ " color = vec4(1, 0, 0, 1) *" \
+ " texture(s1, texCoord.x) *" \
+ " texture(s2, texCoord) *" \
+ " texture(s2a, vec3(texCoord, 0.0)) *" \
+ " texture(s3, vec3(texCoord, 0.0)) *" \
+ " texture(scube, vec3(texCoord, 0)) *" \
+ " texture(srect, texCoord);\n" \
+ "}\n");
+
+const QByteArray computeShader = QByteArrayLiteral(
+ "#version 430 core\n" \
+ "uniform float particleStep;\n" \
+ "uniform float finalCollisionFactor;\n" \
+ "layout (local_size_x = 1024) in;\n" \
+ "struct ParticleData\n" \
+ "{\n" \
+ " vec4 position;\n" \
+ " vec4 direction;\n" \
+ " vec4 color;\n" \
+ "};\n" \
+ "layout (std140, binding = 0) coherent buffer Particles\n" \
+ "{\n" \
+ " ParticleData particles[];\n" \
+ "} data;\n" \
+ "void main(void)\n" \
+ "{\n" \
+ " uint globalId = gl_GlobalInvocationID.x;\n" \
+ " ParticleData currentParticle = data.particles[globalId];\n" \
+ " currentParticle.position = currentParticle.position + currentParticle.direction * particleStep;\n" \
+ " vec4 acceleration = normalize(vec4(0.0) - currentParticle.position) * finalCollisionFactor;\n" \
+ " currentParticle.direction = currentParticle.direction + acceleration * particleStep;\n" \
+ " data.particles[globalId] = currentParticle;\n" \
+ "}");
+
+} // anonymous
+
+class tst_GraphicsHelperGL4 : public QObject
+{
+ Q_OBJECT
+private Q_SLOTS:
+ void init()
+ {
+ m_window.reset(new QWindow);
+ m_window->setSurfaceType(QWindow::OpenGLSurface);
+ m_window->setGeometry(0, 0, 10, 10);
+
+ QSurfaceFormat format;
+ format.setVersion(4, 3);
+ format.setProfile(QSurfaceFormat::CoreProfile);
+ format.setDepthBufferSize(24);
+ format.setSamples(4);
+ format.setStencilBufferSize(8);
+ m_window->setFormat(format);
+ m_glContext.setFormat(format);
+
+ m_window->create();
+
+ if (!m_glContext.create()) {
+ qWarning() << "Failed to create OpenGL context";
+ return;
+ }
+
+ if (!m_glContext.makeCurrent(m_window.data())) {
+ qWarning() << "Failed to make OpenGL context current";
+ return;
+ }
+
+ if ((m_func = m_glContext.versionFunctions<QOpenGLFunctions_4_3_Core>()) != nullptr) {
+ m_glHelper.initializeHelper(&m_glContext, m_func);
+ m_initializationSuccessful = true;
+ }
+ }
+
+ void alphaTest()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+ // Deprecated
+ }
+
+ void bindBufferBase()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ GLuint bufferId = 0;
+ // WHEN
+ m_func->glGenBuffers(1, &bufferId);
+ // THEN
+ QVERIFY(bufferId != 0);
+
+
+ // WHEN
+ m_func->glBindBuffer(GL_SHADER_STORAGE_BUFFER, bufferId);
+ m_glHelper.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, bufferId);
+ // THEN
+ const GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ GLint boundToPointBufferId = 0;
+ m_func->glGetIntegeri_v(GL_SHADER_STORAGE_BUFFER_BINDING, 2, &boundToPointBufferId);
+ QVERIFY(boundToPointBufferId == GLint(bufferId));
+
+ // Restore to sane state
+ m_func->glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
+ m_func->glDeleteBuffers(1, &bufferId);
+ }
+
+ void bindFragDataLocation()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeFragOutputs);
+
+ // WHEN
+ QHash<QString, int> fragLocations;
+ fragLocations.insert(QStringLiteral("temp"), 2);
+ fragLocations.insert(QStringLiteral("color"), 1);
+ m_glHelper.bindFragDataLocation(shaderProgram.programId(), fragLocations);
+
+ // THEN
+ QVERIFY(shaderProgram.link());
+ const GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ const GLint tempLocation = m_func->glGetFragDataLocation(shaderProgram.programId(), "temp");
+ const GLint colorLocation = m_func->glGetFragDataLocation(shaderProgram.programId(), "color");
+ QCOMPARE(tempLocation, 2);
+ QCOMPARE(colorLocation, 1);
+ }
+
+ void bindFrameBufferAttachment()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ GLuint fboId;
+ m_func->glGenFramebuffers(1, &fboId);
+
+ Attachment attachment;
+ attachment.m_point = QRenderTargetOutput::Color2;
+
+ // THEN
+ QVERIFY(fboId != 0);
+
+ // WHEN
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId);
+
+ QOpenGLTexture texture(QOpenGLTexture::Target2D);
+ texture.setSize(512, 512);
+ texture.setFormat(QOpenGLTexture::RGBA32F);
+ texture.setMinificationFilter(QOpenGLTexture::Linear);
+ texture.setMagnificationFilter(QOpenGLTexture::Linear);
+ texture.setWrapMode(QOpenGLTexture::ClampToEdge);
+ if (!texture.create())
+ qWarning() << "Texture creation failed";
+ texture.allocateStorage();
+ QVERIFY(texture.isStorageAllocated());
+ GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ m_glHelper.bindFrameBufferAttachment(&texture, attachment);
+
+ // THEN
+ GLenum status = m_func->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ QVERIFY(status == GL_FRAMEBUFFER_COMPLETE);
+
+ error = m_func->glGetError();
+ QVERIFY(error == 0);
+ GLint textureAttachmentId = 0;
+ m_func->glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0 + 2,
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
+ &textureAttachmentId);
+ QCOMPARE(GLuint(textureAttachmentId), texture.textureId());
+
+ // Restore state
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ m_func->glDeleteFramebuffers(1, &fboId);
+ }
+
+ void bindFrameBufferObject()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ GLuint fboId;
+ m_func->glGenFramebuffers(1, &fboId);
+
+ // THEN
+ QVERIFY(fboId != 0);
+
+ // WHEN
+ m_glHelper.bindFrameBufferObject(fboId);
+
+ // THEN
+ const GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ GLint boundindFBOId = 0;
+ m_func->glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &boundindFBOId);
+ QVERIFY(GLuint(boundindFBOId) == fboId);
+
+ // Cleanup
+ m_func->glDeleteFramebuffers(1, &fboId);
+ }
+
+ void bindShaderStorageBlock()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Compute, computeShader);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ GLint index = m_func->glGetProgramResourceIndex(shaderProgram.programId(),
+ GL_SHADER_STORAGE_BLOCK,
+ "Particles");
+ m_glHelper.bindShaderStorageBlock(shaderProgram.programId(), index, 1);
+
+ // THEN
+ const GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ }
+
+ void bindUniformBlock()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCodeUniformBuffer);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformBuffer);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ GLint index = m_func->glGetUniformBlockIndex(shaderProgram.programId(), "ColorArray");
+ m_glHelper.bindUniformBlock(shaderProgram.programId(), index, 1);
+
+ // THEN
+ const GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ }
+
+ void blendEquation()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ GLint equation = 0;
+ m_func->glGetIntegerv(GL_BLEND_EQUATION_RGB, &equation);
+ QCOMPARE(equation, GL_FUNC_ADD);
+
+ // WHEN
+ m_glHelper.blendEquation(GL_FUNC_REVERSE_SUBTRACT);
+
+ // THEN
+ m_func->glGetIntegerv(GL_BLEND_EQUATION_RGB, &equation);
+ QCOMPARE(equation, GL_FUNC_REVERSE_SUBTRACT);
+ }
+
+ void blendFunci()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ GLint destinationRgb = 0;
+ GLint destinationAlpha = 0;
+ GLint sourceRgb = 0;
+ GLint sourceAlpha = 0;
+ m_func->glGetIntegeri_v(GL_BLEND_SRC_RGB, 4, &sourceRgb);
+ m_func->glGetIntegeri_v(GL_BLEND_DST_RGB, 4, &destinationRgb);
+ m_func->glGetIntegeri_v(GL_BLEND_SRC_ALPHA, 4, &sourceAlpha);
+ m_func->glGetIntegeri_v(GL_BLEND_DST_ALPHA, 4, &destinationAlpha);
+
+ // THEN
+ QCOMPARE(destinationAlpha, GL_ZERO);
+ QCOMPARE(destinationRgb, GL_ZERO);
+ QCOMPARE(sourceRgb, GL_ONE);
+ QCOMPARE(sourceAlpha, GL_ONE);
+
+ // WHEN
+ m_glHelper.blendFunci(4, GL_SRC_COLOR, GL_ONE_MINUS_SRC_ALPHA);
+
+ m_func->glGetIntegeri_v(GL_BLEND_SRC_RGB, 4, &sourceRgb);
+ m_func->glGetIntegeri_v(GL_BLEND_DST_RGB, 4, &destinationRgb);
+ m_func->glGetIntegeri_v(GL_BLEND_SRC_ALPHA, 4, &sourceAlpha);
+ m_func->glGetIntegeri_v(GL_BLEND_DST_ALPHA, 4, &destinationAlpha);
+
+ // THEN
+ QCOMPARE(destinationAlpha, GL_ONE_MINUS_SRC_ALPHA);
+ QCOMPARE(destinationRgb, GL_ONE_MINUS_SRC_ALPHA);
+ QCOMPARE(sourceRgb, GL_SRC_COLOR);
+ QCOMPARE(sourceAlpha, GL_SRC_COLOR);
+
+ // Reset default
+ m_glHelper.blendFunci(4, GL_ONE, GL_ZERO);
+ }
+
+ void blendFuncSeparatei()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ GLint destinationRgb = 0;
+ GLint destinationAlpha = 0;
+ GLint sourceRgb = 0;
+ GLint sourceAlpha = 0;
+ m_func->glGetIntegeri_v(GL_BLEND_SRC_RGB, 2, &sourceRgb);
+ m_func->glGetIntegeri_v(GL_BLEND_DST_RGB, 2, &destinationRgb);
+ m_func->glGetIntegeri_v(GL_BLEND_SRC_ALPHA, 2, &sourceAlpha);
+ m_func->glGetIntegeri_v(GL_BLEND_DST_ALPHA, 2, &destinationAlpha);
+
+ // THEN
+ QCOMPARE(destinationAlpha, GL_ZERO);
+ QCOMPARE(destinationRgb, GL_ZERO);
+ QCOMPARE(sourceRgb, GL_ONE);
+ QCOMPARE(sourceAlpha, GL_ONE);
+
+ // WHEN
+ m_glHelper.blendFuncSeparatei(2, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ m_func->glGetIntegeri_v(GL_BLEND_SRC_RGB, 2, &sourceRgb);
+ m_func->glGetIntegeri_v(GL_BLEND_DST_RGB, 2, &destinationRgb);
+ m_func->glGetIntegeri_v(GL_BLEND_SRC_ALPHA, 2, &sourceAlpha);
+ m_func->glGetIntegeri_v(GL_BLEND_DST_ALPHA, 2, &destinationAlpha);
+
+ // THEN
+ QCOMPARE(destinationAlpha, GL_ONE_MINUS_SRC_ALPHA);
+ QCOMPARE(destinationRgb, GL_ONE_MINUS_SRC_COLOR);
+ QCOMPARE(sourceRgb, GL_SRC_COLOR);
+ QCOMPARE(sourceAlpha, GL_SRC_ALPHA);
+
+ // Reset default
+ m_glHelper.blendFunci(4, GL_ONE, GL_ZERO);
+ }
+
+ void boundFrameBufferObject()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ GLuint fboId;
+ m_func->glGenFramebuffers(1, &fboId);
+
+ // WHEN
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId);
+
+ // THEN
+ GLint boundBuffer = 0;
+ m_func->glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &boundBuffer);
+ QCOMPARE(GLuint(boundBuffer), fboId);
+
+ // THEN
+ QCOMPARE(m_glHelper.boundFrameBufferObject(), fboId);
+
+ // Reset state
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ m_func->glDeleteFramebuffers(1, &fboId);
+ }
+
+ void checkFrameBufferComplete()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+ // GIVEN
+ GLuint fboId;
+ m_func->glGenFramebuffers(1, &fboId);
+
+ Attachment attachment;
+ attachment.m_point = QRenderTargetOutput::Color1;
+
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId);
+
+ QOpenGLTexture texture(QOpenGLTexture::Target2D);
+ texture.setSize(512, 512);
+ texture.setFormat(QOpenGLTexture::RGBA8U);
+ texture.setMinificationFilter(QOpenGLTexture::Linear);
+ texture.setMagnificationFilter(QOpenGLTexture::Linear);
+ texture.create();
+ texture.allocateStorage();
+ m_glHelper.bindFrameBufferAttachment(&texture, attachment);
+
+ // THEN
+ GLenum status = m_func->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ QVERIFY(status == GL_FRAMEBUFFER_COMPLETE);
+
+ QVERIFY(m_glHelper.checkFrameBufferComplete());
+
+ // Restore
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ m_func->glDeleteFramebuffers(1, &fboId);
+ }
+
+ void clearBufferf()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ // GIVEN
+ GLuint fboId;
+ m_func->glGenFramebuffers(1, &fboId);
+
+ // THEN
+ QVERIFY(fboId != 0);
+
+ // WHEN
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId);
+ // Create 4 attachments
+ QOpenGLTexture *textures[4];
+ for (int i = 0; i < 4; ++i) {
+ Attachment attachment;
+ attachment.m_point = static_cast<QRenderTargetOutput::AttachmentPoint>(i);
+
+ QOpenGLTexture *texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
+ textures[i] = texture;
+ texture->setSize(512, 512);
+ texture->setFormat(QOpenGLTexture::RGBA32F);
+ texture->setMinificationFilter(QOpenGLTexture::Linear);
+ texture->setMagnificationFilter(QOpenGLTexture::Linear);
+ texture->setWrapMode(QOpenGLTexture::ClampToEdge);
+ if (!texture->create())
+ qWarning() << "Texture creation failed";
+ texture->allocateStorage();
+ QVERIFY(texture->isStorageAllocated());
+ GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ m_glHelper.bindFrameBufferAttachment(texture, attachment);
+ }
+
+ GLenum status = m_func->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ QVERIFY(status == GL_FRAMEBUFFER_COMPLETE);
+
+ // Set Draw buffers
+ GLenum clearBufferEnum = GL_COLOR_ATTACHMENT3;
+ m_func->glDrawBuffers(1, &clearBufferEnum);
+
+ const GLint bufferIndex = 0; // index of the element in the draw buffers
+ GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+
+ // WHEN
+ const QVector4D clearValue1 = QVector4D(0.5f, 0.2f, 0.4f, 0.8f);
+ m_func->glClearBufferfv(GL_COLOR, bufferIndex, reinterpret_cast<const float *>(&clearValue1));
+ error = m_func->glGetError();
+ QVERIFY(error == 0);
+
+ // THEN
+ QVector<QVector4D> colors(512 * 512);
+ textures[3]->bind();
+ m_func->glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, colors.data());
+ textures[3]->release();
+ for (const QVector4D c : colors)
+ QVERIFY(c == clearValue1);
+
+
+ // WHEN
+ const QVector4D clearValue2 = QVector4D(0.4f, 0.5f, 0.4f, 1.0f);
+ m_glHelper.clearBufferf(bufferIndex, clearValue2);
+
+ // THEN
+ textures[3]->bind();
+ m_func->glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, colors.data());
+ textures[3]->release();
+ for (const QVector4D c : colors)
+ QVERIFY(c == clearValue2);
+
+ // Restore
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ m_func->glDeleteFramebuffers(1, &fboId);
+ for (int i = 0; i < 4; ++i)
+ delete textures[i];
+ }
+
+ void createFrameBufferObject()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // WHEN
+ const GLuint fboId = m_glHelper.createFrameBufferObject();
+
+ // THEN
+ QVERIFY(fboId != 0);
+
+ // Restore
+ m_func->glDeleteFramebuffers(1, &fboId);
+ }
+
+ void depthMask()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ GLboolean depthWritingEnabled = false;
+ m_func->glGetBooleanv(GL_DEPTH_WRITEMASK, &depthWritingEnabled);
+
+ // THEN
+ QVERIFY(depthWritingEnabled);
+
+ // WHEN
+ m_glHelper.depthMask(GL_FALSE);
+
+ // THEN
+ m_func->glGetBooleanv(GL_DEPTH_WRITEMASK, &depthWritingEnabled);
+ QVERIFY(!depthWritingEnabled);
+
+ // WHEN
+ m_glHelper.depthMask(GL_TRUE);
+
+ // THEN
+ m_func->glGetBooleanv(GL_DEPTH_WRITEMASK, &depthWritingEnabled);
+ QVERIFY(depthWritingEnabled);
+ }
+
+ void depthTest()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ m_func->glDisable(GL_DEPTH_TEST);
+ m_func->glDepthFunc(GL_LESS);
+
+ // WHEN
+ m_glHelper.depthTest(GL_LEQUAL);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_DEPTH_TEST));
+ GLint depthMode = 0;
+ m_func->glGetIntegerv(GL_DEPTH_FUNC, &depthMode);
+ QCOMPARE(depthMode, GL_LEQUAL);
+
+ // WHEN
+ m_glHelper.depthTest(GL_LESS);
+ QVERIFY(m_func->glIsEnabled(GL_DEPTH_TEST));
+ m_func->glGetIntegerv(GL_DEPTH_FUNC, &depthMode);
+ QCOMPARE(depthMode, GL_LESS);
+ }
+
+ void disableClipPlane()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ m_func->glEnable(GL_CLIP_DISTANCE0 + 5);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_CLIP_DISTANCE0 + 5));
+
+ // WHEN
+ m_glHelper.disableClipPlane(5);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_CLIP_DISTANCE0 + 5));
+ }
+
+ void disablei()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ m_func->glEnablei(GL_BLEND, 2);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabledi(GL_BLEND, 2));
+
+ // WHEN
+ m_glHelper.disablei(GL_BLEND, 2);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabledi(GL_BLEND, 2));
+ }
+
+ void disablePrimitiveRestart()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ m_func->glEnable(GL_PRIMITIVE_RESTART);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_PRIMITIVE_RESTART));
+
+ // WHEN
+ m_glHelper.disablePrimitiveRestart();
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_PRIMITIVE_RESTART));
+ }
+
+ void drawBuffers()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ GLuint fboId;
+ m_func->glGenFramebuffers(1, &fboId);
+
+ // THEN
+ QVERIFY(fboId != 0);
+
+ // WHEN
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId);
+ QOpenGLTexture *textures[4];
+
+ // Create 4 attachments
+ for (int i = 0; i < 4; ++i) {
+ Attachment attachment;
+ attachment.m_point = static_cast<QRenderTargetOutput::AttachmentPoint>(i);
+
+ QOpenGLTexture *texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
+ textures[i] = texture;
+ texture->setSize(512, 512);
+ texture->setFormat(QOpenGLTexture::RGBA32F);
+ texture->setMinificationFilter(QOpenGLTexture::Linear);
+ texture->setMagnificationFilter(QOpenGLTexture::Linear);
+ texture->setWrapMode(QOpenGLTexture::ClampToEdge);
+ if (!texture->create())
+ qWarning() << "Texture creation failed";
+ texture->allocateStorage();
+ QVERIFY(texture->isStorageAllocated());
+ GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ m_glHelper.bindFrameBufferAttachment(texture, attachment);
+ }
+ // THEN
+ GLenum status = m_func->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ QVERIFY(status == GL_FRAMEBUFFER_COMPLETE);
+
+ // WHEN
+ GLenum bufferEnum = GL_COLOR_ATTACHMENT4;
+ m_func->glDrawBuffers(1, &bufferEnum);
+
+ // THEN
+ GLint enumValue = -1;
+ m_func->glGetIntegerv(GL_DRAW_BUFFER0, &enumValue);
+ QCOMPARE(enumValue, GL_COLOR_ATTACHMENT4);
+
+ // WHEN
+ GLint newBufferEnum = 2;
+ m_glHelper.drawBuffers(1, &newBufferEnum);
+
+ // THEN
+ m_func->glGetIntegerv(GL_DRAW_BUFFER0, &enumValue);
+ QCOMPARE(enumValue, GL_COLOR_ATTACHMENT0 + newBufferEnum);
+
+ // WHEN
+ newBufferEnum = 0;
+ m_glHelper.drawBuffers(1, &newBufferEnum);
+
+ // THEN
+ m_func->glGetIntegerv(GL_DRAW_BUFFER0, &enumValue);
+ QCOMPARE(enumValue, GL_COLOR_ATTACHMENT0 + newBufferEnum);
+
+ // Restore
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ m_func->glDeleteFramebuffers(1, &fboId);
+ for (int i = 0; i < 4; ++i)
+ delete textures[i];
+ }
+
+ void enableClipPlane()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ m_func->glDisable(GL_CLIP_DISTANCE0 + 4);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_CLIP_DISTANCE0 + 4));
+
+ // WHEN
+ m_glHelper.enableClipPlane(4);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_CLIP_DISTANCE0 + 4));
+ }
+
+ void enablei()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ m_func->glDisablei(GL_BLEND, 4);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabledi(GL_BLEND, 4));
+
+ // WHEN
+ m_glHelper.enablei(GL_BLEND, 4);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabledi(GL_BLEND, 4));
+ }
+
+ void enablePrimitiveRestart()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ m_func->glDisable(GL_PRIMITIVE_RESTART);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_PRIMITIVE_RESTART));
+
+ // WHEN
+ m_glHelper.enablePrimitiveRestart(883);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_PRIMITIVE_RESTART));
+ GLint restartIndex = 0;
+ m_func->glGetIntegerv(GL_PRIMITIVE_RESTART_INDEX, &restartIndex);
+ QCOMPARE(restartIndex, 883);
+
+ // Restore
+ m_func->glDisable(GL_PRIMITIVE_RESTART);
+ }
+
+ void frontFace()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ m_func->glFrontFace(GL_CW);
+
+ // THEN
+ GLint face = 0;
+ m_func->glGetIntegerv(GL_FRONT_FACE, &face);
+ QCOMPARE(face, GL_CW);
+
+ // WHEN
+ m_glHelper.frontFace(GL_CCW);
+
+ // THEN
+ m_func->glGetIntegerv(GL_FRONT_FACE, &face);
+ QCOMPARE(face, GL_CCW);
+ }
+
+ void getRenderBufferDimensions()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ GLuint renderBufferId = 0;
+ m_func->glGenRenderbuffers(1, &renderBufferId);
+ QVERIFY(renderBufferId != 0);
+
+ // WHEN
+ m_func->glBindRenderbuffer(GL_RENDERBUFFER, renderBufferId);
+ m_func->glRenderbufferStorage(GL_RENDERBUFFER, GL_SRGB8_ALPHA8, 512, 512);
+ m_func->glBindRenderbuffer(GL_RENDERBUFFER, 0);
+ const QSize dimensions = m_glHelper.getRenderBufferDimensions(renderBufferId);
+
+ // THEN
+ QCOMPARE(dimensions, QSize(512, 512));
+
+ // Restore
+ m_func->glDeleteRenderbuffers(1, &renderBufferId);
+ }
+
+ void getTextureDimensions()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLTexture texture(QOpenGLTexture::Target2D);
+ texture.setSize(512, 512);
+ texture.setFormat(QOpenGLTexture::RGBA8U);
+ texture.setMinificationFilter(QOpenGLTexture::Linear);
+ texture.setMagnificationFilter(QOpenGLTexture::Linear);
+ texture.create();
+ texture.allocateStorage();
+
+ // WHEN
+ const QSize dimensions = m_glHelper.getTextureDimensions(texture.textureId(), GL_TEXTURE_2D);
+
+ // THEN
+ QCOMPARE(dimensions, QSize(512, 512));
+ }
+
+ void pointSize()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ m_func->glEnable(GL_PROGRAM_POINT_SIZE);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_PROGRAM_POINT_SIZE));
+ GLfloat size = 0;
+ m_func->glGetFloatv(GL_POINT_SIZE, &size);
+ QCOMPARE(size, 1.0f);
+
+ // WHEN
+ m_glHelper.pointSize(false, 0.5f);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_PROGRAM_POINT_SIZE));
+ m_func->glGetFloatv(GL_POINT_SIZE, &size);
+ QCOMPARE(size, 0.5f);
+ }
+
+ void maxClipPlaneCount()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ GLint maxCount = -1;
+ m_func->glGetIntegerv(GL_MAX_CLIP_PLANES, &maxCount);
+
+ // THEN
+ QCOMPARE(maxCount, m_glHelper.maxClipPlaneCount());
+ }
+
+ void programUniformBlock()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCodeUniformBuffer);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformBuffer);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ const QVector<ShaderUniformBlock> activeUniformBlocks = m_glHelper.programUniformBlocks(shaderProgram.programId());
+
+ // THEN
+ QCOMPARE(activeUniformBlocks.size(), 1);
+ const ShaderUniformBlock uniformBlock = activeUniformBlocks.first();
+
+ QCOMPARE(uniformBlock.m_activeUniformsCount, 1);
+ QCOMPARE(uniformBlock.m_name, QStringLiteral("ColorArray"));
+ QCOMPARE(uniformBlock.m_binding, 2);
+ }
+
+ void programAttributesAndLocations()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeSamplers);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ QVector<ShaderAttribute> activeAttributes = m_glHelper.programAttributesAndLocations(shaderProgram.programId());
+
+ // THEN
+ QCOMPARE(activeAttributes.size(), 2);
+ std::sort(activeAttributes.begin(), activeAttributes.end(), [] (const ShaderAttribute &a, const ShaderAttribute &b) { return a.m_location < b.m_location; });
+
+ const ShaderAttribute attribute1 = activeAttributes.at(0);
+ QCOMPARE(attribute1.m_name, QStringLiteral("vertexPosition"));
+ QCOMPARE(attribute1.m_size, 1);
+ QCOMPARE(attribute1.m_location, 1);
+ QCOMPARE(attribute1.m_type, GLenum(GL_FLOAT_VEC3));
+
+ const ShaderAttribute attribute2 = activeAttributes.at(1);
+ QCOMPARE(attribute2.m_name, QStringLiteral("vertexTexCoord"));
+ QCOMPARE(attribute2.m_size, 1);
+ QCOMPARE(attribute2.m_location, 2);
+ QCOMPARE(attribute2.m_type, GLenum(GL_FLOAT_VEC2));
+ }
+
+ void programUniformsAndLocations()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloat);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ QVector<ShaderUniform> activeUniforms = m_glHelper.programUniformsAndLocations(shaderProgram.programId());
+
+ // THEN
+ QCOMPARE(activeUniforms.size(), 4);
+ std::sort(activeUniforms.begin(), activeUniforms.end(), [] (const ShaderUniform &a, const ShaderUniform &b) { return a.m_location < b.m_location; });
+
+ const ShaderUniform uniform1 = activeUniforms.at(0);
+ QCOMPARE(uniform1.m_location, 1);
+ QCOMPARE(uniform1.m_offset, -1);
+ QCOMPARE(uniform1.m_blockIndex, -1);
+ QCOMPARE(uniform1.m_arrayStride, -1);
+ QCOMPARE(uniform1.m_matrixStride, -1);
+ QCOMPARE(uniform1.m_size, 1);
+ QCOMPARE(uniform1.m_type, GLenum(GL_FLOAT));
+ QCOMPARE(uniform1.m_name, QStringLiteral("multiplier"));
+
+ const ShaderUniform uniform2 = activeUniforms.at(1);
+ QCOMPARE(uniform2.m_location, 2);
+ QCOMPARE(uniform2.m_offset, -1);
+ QCOMPARE(uniform2.m_blockIndex, -1);
+ QCOMPARE(uniform2.m_arrayStride, -1);
+ QCOMPARE(uniform2.m_matrixStride, -1);
+ QCOMPARE(uniform2.m_size, 1);
+ QCOMPARE(uniform2.m_type, GLenum(GL_FLOAT_VEC2));
+ QCOMPARE(uniform2.m_name, QStringLiteral("multiplierVec2"));
+
+ const ShaderUniform uniform3 = activeUniforms.at(2);
+ QCOMPARE(uniform3.m_location, 3);
+ QCOMPARE(uniform3.m_offset, -1);
+ QCOMPARE(uniform3.m_blockIndex, -1);
+ QCOMPARE(uniform3.m_arrayStride, -1);
+ QCOMPARE(uniform3.m_matrixStride, -1);
+ QCOMPARE(uniform3.m_size, 1);
+ QCOMPARE(uniform3.m_type, GLenum(GL_FLOAT_VEC3));
+ QCOMPARE(uniform3.m_name, QStringLiteral("multiplierVec3"));
+
+ const ShaderUniform uniform4 = activeUniforms.at(3);
+ QCOMPARE(uniform4.m_location, 4);
+ QCOMPARE(uniform4.m_offset, -1);
+ QCOMPARE(uniform4.m_blockIndex, -1);
+ QCOMPARE(uniform4.m_arrayStride, -1);
+ QCOMPARE(uniform4.m_matrixStride, -1);
+ QCOMPARE(uniform4.m_size, 1);
+ QCOMPARE(uniform4.m_type, GLenum(GL_FLOAT_VEC4));
+ QCOMPARE(uniform4.m_name, QStringLiteral("multiplierVec4"));
+ }
+
+ void programShaderStorageBlock()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Compute, computeShader);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ const QVector<ShaderStorageBlock> activeShaderStorageBlocks = m_glHelper.programShaderStorageBlocks(shaderProgram.programId());
+
+ // THEN
+ QVERIFY(activeShaderStorageBlocks.size() == 1);
+ ShaderStorageBlock block = activeShaderStorageBlocks.first();
+ QCOMPARE(block.m_name, QStringLiteral("Particles"));
+ QCOMPARE(block.m_activeVariablesCount, 3);
+ QCOMPARE(block.m_index, 0);
+ QCOMPARE(block.m_size, (4 + 4 + 4) * 4);
+ }
+
+ void releaseFrameBufferObject()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ GLuint fboId;
+ m_func->glGenFramebuffers(1, &fboId);
+
+ // THEN
+ QVERIFY(fboId != 0);
+
+ // WHEN
+ m_glHelper.releaseFrameBufferObject(fboId);
+
+ // THEN
+ QVERIFY(!m_func->glIsFramebuffer(fboId));
+ }
+
+ void setMSAAEnabled()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ m_func->glDisable(GL_MULTISAMPLE);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_MULTISAMPLE));
+
+ // WHEN
+ m_glHelper.setMSAAEnabled(true);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_MULTISAMPLE));
+
+ // WHEN
+ m_glHelper.setMSAAEnabled(false);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_MULTISAMPLE));
+ }
+
+ void setAlphaCoverageEnabled()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ m_func->glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE));
+
+ // WHEN
+ m_glHelper.setAlphaCoverageEnabled(true);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE));
+
+ // WHEN
+ m_glHelper.setAlphaCoverageEnabled(false);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE));
+ }
+
+ void setClipPlane()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+ // Deprecated in GL 4
+ }
+
+ void setSeamlessCubemap()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ m_func->glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
+ QVERIFY(!m_func->glIsEnabled(GL_TEXTURE_CUBE_MAP_SEAMLESS));
+
+ // WHEN
+ m_glHelper.setSeamlessCubemap(true);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_TEXTURE_CUBE_MAP_SEAMLESS));
+
+ // WHEN
+ m_glHelper.setSeamlessCubemap(false);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_TEXTURE_CUBE_MAP_SEAMLESS));
+ }
+
+ void setVerticesPerPatch()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ m_func->glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_TEXTURE_CUBE_MAP_SEAMLESS));
+
+ // WHEN
+ m_glHelper.setSeamlessCubemap(true);
+
+ // THEN
+ QVERIFY(m_func->glIsEnabled(GL_TEXTURE_CUBE_MAP_SEAMLESS));
+
+ // WHEN
+ m_glHelper.setSeamlessCubemap(false);
+
+ // THEN
+ QVERIFY(!m_func->glIsEnabled(GL_TEXTURE_CUBE_MAP_SEAMLESS));
+ }
+
+ void supportsFeature()
+ {
+ for (int i = 0; i <= GraphicsHelperInterface::DrawBuffersBlend; ++i)
+ QVERIFY(m_glHelper.supportsFeature(static_cast<GraphicsHelperInterface::Feature>(i)));
+ }
+
+
+#define ADD_UNIFORM_ENTRY(FragShader, Type, Location, ComponentSize, ExpectedRawSize) \
+ QTest::newRow(#FragShader"_"#Type) << FragShader << Type << Location << ComponentSize << ExpectedRawSize;
+
+ void uniformsByteSize_data()
+ {
+ QTest::addColumn<QByteArray>("fragShader");
+ QTest::addColumn<int>("type");
+ QTest::addColumn<int>("location");
+ QTest::addColumn<int>("componentSize");
+ QTest::addColumn<int>("expectedByteSize");
+
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloat, GL_FLOAT, 1, 1, 4);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloat, GL_FLOAT_VEC2, 2, 1, 4 * 2);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloat, GL_FLOAT_VEC3, 3, 1, 4 * 3);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloat, GL_FLOAT_VEC4, 4, 1, 4 * 4);
+
+ ADD_UNIFORM_ENTRY(fragCodeUniformsInt, GL_INT, 1, 1, 4);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsInt, GL_INT_VEC2, 2, 1, 4 * 2);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsInt, GL_INT_VEC3, 3, 1, 4 * 3);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsInt, GL_INT_VEC4, 4, 1, 4 * 4);
+
+ ADD_UNIFORM_ENTRY(fragCodeUniformsUInt, GL_UNSIGNED_INT, 1, 1, 4);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsUInt, GL_UNSIGNED_INT_VEC2, 2, 1, 4 * 2);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsUInt, GL_UNSIGNED_INT_VEC3, 3, 1, 4 * 3);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsUInt, GL_UNSIGNED_INT_VEC4, 4, 1, 4 * 4);
+
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, GL_FLOAT_MAT2, 1, 1, 4 * 2 * 2);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, GL_FLOAT_MAT2x3, 2, 1, 4 * 2 * 3);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, GL_FLOAT_MAT3x2, 3, 1, 4 * 3 * 2);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, GL_FLOAT_MAT2x4, 4, 1, 4 * 2 * 4);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, GL_FLOAT_MAT4x2, 5, 1, 4 * 4 * 2);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, GL_FLOAT_MAT3, 6, 1, 4 * 3 * 3);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, GL_FLOAT_MAT3x4, 7, 1, 4 * 3 * 4);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, GL_FLOAT_MAT4x3, 8, 1, 4 * 4 * 3);
+ ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, GL_FLOAT_MAT4, 9, 1, 4 * 4 * 4);
+
+ ADD_UNIFORM_ENTRY(fragCodeSamplers, GL_SAMPLER_1D, 1, 1, 4);
+ ADD_UNIFORM_ENTRY(fragCodeSamplers, GL_SAMPLER_2D, 2, 1, 4);
+ ADD_UNIFORM_ENTRY(fragCodeSamplers, GL_SAMPLER_2D_ARRAY, 3, 1, 4);
+ ADD_UNIFORM_ENTRY(fragCodeSamplers, GL_SAMPLER_3D, 4, 1, 4);
+ ADD_UNIFORM_ENTRY(fragCodeSamplers, GL_SAMPLER_CUBE, 5, 1, 4);
+ ADD_UNIFORM_ENTRY(fragCodeSamplers, GL_SAMPLER_2D_RECT, 6, 1, 4);
+ }
+
+ void uniformsByteSize()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QFETCH(QByteArray, fragShader);
+ QFETCH(int, type);
+ QFETCH(int, location);
+ QFETCH(int, componentSize);
+ QFETCH(int, expectedByteSize);
+
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragShader);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ const QVector<ShaderUniform> activeUniforms = m_glHelper.programUniformsAndLocations(shaderProgram.programId());
+ ShaderUniform matchingUniform;
+ for (const ShaderUniform &u : activeUniforms) {
+ if (u.m_location == location) {
+ matchingUniform = u;
+ break;
+ }
+ }
+
+ // THEN
+ QCOMPARE(matchingUniform.m_location, location);
+ QCOMPARE(matchingUniform.m_type, GLuint(type));
+ QCOMPARE(matchingUniform.m_size, componentSize);
+
+ // WHEN
+ const int computedRawByteSize = m_glHelper.uniformByteSize(matchingUniform);
+
+ // THEN
+ QCOMPARE(expectedByteSize, computedRawByteSize);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void useProgram()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeFragOutputs);
+
+ // THEN
+ QVERIFY(shaderProgram.link());
+
+ GLint currentProg = 0;
+ m_func->glGetIntegerv(GL_CURRENT_PROGRAM, &currentProg);
+ QVERIFY(currentProg == 0);
+
+ // WHEN
+ m_glHelper.useProgram(shaderProgram.programId());
+
+ // THEN
+ m_func->glGetIntegerv(GL_CURRENT_PROGRAM, &currentProg);
+ QCOMPARE(GLuint(currentProg), shaderProgram.programId());
+
+ // WHEN
+ m_glHelper.useProgram(0);
+
+ // THEN
+ m_func->glGetIntegerv(GL_CURRENT_PROGRAM, &currentProg);
+ QVERIFY(currentProg == 0);
+ }
+
+ void vertexAttribDivisor()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+ }
+
+ void glUniform1fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloat);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat value = 883.0f;
+ m_glHelper.glUniform1fv(1, 1, &value);
+
+ // THEN
+ GLfloat setValue = 0.0f;
+ m_func->glGetUniformfv(shaderProgram.programId(), 1, &setValue);
+ QCOMPARE(value, setValue);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform2fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloat);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[2] = { 383.0f, 427.0f };
+ m_glHelper.glUniform2fv(2, 1, values);
+
+ // THEN
+ GLfloat setValues[2] = { 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), 2, setValues);
+ for (int i = 0; i < 2; ++i)
+ QCOMPARE(setValues[i], values[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform3fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloat);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[3] = { 572.0f, 1340.0f, 1584.0f };
+ m_glHelper.glUniform3fv(3, 1, values);
+
+ // THEN
+ GLfloat setValues[3] = { 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), 3, setValues);
+ for (int i = 0; i < 3; ++i)
+ QCOMPARE(setValues[i], values[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform4fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloat);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[4] = { 454.0f, 350.0f, 883.0f, 355.0f };
+ m_glHelper.glUniform4fv(4, 1, values);
+
+ // THEN
+ GLfloat setValues[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), 4, setValues);
+ for (int i = 0; i < 4; ++i)
+ QCOMPARE(setValues[i], values[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform1iv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsInt);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLint value = 883;
+ m_glHelper.glUniform1iv(1, 1, &value);
+
+ // THEN
+ GLint setValue = 0;
+ m_func->glGetUniformiv(shaderProgram.programId(), 1, &setValue);
+ QCOMPARE(value, setValue);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform2iv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsInt);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLint values[2] = { 383, 427 };
+ m_glHelper.glUniform2iv(2, 1, values);
+
+ // THEN
+ GLint setValues[2] = { 0, 0 };
+ m_func->glGetUniformiv(shaderProgram.programId(), 2, setValues);
+ for (int i = 0; i < 2; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform3iv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsInt);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLint values[3] = { 572, 1340, 1584 };
+ m_glHelper.glUniform3iv(3, 1, values);
+
+ // THEN
+ GLint setValues[3] = { 0, 0, 0 };
+ m_func->glGetUniformiv(shaderProgram.programId(), 3, setValues);
+ for (int i = 0; i < 3; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform4iv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsInt);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLint values[4] = { 454, 350, 883, 355 };
+ m_glHelper.glUniform4iv(4, 1, values);
+
+ // THEN
+ GLint setValues[4] = { 0, 0, 0, 0 };
+ m_func->glGetUniformiv(shaderProgram.programId(), 4, setValues);
+ for (int i = 0; i < 4; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform1uiv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsUInt);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLuint value = 883U;
+ m_glHelper.glUniform1uiv(1, 1, &value);
+
+ // THEN
+ GLuint setValue = 0U;
+ m_func->glGetUniformuiv(shaderProgram.programId(), 1, &setValue);
+ QCOMPARE(value, setValue);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform2uiv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsUInt);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLuint values[2] = { 383U, 427U };
+ m_glHelper.glUniform2uiv(2, 1, values);
+
+ // THEN
+ GLuint setValues[2] = { 0U, 0U };
+ m_func->glGetUniformuiv(shaderProgram.programId(), 2, setValues);
+ for (int i = 0; i < 2; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform3uiv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsUInt);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLuint values[3] = { 572U, 1340U, 1584U };
+ m_glHelper.glUniform3uiv(3, 1, values);
+
+ // THEN
+ GLuint setValues[3] = { 0U, 0U, 0U };
+ m_func->glGetUniformuiv(shaderProgram.programId(), 3, setValues);
+ for (int i = 0; i < 3; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniform4uiv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsUInt);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLuint values[4] = { 454U, 350U, 883U, 355U };
+ m_glHelper.glUniform4uiv(4, 1, values);
+
+ // THEN
+ GLuint setValues[4] = { 0U, 0U, 0U, 0U };
+ m_func->glGetUniformuiv(shaderProgram.programId(), 4, setValues);
+ for (int i = 0; i < 4; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix2fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[4] = { 454.0f, 350.0f, 883.0f, 355.0f };
+ m_glHelper.glUniformMatrix2fv(1, 1, values);
+
+ // THEN
+ GLfloat setValues[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), 1, setValues);
+ for (int i = 0; i < 4; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix3fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[9] = { 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f, 1200.0f, 427.0f, 396.0f };
+ m_glHelper.glUniformMatrix3fv(6, 1, values);
+
+ // THEN
+ GLfloat setValues[9] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), 6, setValues);
+ for (int i = 0; i < 9; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix4fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[16] = { 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f, 1200.0f, 427.0f, 396.0f, 1603.0f, 55.0f, 5.7, 383.0f, 6.2f, 5.3f, 327.0f };
+ m_glHelper.glUniformMatrix4fv(9, 1, values);
+
+ // THEN
+ GLfloat setValues[16] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), 9, setValues);
+ for (int i = 0; i < 16; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix2x3fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[6] = { 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f};
+ m_glHelper.glUniformMatrix2x3fv(2, 1, values);
+
+ // THEN
+ GLfloat setValues[6] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), 2, setValues);
+ for (int i = 0; i < 6; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix3x2fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[6] = { 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f};
+ m_glHelper.glUniformMatrix3x2fv(3, 1, values);
+
+ // THEN
+ GLfloat setValues[6] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), 3, setValues);
+ for (int i = 0; i < 6; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix2x4fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[8] = { 383.0f, 427.0f, 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f};
+ m_glHelper.glUniformMatrix2x4fv(4, 1, values);
+
+ // THEN
+ GLfloat setValues[8] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), 4, setValues);
+ for (int i = 0; i < 8; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix4x2fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[8] = { 383.0f, 427.0f, 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f};
+ m_glHelper.glUniformMatrix4x2fv(5, 1, values);
+
+ // THEN
+ GLfloat setValues[8] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), 5, setValues);
+ for (int i = 0; i < 8; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix3x4fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[12] = { 55.0f, 5.7, 383.0f, 6.2f, 5.3f, 383.0f, 427.0f, 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f,};
+ m_glHelper.glUniformMatrix3x4fv(7, 1, values);
+
+ // THEN
+ GLfloat setValues[12] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), 7, setValues);
+ for (int i = 0; i < 12; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+ void glUniformMatrix4x3fv()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformsFloatMatrices);
+ QVERIFY(shaderProgram.link());
+
+ // WHEN
+ m_func->glUseProgram(shaderProgram.programId());
+ GLfloat values[12] = { 55.0f, 5.7, 383.0f, 6.2f, 383.0f, 427.0f, 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f};
+ m_glHelper.glUniformMatrix4x3fv(8, 1, values);
+
+ // THEN
+ GLfloat setValues[12] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ m_func->glGetUniformfv(shaderProgram.programId(), 8, setValues);
+ for (int i = 0; i < 12; ++i)
+ QCOMPARE(values[i], setValues[i]);
+
+ // Restore
+ m_func->glUseProgram(0);
+ }
+
+#define ADD_GL_TYPE_ENTRY(Type, Expected) \
+ QTest::newRow(#Type) << Type << Expected;
+
+ void uniformTypeFromGLType_data()
+ {
+ QTest::addColumn<int>("glType");
+ QTest::addColumn<UniformType>("expected");
+
+ ADD_GL_TYPE_ENTRY(GL_FLOAT, UniformType::Float);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC2, UniformType::Vec2);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC3, UniformType::Vec3);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC3, UniformType::Vec3);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC2, UniformType::Vec2);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC3, UniformType::Vec3);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC3, UniformType::Vec3);
+ ADD_GL_TYPE_ENTRY(GL_INT, UniformType::Int);
+ ADD_GL_TYPE_ENTRY(GL_INT_VEC2, UniformType::IVec2);
+ ADD_GL_TYPE_ENTRY(GL_INT_VEC3, UniformType::IVec3);
+ ADD_GL_TYPE_ENTRY(GL_INT_VEC4, UniformType::IVec4);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT, UniformType::UInt);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_VEC2, UniformType::UIVec2);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_VEC3, UniformType::UIVec3);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_VEC4, UniformType::UIVec4);
+ ADD_GL_TYPE_ENTRY(GL_BOOL, UniformType::Bool);
+ ADD_GL_TYPE_ENTRY(GL_BOOL_VEC2, UniformType::BVec2);
+ ADD_GL_TYPE_ENTRY(GL_BOOL_VEC3, UniformType::BVec3);
+ ADD_GL_TYPE_ENTRY(GL_BOOL_VEC4, UniformType::BVec4);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT2, UniformType::Mat2);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT3, UniformType::Mat3);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT4, UniformType::Mat4);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT2x3, UniformType::Mat2x3);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT2x4, UniformType::Mat2x4);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT3x2, UniformType::Mat3x2);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT4x2, UniformType::Mat4x2);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT4x3, UniformType::Mat4x3);
+ ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT3x4, UniformType::Mat3x4);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_1D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_1D_ARRAY, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_1D_SHADOW, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_2D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_2D_ARRAY, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_2D_RECT, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_2D_MULTISAMPLE, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_2D_MULTISAMPLE_ARRAY, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_2D_SHADOW, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_2D_ARRAY_SHADOW, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_3D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_CUBE, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_CUBE_SHADOW, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_CUBE_MAP_ARRAY, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_SAMPLER_BUFFER, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_INT_SAMPLER_1D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_INT_SAMPLER_2D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_INT_SAMPLER_3D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_INT_SAMPLER_BUFFER, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_INT_SAMPLER_2D_ARRAY, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_INT_SAMPLER_2D_MULTISAMPLE, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_INT_SAMPLER_CUBE, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_INT_SAMPLER_CUBE_MAP_ARRAY, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_SAMPLER_1D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_SAMPLER_2D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_SAMPLER_3D, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_SAMPLER_BUFFER, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_SAMPLER_2D_ARRAY, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_SAMPLER_CUBE, UniformType::Sampler);
+ ADD_GL_TYPE_ENTRY(GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY, UniformType::Sampler);
+ }
+
+ void uniformTypeFromGLType()
+ {
+ // GIVEN
+ QFETCH(int, glType);
+ QFETCH(UniformType, expected);
+
+ // WHEN
+ UniformType computed = m_glHelper.uniformTypeFromGLType(glType);
+
+ // THEN
+ QCOMPARE(computed, expected);
+ }
+
+private:
+ QScopedPointer<QWindow> m_window;
+ QOpenGLContext m_glContext;
+ GraphicsHelperGL4 m_glHelper;
+ QOpenGLFunctions_4_3_Core *m_func = nullptr;
+ bool m_initializationSuccessful = false;
+};
+
+#endif
+
+QT_BEGIN_NAMESPACE
+QTEST_ADD_GPU_BLACKLIST_SUPPORT_DEFS
+QT_END_NAMESPACE
+
+int main(int argc, char *argv[])
+{
+#ifdef TEST_SHOULD_BE_PERFORMED
+ QGuiApplication app(argc, argv);
+ app.setAttribute(Qt::AA_Use96Dpi, true);
+ QTEST_ADD_GPU_BLACKLIST_SUPPORT
+ tst_GraphicsHelperGL4 tc;
+ QTEST_SET_MAIN_SOURCE_PATH
+ return QTest::qExec(&tc, argc, argv);
+#endif
+ return 0;
+}
+
+#ifdef TEST_SHOULD_BE_PERFORMED
+#include "tst_graphicshelpergl4.moc"
+#endif
diff --git a/tests/auto/render/qray3d/tst_qray3d.cpp b/tests/auto/render/qray3d/tst_qray3d.cpp
index 6297f1c73..d01156832 100644
--- a/tests/auto/render/qray3d/tst_qray3d.cpp
+++ b/tests/auto/render/qray3d/tst_qray3d.cpp
@@ -238,10 +238,10 @@ void tst_QRay3D::point()
QFETCH(QVector3D, point_on_line_pos_0_6);
QFETCH(QVector3D, point_on_line_neg_7_2);
Qt3DRender::QRay3D line(point, direction);
- QVERIFY(fuzzyCompare(line.point(0.6), point_on_line_pos_0_6));
- QVERIFY(fuzzyCompare(line.point(-7.2), point_on_line_neg_7_2));
- QVERIFY(fuzzyCompare(line.projectedDistance(point_on_line_pos_0_6), 0.6));
- QVERIFY(fuzzyCompare(line.projectedDistance(point_on_line_neg_7_2), -7.2));
+ QVERIFY(fuzzyCompare(line.point(0.6f), point_on_line_pos_0_6));
+ QVERIFY(fuzzyCompare(line.point(-7.2f), point_on_line_neg_7_2));
+ QVERIFY(fuzzyCompare(line.projectedDistance(point_on_line_pos_0_6), 0.6f));
+ QVERIFY(fuzzyCompare(line.projectedDistance(point_on_line_neg_7_2), -7.2f));
}
void tst_QRay3D::contains_point_data()
diff --git a/tests/auto/render/raycasting/tst_raycasting.cpp b/tests/auto/render/raycasting/tst_raycasting.cpp
index 04274f67a..49341a4c5 100644
--- a/tests/auto/render/raycasting/tst_raycasting.cpp
+++ b/tests/auto/render/raycasting/tst_raycasting.cpp
@@ -313,7 +313,7 @@ void tst_RayCasting::mousePicking()
Qt3DRender::QCamera camera;
camera.setProjectionType(QCameraLens::PerspectiveProjection);
camera.setFieldOfView(45.0f);
- camera.setAspectRatio(800.0/600.0f);
+ camera.setAspectRatio(800.0f/600.0f);
camera.setNearPlane(0.1f);
camera.setFarPlane(1000.0f);
camera.setPosition(QVector3D(0.0f, 0.0f, -40.0f));
diff --git a/tests/auto/render/render.pro b/tests/auto/render/render.pro
index 69080ea47..df155d9a3 100644
--- a/tests/auto/render/render.pro
+++ b/tests/auto/render/render.pro
@@ -60,5 +60,10 @@ qtConfig(private_tests) {
qcomputecommand \
loadscenejob \
qrendercapture \
- uniform
+ uniform \
+ graphicshelpergl3_3 \
+ graphicshelpergl3_2 \
+ graphicshelpergl2
+
+ !macos: SUBDIRS += graphicshelpergl4
}
diff --git a/tests/auto/render/triangleboundingvolume/tst_triangleboundingvolume.cpp b/tests/auto/render/triangleboundingvolume/tst_triangleboundingvolume.cpp
index ea9ccc2f5..9ffc26973 100644
--- a/tests/auto/render/triangleboundingvolume/tst_triangleboundingvolume.cpp
+++ b/tests/auto/render/triangleboundingvolume/tst_triangleboundingvolume.cpp
@@ -104,7 +104,7 @@ private Q_SLOTS:
Qt3DRender::QCamera camera;
camera.setProjectionType(Qt3DRender::QCameraLens::PerspectiveProjection);
camera.setFieldOfView(45.0f);
- camera.setAspectRatio(800.0/600.0f);
+ camera.setAspectRatio(800.0f/600.0f);
camera.setNearPlane(0.1f);
camera.setFarPlane(1000.0f);
camera.setPosition(QVector3D(0.0f, 0.0f, 40.0f));
diff --git a/tests/auto/render/uniform/tst_uniform.cpp b/tests/auto/render/uniform/tst_uniform.cpp
index 4a7f086e9..255b79646 100644
--- a/tests/auto/render/uniform/tst_uniform.cpp
+++ b/tests/auto/render/uniform/tst_uniform.cpp
@@ -254,6 +254,30 @@ private Q_SLOTS:
QCOMPARE(v.constData<float>()[2], 454.0f);
QCOMPARE(v.constData<float>()[3], 1584.0f);
}
+ {
+ // GIVEN
+ UniformValue v = UniformValue::fromVariant(QVariant::fromValue(QMatrix4x4()));
+ // THEN
+ QCOMPARE(v.constData<float>()[ 0], 1.0f);
+ QCOMPARE(v.constData<float>()[ 1], 0.0f);
+ QCOMPARE(v.constData<float>()[ 2], 0.0f);
+ QCOMPARE(v.constData<float>()[ 3], 0.0f);
+
+ QCOMPARE(v.constData<float>()[ 4], 0.0f);
+ QCOMPARE(v.constData<float>()[ 5], 1.0f);
+ QCOMPARE(v.constData<float>()[ 6], 0.0f);
+ QCOMPARE(v.constData<float>()[ 7], 0.0f);
+
+ QCOMPARE(v.constData<float>()[ 8], 0.0f);
+ QCOMPARE(v.constData<float>()[ 9], 0.0f);
+ QCOMPARE(v.constData<float>()[10], 1.0f);
+ QCOMPARE(v.constData<float>()[11], 0.0f);
+
+ QCOMPARE(v.constData<float>()[12], 0.0f);
+ QCOMPARE(v.constData<float>()[13], 0.0f);
+ QCOMPARE(v.constData<float>()[14], 0.0f);
+ QCOMPARE(v.constData<float>()[15], 1.0f);
+ }
}
void checkComparison()
diff --git a/tests/manual/dynamicscene-cpp/examplescene.cpp b/tests/manual/dynamicscene-cpp/examplescene.cpp
index b11e2f54a..0ec2294a7 100644
--- a/tests/manual/dynamicscene-cpp/examplescene.cpp
+++ b/tests/manual/dynamicscene-cpp/examplescene.cpp
@@ -73,7 +73,7 @@ ExampleScene::~ExampleScene()
void ExampleScene::updateScene()
{
for (int i = 0; i < m_entities.size(); ++i) {
- const bool visible = (i % 2) ^ m_even;
+ const bool visible = (i % 2) ^ static_cast<int>(m_even);
m_entities[i]->setParent(visible ? this : nullptr);
}
m_even = !m_even;
diff --git a/tests/manual/skybox/Skybox.qml b/tests/manual/skybox/Skybox.qml
index 84d999771..f8a77bd65 100644
--- a/tests/manual/skybox/Skybox.qml
+++ b/tests/manual/skybox/Skybox.qml
@@ -66,12 +66,12 @@ Entity {
x: WrapMode.ClampToEdge
y: WrapMode.ClampToEdge
}
- TextureImage { face: Texture.CubeMapPositiveX; source: sourceDirectory + "_posx" + extension }
- TextureImage { face: Texture.CubeMapPositiveY; source: sourceDirectory + "_posy" + extension }
- TextureImage { face: Texture.CubeMapPositiveZ; source: sourceDirectory + "_posz" + extension }
- TextureImage { face: Texture.CubeMapNegativeX; source: sourceDirectory + "_negx" + extension }
- TextureImage { face: Texture.CubeMapNegativeY; source: sourceDirectory + "_negy" + extension }
- TextureImage { face: Texture.CubeMapNegativeZ; source: sourceDirectory + "_negz" + extension }
+ TextureImage { face: Texture.CubeMapPositiveX; mirrored: false; source: sourceDirectory + "_posx" + extension }
+ TextureImage { face: Texture.CubeMapPositiveY; mirrored: false; source: sourceDirectory + "_posy" + extension }
+ TextureImage { face: Texture.CubeMapPositiveZ; mirrored: false; source: sourceDirectory + "_posz" + extension }
+ TextureImage { face: Texture.CubeMapNegativeX; mirrored: false; source: sourceDirectory + "_negx" + extension }
+ TextureImage { face: Texture.CubeMapNegativeY; mirrored: false; source: sourceDirectory + "_negy" + extension }
+ TextureImage { face: Texture.CubeMapNegativeZ; mirrored: false; source: sourceDirectory + "_negz" + extension }
}
ShaderProgram {
diff --git a/tools/qgltf/qgltf.cpp b/tools/qgltf/qgltf.cpp
index b57ea8df2..a26fc487c 100644
--- a/tools/qgltf/qgltf.cpp
+++ b/tools/qgltf/qgltf.cpp
@@ -373,7 +373,7 @@ void Importer::delNode(Importer::Node *n)
{
if (!n)
return;
- foreach (Importer::Node *c, n->children)
+ for (Importer::Node *c : qAsConst(n->children))
delNode(c);
delete n;
}
@@ -398,10 +398,10 @@ const Importer::Node *Importer::rootNode() const
bool Importer::allMeshesForMaterialHaveTangents(uint materialIndex) const
{
- foreach (const MeshInfo &mi, m_meshInfo) {
+ for (const MeshInfo &mi : m_meshInfo) {
if (mi.materialIndex == materialIndex) {
bool hasTangents = false;
- foreach (const MeshInfo::Accessor &acc, mi.accessors) {
+ for (const MeshInfo::Accessor &acc : mi.accessors) {
if (acc.usage == QStringLiteral("TANGENT")) {
hasTangents = true;
break;
@@ -417,8 +417,8 @@ bool Importer::allMeshesForMaterialHaveTangents(uint materialIndex) const
QVector<Importer::MeshInfo::BufferView> Importer::bufferViews() const
{
QVector<Importer::MeshInfo::BufferView> bv;
- foreach (const MeshInfo &mi, m_meshInfo) {
- foreach (const MeshInfo::BufferView &v, mi.views)
+ for (const MeshInfo &mi : m_meshInfo) {
+ for (const MeshInfo::BufferView &v : mi.views)
bv << v;
}
return bv;
@@ -427,8 +427,8 @@ QVector<Importer::MeshInfo::BufferView> Importer::bufferViews() const
QVector<Importer::MeshInfo::Accessor> Importer::accessors() const
{
QVector<Importer::MeshInfo::Accessor> acc;
- foreach (const MeshInfo &mi, m_meshInfo) {
- foreach (const MeshInfo::Accessor &a, mi.accessors)
+ for (const MeshInfo &mi : m_meshInfo) {
+ for (const MeshInfo::Accessor &a : mi.accessors)
acc << a;
}
return acc;
@@ -476,7 +476,7 @@ QVector<Importer::AnimationInfo> Importer::animations() const
const Importer::Node *Importer::findNode(const Node *root, const QString &originalName) const
{
- foreach (const Node *c, root->children) {
+ for (const Node *c : root->children) {
if (c->name == originalName)
return c;
const Node *cn = findNode(c, originalName);
@@ -881,10 +881,10 @@ void AssimpImporter::buildBuffer()
if (!opts.interleave)
qDebug() << " non-interleaved layout";
QStringList sl;
- foreach (const MeshInfo::BufferView &bv, meshInfo.views) sl << bv.name;
+ for (const MeshInfo::BufferView &bv : qAsConst(meshInfo.views)) sl << bv.name;
qDebug() << " buffer views:" << sl;
sl.clear();
- foreach (const MeshInfo::Accessor &acc, meshInfo.accessors) sl << acc.name;
+ for (const MeshInfo::Accessor &acc : qAsConst(meshInfo.accessors)) sl << acc.name;
qDebug() << " accessors:" << sl;
qDebug() << " material: #" << meshInfo.materialIndex;
}
@@ -1138,7 +1138,7 @@ void AssimpImporter::parseAnimations()
m_animations << animInfo;
if (opts.showLog) {
- foreach (const KeyFrame &kf, keyFrames) {
+ for (const KeyFrame &kf : qAsConst(keyFrames)) {
QString msg;
QTextStream s(&msg);
s << " @ " << kf.t;
@@ -1185,7 +1185,7 @@ bool Exporter::nodeIsUseful(const Importer::Node *n) const
if (!n->meshes.isEmpty() || m_importer->cameraInfo().contains(n->name))
return true;
- foreach (const Importer::Node *c, n->children) {
+ for (const Importer::Node *c : n->children) {
if (nodeIsUseful(c))
return true;
}
@@ -1195,7 +1195,8 @@ bool Exporter::nodeIsUseful(const Importer::Node *n) const
void Exporter::copyExternalTextures(const QString &inputFilename)
{
- foreach (const QString &textureFilename, m_importer->externalTextures()) {
+ const auto textureFilenames = m_importer->externalTextures();
+ for (const QString &textureFilename : textureFilenames) {
const QString dst = opts.outDir + textureFilename;
m_files.insert(QFileInfo(dst).fileName());
// External textures need copying only when output dir was specified.
@@ -1213,7 +1214,8 @@ void Exporter::copyExternalTextures(const QString &inputFilename)
void Exporter::exportEmbeddedTextures()
{
#ifdef HAS_QIMAGE
- foreach (const Importer::EmbeddedTextureInfo &embTex, m_importer->embeddedTextures()) {
+ const auto embeddedTextures = m_importer->embeddedTextures();
+ for (const Importer::EmbeddedTextureInfo &embTex : embeddedTextures) {
QString fn = opts.outDir + embTex.name;
m_files.insert(QFileInfo(fn).fileName());
if (opts.showLog)
@@ -1228,13 +1230,16 @@ void Exporter::compressTextures()
if (opts.texComp != Options::ETC1)
return;
+ const auto textureFilenames = m_importer->externalTextures();
+ const auto embeddedTextures = m_importer->embeddedTextures();
QStringList imageList;
- foreach (const QString &textureFilename, m_importer->externalTextures())
+ imageList.reserve(textureFilenames.size() + embeddedTextures.size());
+ for (const QString &textureFilename : textureFilenames)
imageList << opts.outDir + textureFilename;
- foreach (const Importer::EmbeddedTextureInfo &embTex, m_importer->embeddedTextures())
+ for (const Importer::EmbeddedTextureInfo &embTex : embeddedTextures)
imageList << opts.outDir + embTex.name;
- foreach (const QString &filename, imageList) {
+ for (const QString &filename : qAsConst(imageList)) {
if (QFileInfo(filename).suffix().toLower() != QStringLiteral("png"))
continue;
QByteArray cmd = QByteArrayLiteral("etc1tool ");
@@ -1720,7 +1725,7 @@ QString GltfExporter::exportNode(const Importer::Node *n, QJsonObject &nodes)
QJsonObject node;
node["name"] = n->name;
QJsonArray children;
- foreach (const Importer::Node *c, n->children) {
+ for (const Importer::Node *c : n->children) {
if (nodeIsUseful(c))
children << exportNode(c, nodes);
}
@@ -1898,19 +1903,19 @@ void GltfExporter::exportMaterials(QJsonObject &materials, QHash<QString, QStrin
void GltfExporter::writeShader(const QString &src, const QString &dst, const QVector<QPair<QByteArray, QByteArray> > &substTab)
{
- for (size_t i = 0; i < sizeof(shaders) / sizeof(Shader); ++i) {
+ for (const Shader shader : shaders) {
QByteArray name = src.toUtf8();
- if (!qstrcmp(shaders[i].name, name.constData())) {
+ if (!qstrcmp(shader.name, name.constData())) {
QString outfn = opts.outDir + dst;
QFile outf(outfn);
if (outf.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
m_files.insert(QFileInfo(outf.fileName()).fileName());
if (opts.showLog)
qDebug() << "Writing" << outfn;
- foreach (const QString &s, QString::fromUtf8(shaders[i].text).split('\n')) {
- QString line = s;
- for (int i = 0; i < substTab.count(); ++i)
- line.replace(substTab[i].first, substTab[i].second);
+ const auto lines = QString::fromUtf8(shader.text).split('\n');
+ for (QString line : lines) {
+ for (const auto &subst : substTab)
+ line.replace(subst.first, subst.second);
line += QStringLiteral("\n");
outf.write(line.toUtf8());
}
@@ -1923,7 +1928,7 @@ void GltfExporter::writeShader(const QString &src, const QString &dst, const QVe
void GltfExporter::exportParameter(QJsonObject &dst, const QVector<ProgramInfo::Param> &params)
{
- foreach (const ProgramInfo::Param &param, params) {
+ for (const ProgramInfo::Param &param : params) {
QJsonObject parameter;
parameter["type"] = int(param.type);
if (!param.semantic.isEmpty())
@@ -1951,7 +1956,7 @@ void GltfExporter::exportTechniques(QJsonObject &obj, const QString &basename)
QJsonObject shaders;
QHash<QString, QString> shaderMap;
- foreach (ProgramInfo *prog, m_usedPrograms) {
+ for (ProgramInfo *prog : qAsConst(m_usedPrograms)) {
QString newName;
if (!shaderMap.contains(prog->vertShader)) {
QJsonObject vertexShader;
@@ -2001,47 +2006,51 @@ void GltfExporter::exportTechniques(QJsonObject &obj, const QString &basename)
obj["shaders"] = shaders;
QJsonObject programs;
- QHash<ProgramInfo *, ProgramNames> programMap;
- foreach (ProgramInfo *prog, m_usedPrograms) {
+ QHash<const ProgramInfo *, ProgramNames> programMap;
+ for (const ProgramInfo *prog : qAsConst(m_usedPrograms)) {
QJsonObject program;
program["vertexShader"] = shaderMap[prog->vertShader];
program["fragmentShader"] = shaderMap[prog->fragShader];
QJsonArray attrs;
- foreach (const ProgramInfo::Param &param, prog->attributes)
+ for (const ProgramInfo::Param &param : prog->attributes) {
attrs << param.nameInShader;
+ }
program["attributes"] = attrs;
QString programName = newProgramName();
programMap[prog].name = programName;
programs[programMap[prog].name] = program;
if (opts.genCore) {
- program["vertexShader"] = shaderMap[QString(prog->vertShader + QStringLiteral("_core"))];
- program["fragmentShader"] = shaderMap[QString(prog->fragShader + QStringLiteral("_core"))];
+ program["vertexShader"] = shaderMap[QString(prog->vertShader + QLatin1String("_core"))];
+ program["fragmentShader"] = shaderMap[QString(prog->fragShader + QLatin1String("_core"))];
QJsonArray attrs;
- foreach (const ProgramInfo::Param &param, prog->attributes)
+ for (const ProgramInfo::Param &param : prog->attributes) {
attrs << param.nameInShader;
+ }
program["attributes"] = attrs;
- programMap[prog].coreName = programName + QStringLiteral("_core");
+ programMap[prog].coreName = programName + QLatin1String("_core");
programs[programMap[prog].coreName] = program;
}
}
obj["programs"] = programs;
QJsonObject techniques;
- foreach (const TechniqueInfo &techniqueInfo, m_techniques) {
+ for (const TechniqueInfo &techniqueInfo : qAsConst(m_techniques)) {
QJsonObject technique;
QJsonObject parameters;
- ProgramInfo *prog = techniqueInfo.prog;
+ const ProgramInfo *prog = techniqueInfo.prog;
exportParameter(parameters, prog->attributes);
exportParameter(parameters, prog->uniforms);
technique["parameters"] = parameters;
technique["program"] = programMap[prog].name;
QJsonObject progAttrs;
- foreach (const ProgramInfo::Param &param, prog->attributes)
+ for (const ProgramInfo::Param &param : prog->attributes) {
progAttrs[param.nameInShader] = param.name;
+ }
technique["attributes"] = progAttrs;
QJsonObject progUniforms;
- foreach (const ProgramInfo::Param &param, prog->uniforms)
+ for (const ProgramInfo::Param &param : prog->uniforms) {
progUniforms[param.nameInShader] = param.name;
+ }
technique["uniforms"] = progUniforms;
QJsonObject states;
QJsonArray enabledStates;
@@ -2074,7 +2083,8 @@ void GltfExporter::exportAnimations(QJsonObject &obj,
QVector<Importer::MeshInfo::BufferView> &bvList,
QVector<Importer::MeshInfo::Accessor> &accList)
{
- if (m_importer->animations().isEmpty()) {
+ const auto animationInfos = m_importer->animations();
+ if (animationInfos.empty()) {
obj["animations"] = QJsonObject();
return;
}
@@ -2083,7 +2093,7 @@ void GltfExporter::exportAnimations(QJsonObject &obj,
QByteArray extraData;
int sz = 0;
- foreach (const Importer::AnimationInfo &ai, m_importer->animations())
+ for (const Importer::AnimationInfo &ai : animationInfos)
sz += ai.keyFrames.count() * (1 + 3 + 4 + 3) * sizeof(float);
extraData.resize(sz);
@@ -2091,7 +2101,7 @@ void GltfExporter::exportAnimations(QJsonObject &obj,
float *p = base;
QJsonObject animations;
- foreach (const Importer::AnimationInfo &ai, m_importer->animations()) {
+ for (const Importer::AnimationInfo &ai : animationInfos) {
QJsonObject animation;
animation["name"] = ai.name;
animation["count"] = ai.keyFrames.count();
@@ -2157,7 +2167,7 @@ void GltfExporter::exportAnimations(QJsonObject &obj,
acc.componentType = GLT_FLOAT;
acc.type = QStringLiteral("SCALAR");
acc.offset = uint((p - base) * sizeof(float));
- foreach (const Importer::KeyFrame &kf, ai.keyFrames)
+ for (const Importer::KeyFrame &kf : ai.keyFrames)
*p++ = kf.t;
parameters["TIME"] = acc.name;
accList << acc;
@@ -2168,7 +2178,7 @@ void GltfExporter::exportAnimations(QJsonObject &obj,
acc.type = QStringLiteral("VEC3");
acc.offset = uint((p - base) * sizeof(float));
QVector<float> lastV;
- foreach (const Importer::KeyFrame &kf, ai.keyFrames) {
+ for (const Importer::KeyFrame &kf : ai.keyFrames) {
const QVector<float> *v = kf.transValid ? &kf.trans : &lastV;
*p++ = v->at(0);
*p++ = v->at(1);
@@ -2185,7 +2195,7 @@ void GltfExporter::exportAnimations(QJsonObject &obj,
acc.type = QStringLiteral("VEC4");
acc.offset = uint((p - base) * sizeof(float));
QVector<float> lastV;
- foreach (const Importer::KeyFrame &kf, ai.keyFrames) {
+ for (const Importer::KeyFrame &kf : ai.keyFrames) {
const QVector<float> *v = kf.rotValid ? &kf.rot : &lastV;
*p++ = v->at(1); // x
*p++ = v->at(2); // y
@@ -2203,7 +2213,7 @@ void GltfExporter::exportAnimations(QJsonObject &obj,
acc.type = QStringLiteral("VEC3");
acc.offset = uint((p - base) * sizeof(float));
QVector<float> lastV;
- foreach (const Importer::KeyFrame &kf, ai.keyFrames) {
+ for (const Importer::KeyFrame &kf : ai.keyFrames) {
const QVector<float> *v = kf.scaleValid ? &kf.scale : &lastV;
*p++ = v->at(0);
*p++ = v->at(1);
@@ -2302,7 +2312,7 @@ void GltfExporter::save(const QString &inputFilename)
m_obj["buffers"] = buffers;
QJsonObject bufferViews;
- foreach (const Importer::MeshInfo::BufferView &bv, bvList) {
+ for (const Importer::MeshInfo::BufferView &bv : qAsConst(bvList)) {
QJsonObject bufferView;
bufferView["buffer"] = bufList[bv.bufIndex].name;
bufferView["byteLength"] = int(bv.length);
@@ -2314,7 +2324,7 @@ void GltfExporter::save(const QString &inputFilename)
m_obj["bufferViews"] = bufferViews;
QJsonObject accessors;
- foreach (const Importer::MeshInfo::Accessor &acc, accList) {
+ for (const Importer::MeshInfo::Accessor &acc : qAsConst(accList)) {
QJsonObject accessor;
accessor["bufferView"] = acc.bufferView;
accessor["byteOffset"] = int(acc.offset);
@@ -2332,14 +2342,14 @@ void GltfExporter::save(const QString &inputFilename)
QJsonObject meshes;
for (uint i = 0; i < m_importer->meshCount(); ++i) {
- Importer::MeshInfo meshInfo = m_importer->meshInfo(i);
+ const Importer::MeshInfo meshInfo = m_importer->meshInfo(i);
QJsonObject mesh;
mesh["name"] = meshInfo.originalName;
QJsonArray prims;
QJsonObject prim;
prim["mode"] = 4; // triangles
QJsonObject attrs;
- foreach (const Importer::MeshInfo::Accessor &acc, meshInfo.accessors) {
+ for (const Importer::MeshInfo::Accessor &acc : meshInfo.accessors) {
if (acc.usage != QStringLiteral("INDEX"))
attrs[acc.usage] = acc.name;
else
@@ -2354,7 +2364,8 @@ void GltfExporter::save(const QString &inputFilename)
m_obj["meshes"] = meshes;
QJsonObject cameras;
- foreach (const Importer::CameraInfo &camInfo, m_importer->cameraInfo()) {
+ const auto cameraInfos = m_importer->cameraInfo();
+ for (const Importer::CameraInfo &camInfo : cameraInfos) {
QJsonObject camera;
QJsonObject persp;
persp["aspect_ratio"] = camInfo.aspectRatio;
@@ -2369,7 +2380,7 @@ void GltfExporter::save(const QString &inputFilename)
QJsonArray sceneNodes;
QJsonObject nodes;
- foreach (const Importer::Node *n, m_importer->rootNode()->children) {
+ for (const Importer::Node *n : qAsConst(m_importer->rootNode()->children)) {
if (nodeIsUseful(n))
sceneNodes << exportNode(n, nodes);
}
@@ -2459,7 +2470,7 @@ void GltfExporter::save(const QString &inputFilename)
QByteArray pre = "<RCC><qresource prefix=\"/models\">\n";
QByteArray post = "</qresource></RCC>\n";
f.write(pre);
- foreach (const QString &file,m_files) {
+ for (const QString &file : qAsConst(m_files)) {
QString line = QString(QStringLiteral(" <file>%1</file>\n")).arg(file);
f.write(line.toUtf8());
}
@@ -2539,12 +2550,13 @@ int main(int argc, char **argv)
QDir().mkpath(opts.outDir);
}
- if (cmdLine.positionalArguments().isEmpty())
+ const auto fileNames = cmdLine.positionalArguments();
+ if (fileNames.isEmpty())
cmdLine.showHelp();
AssimpImporter importer;
GltfExporter exporter(&importer);
- foreach (const QString &fn, cmdLine.positionalArguments()) {
+ for (const QString &fn : fileNames) {
if (!importer.load(fn)) {
qWarning() << "Failed to import" << fn;
continue;
diff --git a/tools/qgltf/qgltf.pro b/tools/qgltf/qgltf.pro
index a61607204..a19f2e91c 100644
--- a/tools/qgltf/qgltf.pro
+++ b/tools/qgltf/qgltf.pro
@@ -1,6 +1,9 @@
option(host_build)
!cross_compile:load(qt_build_paths)
+# Qt3D is free of Q_FOREACH - make sure it stays that way:
+DEFINES *= QT_NO_FOREACH
+
SOURCES = qgltf.cpp
include(../../src/3rdparty/assimp/assimp_dependency.pri)