blob: 24d7ff6433f7dcd62224ef02564525c17833805e [file] [log] [blame]
/****************************************************************************
**
** 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 <Qt3DRender/private/shader_p.h>
#include <Qt3DRender/qshaderprogram.h>
#include <Qt3DRender/private/nodemanagers_p.h>
#include <Qt3DRender/private/qrenderaspect_p.h>
#include <Qt3DRender/qrenderaspect.h>
#include <Qt3DRender/private/geometryrenderermanager_p.h>
#include <Qt3DRender/private/buffermanager_p.h>
#include <Qt3DRender/private/geometryrenderer_p.h>
#include <Qt3DRender/private/geometry_p.h>
#include <Qt3DRender/private/buffer_p.h>
#include <Qt3DRender/private/attribute_p.h>
#include <Qt3DRender/private/triangleboundingvolume_p.h>
#include <Qt3DRender/private/trianglesextractor_p.h>
#include <Qt3DRender/qattribute.h>
#include <Qt3DRender/qbuffer.h>
#include <Qt3DRender/qgeometry.h>
#include <Qt3DRender/qgeometryrenderer.h>
#include <Qt3DCore/private/qnodevisitor_p.h>
#include <Qt3DCore/private/qnode_p.h>
Qt3DRender::QGeometryRenderer *customIndexedGeometryRenderer()
{
Qt3DRender::QGeometryRenderer *customMeshRenderer = new Qt3DRender::QGeometryRenderer;
Qt3DRender::QGeometry *customGeometry = new Qt3DRender::QGeometry(customMeshRenderer);
auto vertexDataBuffer = new Qt3DRender::QBuffer(customGeometry);
auto indexDataBuffer = new Qt3DRender::QBuffer(customGeometry);
// vec3 for position
// vec3 for colors
// vec3 for normals
/* 2
/|\
/ | \
/ /3\ \
0/___\ 1
*/
// 4 distinct vertices
QByteArray vertexBufferData;
vertexBufferData.resize(4 * (3 + 3 + 3) * sizeof(float));
// Vertices
QVector3D v0(-1.0f, 0.0f, -1.0f);
QVector3D v1(1.0f, 0.0f, -1.0f);
QVector3D v2(0.0f, 1.0f, 0.0f);
QVector3D v3(0.0f, 0.0f, 1.0f);
// Faces Normals
QVector3D n023 = QVector3D::normal(v0, v2, v3);
QVector3D n012 = QVector3D::normal(v0, v1, v2);
QVector3D n310 = QVector3D::normal(v3, v1, v0);
QVector3D n132 = QVector3D::normal(v1, v3, v2);
// Vector Normals
QVector3D n0 = QVector3D(n023 + n012 + n310).normalized();
QVector3D n1 = QVector3D(n132 + n012 + n310).normalized();
QVector3D n2 = QVector3D(n132 + n012 + n023).normalized();
QVector3D n3 = QVector3D(n132 + n310 + n023).normalized();
// Colors
QVector3D red(1.0f, 0.0f, 0.0f);
QVector3D green(0.0f, 1.0f, 0.0f);
QVector3D blue(0.0f, 0.0f, 1.0f);
QVector3D white(1.0f, 1.0f, 1.0f);
const QVector<QVector3D> vertices = QVector<QVector3D>()
<< v0 << n0 << red
<< v1 << n1 << blue
<< v2 << n2 << green
<< v3 << n3 << white;
float *rawVertexArray = reinterpret_cast<float *>(vertexBufferData.data());
int idx = 0;
for (const QVector3D &v : vertices) {
rawVertexArray[idx++] = v.x();
rawVertexArray[idx++] = v.y();
rawVertexArray[idx++] = v.z();
}
// Indices (12)
QByteArray indexBufferData;
indexBufferData.resize(4 * 3 * sizeof(ushort));
ushort *rawIndexArray = reinterpret_cast<ushort *>(indexBufferData.data());
// Front
rawIndexArray[0] = 0;
rawIndexArray[1] = 1;
rawIndexArray[2] = 2;
// Bottom
rawIndexArray[3] = 3;
rawIndexArray[4] = 1;
rawIndexArray[5] = 0;
// Left
rawIndexArray[6] = 0;
rawIndexArray[7] = 2;
rawIndexArray[8] = 3;
// Right
rawIndexArray[9] = 1;
rawIndexArray[10] = 3;
rawIndexArray[11] = 2;
vertexDataBuffer->setData(vertexBufferData);
indexDataBuffer->setData(indexBufferData);
// Attributes
Qt3DRender::QAttribute *positionAttribute = new Qt3DRender::QAttribute();
positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
positionAttribute->setBuffer(vertexDataBuffer);
positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
positionAttribute->setVertexSize(3);
positionAttribute->setByteOffset(0);
positionAttribute->setByteStride(9 * sizeof(float));
positionAttribute->setCount(4);
positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
Qt3DRender::QAttribute *normalAttribute = new Qt3DRender::QAttribute();
normalAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
normalAttribute->setBuffer(vertexDataBuffer);
normalAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
normalAttribute->setVertexSize(3);
normalAttribute->setByteOffset(3 * sizeof(float));
normalAttribute->setByteStride(9 * sizeof(float));
normalAttribute->setCount(4);
normalAttribute->setName(Qt3DRender::QAttribute::defaultNormalAttributeName());
Qt3DRender::QAttribute *colorAttribute = new Qt3DRender::QAttribute();
colorAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
colorAttribute->setBuffer(vertexDataBuffer);
colorAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
colorAttribute->setVertexSize(3);
colorAttribute->setByteOffset(6 * sizeof(float));
colorAttribute->setByteStride(9 * sizeof(float));
colorAttribute->setCount(4);
colorAttribute->setName(Qt3DRender::QAttribute::defaultColorAttributeName());
Qt3DRender::QAttribute *indexAttribute = new Qt3DRender::QAttribute();
indexAttribute->setAttributeType(Qt3DRender::QAttribute::IndexAttribute);
indexAttribute->setBuffer(indexDataBuffer);
indexAttribute->setVertexBaseType(Qt3DRender::QAttribute::UnsignedShort);
indexAttribute->setVertexSize(1);
indexAttribute->setByteOffset(0);
indexAttribute->setByteStride(0);
indexAttribute->setCount(12);
customGeometry->addAttribute(positionAttribute);
customGeometry->addAttribute(normalAttribute);
customGeometry->addAttribute(colorAttribute);
customGeometry->addAttribute(indexAttribute);
customMeshRenderer->setInstanceCount(1);
customMeshRenderer->setIndexOffset(0);
customMeshRenderer->setFirstInstance(0);
customMeshRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Triangles);
customMeshRenderer->setGeometry(customGeometry);
// 4 faces of 3 points
customMeshRenderer->setVertexCount(12);
return customMeshRenderer;
}
Qt3DRender::QGeometryRenderer *customNonIndexedGeometryRenderer()
{
Qt3DRender::QGeometryRenderer *customMeshRenderer = new Qt3DRender::QGeometryRenderer;
Qt3DRender::QGeometry *customGeometry = new Qt3DRender::QGeometry(customMeshRenderer);
auto vertexDataBuffer = new Qt3DRender::QBuffer(customGeometry);
// vec3 for position
// vec3 for colors
// vec3 for normals
/* 2
/|\
/ | \
/ /3\ \
0/___\ 1
*/
// 12 distinct vertices formaing 4 triangles
QByteArray vertexBufferData;
vertexBufferData.resize(4 * 3 * (3 + 3 + 3) * sizeof(float));
// Vertices
QVector3D v0(-1.0f, 0.0f, -1.0f);
QVector3D v1(1.0f, 0.0f, -1.0f);
QVector3D v2(0.0f, 1.0f, 0.0f);
QVector3D v3(0.0f, 0.0f, 1.0f);
// Faces Normals
QVector3D n023 = QVector3D::normal(v0, v2, v3);
QVector3D n012 = QVector3D::normal(v0, v1, v2);
QVector3D n310 = QVector3D::normal(v3, v1, v0);
QVector3D n132 = QVector3D::normal(v1, v3, v2);
// Vector Normals
QVector3D n0 = QVector3D(n023 + n012 + n310).normalized();
QVector3D n1 = QVector3D(n132 + n012 + n310).normalized();
QVector3D n2 = QVector3D(n132 + n012 + n023).normalized();
QVector3D n3 = QVector3D(n132 + n310 + n023).normalized();
// Colors
QVector3D red(1.0f, 0.0f, 0.0f);
QVector3D green(0.0f, 1.0f, 0.0f);
QVector3D blue(0.0f, 0.0f, 1.0f);
QVector3D white(1.0f, 1.0f, 1.0f);
const QVector<QVector3D> vertices = QVector<QVector3D>()
<< v0 << n0 << red
<< v1 << n1 << blue
<< v2 << n2 << green
<< v3 << n3 << white
<< v1 << n1 << blue
<< v0 << n0 << red
<< v0 << n0 << red
<< v2 << n2 << green
<< v3 << n3 << white
<< v1 << n1 << blue
<< v3 << n3 << white
<< v2 << n2 << green;
float *rawVertexArray = reinterpret_cast<float *>(vertexBufferData.data());
int idx = 0;
for (const QVector3D &v : vertices) {
rawVertexArray[idx++] = v.x();
rawVertexArray[idx++] = v.y();
rawVertexArray[idx++] = v.z();
}
vertexDataBuffer->setData(vertexBufferData);
// Attributes
Qt3DRender::QAttribute *positionAttribute = new Qt3DRender::QAttribute();
positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
positionAttribute->setBuffer(vertexDataBuffer);
positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
positionAttribute->setVertexSize(3);
positionAttribute->setByteOffset(0);
positionAttribute->setByteStride(9 * sizeof(float));
positionAttribute->setCount(12);
positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
Qt3DRender::QAttribute *normalAttribute = new Qt3DRender::QAttribute();
normalAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
normalAttribute->setBuffer(vertexDataBuffer);
normalAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
normalAttribute->setVertexSize(3);
normalAttribute->setByteOffset(3 * sizeof(float));
normalAttribute->setByteStride(9 * sizeof(float));
normalAttribute->setCount(12);
normalAttribute->setName(Qt3DRender::QAttribute::defaultNormalAttributeName());
Qt3DRender::QAttribute *colorAttribute = new Qt3DRender::QAttribute();
colorAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
colorAttribute->setBuffer(vertexDataBuffer);
colorAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
colorAttribute->setVertexSize(3);
colorAttribute->setByteOffset(6 * sizeof(float));
colorAttribute->setByteStride(9 * sizeof(float));
colorAttribute->setCount(12);
colorAttribute->setName(Qt3DRender::QAttribute::defaultColorAttributeName());
customGeometry->addAttribute(positionAttribute);
customGeometry->addAttribute(normalAttribute);
customGeometry->addAttribute(colorAttribute);
customMeshRenderer->setInstanceCount(1);
customMeshRenderer->setIndexOffset(0);
customMeshRenderer->setFirstInstance(0);
customMeshRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Triangles);
customMeshRenderer->setGeometry(customGeometry);
// 4 faces of 3 points
customMeshRenderer->setVertexCount(12);
return customMeshRenderer;
}
QT_BEGIN_NAMESPACE
class TestAspect : public Qt3DRender::QRenderAspect
{
public:
TestAspect(Qt3DCore::QNode *root)
: Qt3DRender::QRenderAspect()
{
QVector<Qt3DCore::NodeTreeChange> nodes;
Qt3DCore::QNodeVisitor v;
v.traverse(root, [&nodes](Qt3DCore::QNode *node) {
Qt3DCore::QNodePrivate *d = Qt3DCore::QNodePrivate::get(node);
d->m_typeInfo = const_cast<QMetaObject*>(Qt3DCore::QNodePrivate::findStaticMetaObject(node->metaObject()));
d->m_hasBackendNode = true;
nodes.push_back({
node->id(),
Qt3DCore::QNodePrivate::get(node)->m_typeInfo,
Qt3DCore::NodeTreeChange::Added,
node
});
});
for (const auto &node: nodes)
d_func()->createBackendNode(node);
}
~TestAspect();
Qt3DRender::Render::NodeManagers *nodeManagers() const
{
return d_func()->m_renderer->nodeManagers();
}
};
TestAspect::~TestAspect()
{
}
QT_END_NAMESPACE
class tst_TrianglesExtractor : public QObject
{
Q_OBJECT
public:
tst_TrianglesExtractor()
{
qRegisterMetaType<Qt3DCore::QNode*>();
}
private Q_SLOTS:
void triangles_data()
{
QTest::addColumn<Qt3DRender::QGeometryRenderer *>("geomRenderer");
QTest::addColumn<QVector<Qt3DRender::Render::TriangleBoundingVolume *> >("expectedVolumes");
QVector<Qt3DRender::Render::TriangleBoundingVolume *> v =
QVector<Qt3DRender::Render::TriangleBoundingVolume *>()
<< new Qt3DRender::Render::TriangleBoundingVolume(Qt3DCore::QNodeId(), Vector3D(0, 1, 0), Vector3D(1, 0, -1), Vector3D(-1, 0, -1))
<< new Qt3DRender::Render::TriangleBoundingVolume(Qt3DCore::QNodeId(), Vector3D(-1, 0, -1), Vector3D(1, 0, -1), Vector3D(0, 0, 1))
<< new Qt3DRender::Render::TriangleBoundingVolume(Qt3DCore::QNodeId(), Vector3D(0, 0, 1), Vector3D(0, 1, 0), Vector3D(-1, 0, -1))
<< new Qt3DRender::Render::TriangleBoundingVolume(Qt3DCore::QNodeId(), Vector3D(0, 1, 0), Vector3D(0, 0, 1), Vector3D(1, 0, -1));
QTest::newRow("indexedMesh") << customIndexedGeometryRenderer() << v;
QTest::newRow("nonIndexedMesh") << customNonIndexedGeometryRenderer() << v;
}
void triangles()
{
QSKIP("Deadlocks in QRenderAspect, should be fixed");
// GIVEN
QFETCH(Qt3DRender::QGeometryRenderer *, geomRenderer);
QFETCH(QVector<Qt3DRender::Render::TriangleBoundingVolume *>, expectedVolumes);
TestAspect *aspect = new TestAspect(geomRenderer);
Qt3DRender::Render::NodeManagers *manager = aspect->nodeManagers();
// WHEN
Qt3DRender::Render::GeometryRenderer *bGeomRenderer =
manager->lookupResource
<Qt3DRender::Render::GeometryRenderer,
Qt3DRender::Render::GeometryRendererManager>
(geomRenderer->id());
// THEN
QVERIFY(bGeomRenderer);
// WHEN
Qt3DRender::Render::TrianglesExtractor extractor(bGeomRenderer, manager);
QVector<Qt3DRender::RayCasting::QBoundingVolume *> volumes = extractor.extract(Qt3DCore::QNodeId());
// THEN
QVERIFY(!volumes.empty());
QCOMPARE(volumes.size(), expectedVolumes.size());
for (int i = 0, m = volumes.size(); i < m; ++i) {
const auto *expectedVolume = expectedVolumes.at(i);
const auto *actualVolume = static_cast<Qt3DRender::Render::TriangleBoundingVolume *>(volumes.at(i));
QCOMPARE(expectedVolume->id(), actualVolume->id());
QCOMPARE(expectedVolume->a(), actualVolume->a());
QCOMPARE(expectedVolume->b(), actualVolume->b());
QCOMPARE(expectedVolume->c(), actualVolume->c());
}
}
};
QTEST_MAIN(tst_TrianglesExtractor)
#include "tst_trianglesextractor.moc"