diff options
author | Liang Qi <liang.qi@qt.io> | 2016-10-11 07:49:54 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2016-10-11 07:50:07 +0200 |
commit | 8be45352146be822e45e9d563d8e74687fa0fd0e (patch) | |
tree | 1fe74c32f641480a93eb3ecba35d27196adc2629 | |
parent | d967f59602217923886478140149de8a9cad34ba (diff) | |
parent | 410e2f52e0041e695c5d5814bf67bb078b608ce3 (diff) |
Merge remote-tracking branch 'origin/5.8' into dev
Change-Id: Ic5498fa0fde2e14f46153404ebb7839523e451cd
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 Binary files differindex 58816784e..75c6c42bd 100644 --- a/examples/qt3d/audio-visualizer-qml/images/demotitle.png +++ b/examples/qt3d/audio-visualizer-qml/images/demotitle.png diff --git a/examples/qt3d/audio-visualizer-qml/images/songtitle.png b/examples/qt3d/audio-visualizer-qml/images/songtitle.png Binary files differindex 2a9961093..84efe533a 100644 --- a/examples/qt3d/audio-visualizer-qml/images/songtitle.png +++ b/examples/qt3d/audio-visualizer-qml/images/songtitle.png 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, ¤tProg); + QVERIFY(currentProg == 0); + + // WHEN + m_glHelper.useProgram(shaderProgram.programId()); + + // THEN + m_func->glGetIntegerv(GL_CURRENT_PROGRAM, ¤tProg); + QCOMPARE(GLuint(currentProg), shaderProgram.programId()); + + // WHEN + m_glHelper.useProgram(0); + + // THEN + m_func->glGetIntegerv(GL_CURRENT_PROGRAM, ¤tProg); + 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, ¤tProg); + QVERIFY(currentProg == 0); + + // WHEN + m_glHelper.useProgram(shaderProgram.programId()); + + // THEN + m_func->glGetIntegerv(GL_CURRENT_PROGRAM, ¤tProg); + QCOMPARE(GLuint(currentProg), shaderProgram.programId()); + + // WHEN + m_glHelper.useProgram(0); + + // THEN + m_func->glGetIntegerv(GL_CURRENT_PROGRAM, ¤tProg); + 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, ¤tProg); + QVERIFY(currentProg == 0); + + // WHEN + m_glHelper.useProgram(shaderProgram.programId()); + + // THEN + m_func->glGetIntegerv(GL_CURRENT_PROGRAM, ¤tProg); + QCOMPARE(GLuint(currentProg), shaderProgram.programId()); + + // WHEN + m_glHelper.useProgram(0); + + // THEN + m_func->glGetIntegerv(GL_CURRENT_PROGRAM, ¤tProg); + 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, ¤tProg); + QVERIFY(currentProg == 0); + + // WHEN + m_glHelper.useProgram(shaderProgram.programId()); + + // THEN + m_func->glGetIntegerv(GL_CURRENT_PROGRAM, ¤tProg); + QCOMPARE(GLuint(currentProg), shaderProgram.programId()); + + // WHEN + m_glHelper.useProgram(0); + + // THEN + m_func->glGetIntegerv(GL_CURRENT_PROGRAM, ¤tProg); + 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> ¶ms) { - foreach (const ProgramInfo::Param ¶m, params) { + for (const ProgramInfo::Param ¶m : 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 ¶m, prog->attributes) + for (const ProgramInfo::Param ¶m : 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 ¶m, prog->attributes) + for (const ProgramInfo::Param ¶m : 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 ¶m, prog->attributes) + for (const ProgramInfo::Param ¶m : prog->attributes) { progAttrs[param.nameInShader] = param.name; + } technique["attributes"] = progAttrs; QJsonObject progUniforms; - foreach (const ProgramInfo::Param ¶m, prog->uniforms) + for (const ProgramInfo::Param ¶m : 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) |