summaryrefslogtreecommitdiffstats
path: root/tests/auto/extras
diff options
context:
space:
mode:
authorSean Harmer <sean.harmer@kdab.com>2016-09-30 14:34:00 +0100
committerJani Heikkinen <jani.heikkinen@qt.io>2016-10-10 05:41:44 +0000
commit7fbbcaf280618c03da22cebac690b088d2b3ba03 (patch)
tree9f773fee553d9dba52d8b75b19a7f26f8083cd12 /tests/auto/extras
parent387eebab1ea3b10d777b1c92d04804afb215c52c (diff)
Add unit test for QTorusGeometry
Also fix up some more problems with the torus. We were drawing some triangles more than once due to problems in the indexing. Fixed this by factoring out the calculations of number of vertices and triangles and takign care about needing more vertices to handle the texture coordinate wrapping at the seams but not more indices. Also renamed some members in the functors to be more consistent. Now the torus geometry should be perfect. Change-Id: I1198469531a5fd5e4ec8b86d47c9e66850fe50c7 Reviewed-by: Kevin Ottens <kevin.ottens@kdab.com>
Diffstat (limited to 'tests/auto/extras')
-rw-r--r--tests/auto/extras/extras.pro3
-rw-r--r--tests/auto/extras/qtorusgeometry/qtorusgeometry.pro12
-rw-r--r--tests/auto/extras/qtorusgeometry/tst_qtorusgeometry.cpp366
3 files changed, 380 insertions, 1 deletions
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/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"