blob: 34d195221f86d637dc746ff0b2fc4e047567b8ca [file] [log] [blame]
/****************************************************************************
**
** 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 "qmlscenereader.h"
#include "testpostmanarbiter.h"
#include <QUrl>
#include <QtTest/QTest>
#include <Qt3DCore/qentity.h>
#include <Qt3DCore/qtransform.h>
#include <Qt3DCore/private/qaspectjobmanager_p.h>
#include <Qt3DCore/private/qnodevisitor_p.h>
#include <QtQuick/qquickwindow.h>
#include <Qt3DRender/QCamera>
#include <Qt3DRender/QObjectPicker>
#include <Qt3DRender/QPickEvent>
#include <Qt3DRender/QPickTriangleEvent>
#include <Qt3DRender/private/nodemanagers_p.h>
#include <Qt3DRender/private/managers_p.h>
#include <Qt3DRender/private/entity_p.h>
#include <Qt3DRender/qrenderaspect.h>
#include <Qt3DRender/private/qrenderaspect_p.h>
#include <Qt3DRender/private/pickboundingvolumejob_p.h>
#include <Qt3DRender/private/updatemeshtrianglelistjob_p.h>
#include <Qt3DRender/private/updateworldboundingvolumejob_p.h>
#include <Qt3DRender/private/updateworldtransformjob_p.h>
#include <Qt3DRender/private/expandboundingvolumejob_p.h>
#include <Qt3DRender/private/calcboundingvolumejob_p.h>
#include <Qt3DRender/private/calcgeometrytrianglevolumes_p.h>
#include <Qt3DRender/private/loadbufferjob_p.h>
#include <Qt3DRender/private/buffermanager_p.h>
#include <Qt3DRender/private/geometryrenderermanager_p.h>
#include <Qt3DRender/private/sphere_p.h>
#include <Qt3DExtras/qspheremesh.h>
#include <Qt3DExtras/qcylindermesh.h>
#include <Qt3DExtras/qtorusmesh.h>
#include <Qt3DExtras/qcuboidmesh.h>
#include <Qt3DExtras/qplanemesh.h>
#include <qbackendnodetester.h>
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
QVector<Qt3DCore::QNode *> getNodesForCreation(Qt3DCore::QNode *root)
{
using namespace Qt3DCore;
QVector<QNode *> nodes;
Qt3DCore::QNodeVisitor visitor;
visitor.traverse(root, [&nodes](QNode *node) {
nodes.append(node);
// Store the metaobject of the node in the QNode so that we have it available
// to us during destruction in the QNode destructor. This allows us to send
// the QNodeId and the metaobject as typeinfo to the backend aspects so they
// in turn can find the correct QBackendNodeMapper object to handle the destruction
// of the corresponding backend nodes.
QNodePrivate *d = QNodePrivate::get(node);
d->m_typeInfo = const_cast<QMetaObject*>(QNodePrivate::findStaticMetaObject(node->metaObject()));
// Mark this node as having been handled for creation so that it is picked up
d->m_hasBackendNode = true;
});
return nodes;
}
QVector<Qt3DCore::NodeTreeChange> nodeTreeChangesForNodes(const QVector<Qt3DCore::QNode *> nodes)
{
QVector<Qt3DCore::NodeTreeChange> nodeTreeChanges;
nodeTreeChanges.reserve(nodes.size());
for (Qt3DCore::QNode *n : nodes) {
nodeTreeChanges.push_back({
n->id(),
Qt3DCore::QNodePrivate::get(n)->m_typeInfo,
Qt3DCore::NodeTreeChange::Added,
n
});
}
return nodeTreeChanges;
}
class TestAspect : public Qt3DRender::QRenderAspect
{
public:
TestAspect(Qt3DCore::QNode *root)
: Qt3DRender::QRenderAspect(Qt3DRender::QRenderAspect::Synchronous)
, m_sceneRoot(nullptr)
{
QRenderAspect::onRegistered();
const QVector<Qt3DCore::QNode *> nodes = getNodesForCreation(root);
const QVector<Qt3DCore::NodeTreeChange> nodeTreeChanges = nodeTreeChangesForNodes(nodes);
d_func()->setRootAndCreateNodes(qobject_cast<Qt3DCore::QEntity *>(root), nodeTreeChanges);
Render::Entity *rootEntity = nodeManagers()->lookupResource<Render::Entity, Render::EntityManager>(rootEntityId());
Q_ASSERT(rootEntity);
m_sceneRoot = rootEntity;
}
~TestAspect()
{
QRenderAspect::onUnregistered();
}
void onRegistered() { QRenderAspect::onRegistered(); }
void onUnregistered() { QRenderAspect::onUnregistered(); }
Qt3DRender::Render::NodeManagers *nodeManagers() const { return d_func()->m_renderer->nodeManagers(); }
Qt3DRender::Render::FrameGraphNode *frameGraphRoot() const { return d_func()->m_renderer->frameGraphRoot(); }
Qt3DRender::Render::RenderSettings *renderSettings() const { return d_func()->m_renderer->settings(); }
Qt3DRender::Render::Entity *sceneRoot() const { return m_sceneRoot; }
Qt3DRender::Render::AbstractRenderer *renderer() const { return d_func()->m_renderer; }
private:
Render::Entity *m_sceneRoot;
};
} // namespace Qt3DRender
QT_END_NAMESPACE
namespace {
void runRequiredJobs(Qt3DRender::TestAspect *test)
{
Qt3DRender::Render::UpdateWorldTransformJob updateWorldTransform;
updateWorldTransform.setRoot(test->sceneRoot());
updateWorldTransform.setManagers(test->nodeManagers());
updateWorldTransform.run();
// For each buffer
QVector<Qt3DRender::Render::HBuffer> bufferHandles = test->nodeManagers()->bufferManager()->activeHandles();
for (auto bufferHandle : bufferHandles) {
Qt3DRender::Render::LoadBufferJob loadBuffer(bufferHandle);
loadBuffer.setNodeManager(test->nodeManagers());
loadBuffer.run();
}
Qt3DRender::Render::CalculateBoundingVolumeJob calcBVolume;
calcBVolume.setManagers(test->nodeManagers());
calcBVolume.setRoot(test->sceneRoot());
calcBVolume.run();
Qt3DRender::Render::UpdateWorldBoundingVolumeJob updateWorldBVolume;
updateWorldBVolume.setManager(test->nodeManagers()->renderNodesManager());
updateWorldBVolume.run();
Qt3DRender::Render::ExpandBoundingVolumeJob expandBVolume;
expandBVolume.setRoot(test->sceneRoot());
expandBVolume.setManagers(test->nodeManagers());
expandBVolume.run();
Qt3DRender::Render::UpdateMeshTriangleListJob updateTriangleList;
updateTriangleList.setManagers(test->nodeManagers());
updateTriangleList.run();
// For each geometry id
QVector<Qt3DRender::Render::HGeometryRenderer> geometryRenderHandles = test->nodeManagers()->geometryRendererManager()->activeHandles();
for (auto geometryRenderHandle : geometryRenderHandles) {
Qt3DCore::QNodeId geometryRendererId = test->nodeManagers()->geometryRendererManager()->data(geometryRenderHandle)->peerId();
Qt3DRender::Render::CalcGeometryTriangleVolumes calcGeometryTriangles(geometryRendererId, test->nodeManagers());
calcGeometryTriangles.run();
}
}
} // anonymous
class tst_BoundingSphere : public Qt3DCore::QBackendNodeTester
{
Q_OBJECT
private:
private Q_SLOTS:
void checkIsNull() {
auto defaultSphere = Qt3DRender::Render::Sphere();
QVERIFY(defaultSphere.isNull());
}
void remainsNotNullAfterTransform() {
QMatrix4x4 mat;
mat.translate(-5,-5,-5);
auto mMat = Matrix4x4(mat);
auto pointSphere = Qt3DRender::Render::Sphere(Vector3D(5.f,5.f,5.f),0.f);
pointSphere.transform(mMat);
QVERIFY(!pointSphere.isNull());
QVERIFY(pointSphere.center() == Vector3D(0.,0.,0));
QVERIFY(pointSphere.radius() == 0.f);
}
void remainsNullAfterTransform() {
QMatrix4x4 mat;
mat.translate(-5,-5,-5);
auto mMat = Matrix4x4(mat);
auto defaultSphere = Qt3DRender::Render::Sphere();
defaultSphere.transform(mMat);
QVERIFY(defaultSphere.isNull());
}
void expandToContainSphere() {
auto firstValidSphere = Qt3DRender::Render::Sphere(Vector3D(-10.f,-10.f,-10.f),1.f);
auto secondValidSphere = Qt3DRender::Render::Sphere(Vector3D(10.f,10.f,10.f),1.f);
firstValidSphere.expandToContain(secondValidSphere);
QVERIFY(firstValidSphere.center()==Vector3D(0.f,0.f,0.f));
float dist = static_cast<float>((2 + sqrt(3.*(20)*(20)))/2.);
QVERIFY(qFuzzyCompare(firstValidSphere.radius(), dist));
}
void expandToContainSphereOneInvalid() {
auto firstValidSphere = Qt3DRender::Render::Sphere(Vector3D(-10.f,-10.f,-10.f),1.f);
auto defaultSphere = Qt3DRender::Render::Sphere();
auto copiedSphere = firstValidSphere;
firstValidSphere.expandToContain(defaultSphere);
QVERIFY(firstValidSphere.center() == copiedSphere.center());
QVERIFY(firstValidSphere.radius() == copiedSphere.radius());
QVERIFY(!firstValidSphere.isNull());
}
void expandToContainOtherSphereInvalid() {
auto firstValidSphere = Qt3DRender::Render::Sphere(Vector3D(-10.f,-10.f,-10.f),1.f);
auto defaultSphere = Qt3DRender::Render::Sphere();
defaultSphere.expandToContain(firstValidSphere);
QVERIFY(defaultSphere.center() == firstValidSphere.center());
QVERIFY(defaultSphere.radius() == firstValidSphere.radius());
QVERIFY(!defaultSphere.isNull());
}
void expandNullSphereWithNullSphere() {
auto defaultSphere = Qt3DRender::Render::Sphere();
auto otherDefaultSphere = Qt3DRender::Render::Sphere();
defaultSphere.expandToContain(otherDefaultSphere);
QVERIFY(defaultSphere.isNull());
}
void expandToContainPoint() {
auto firstValidSphere = Qt3DRender::Render::Sphere(Vector3D(-10.f,-10.f,-10.f),1.f);
firstValidSphere.expandToContain(Vector3D(0,0,0));
QVERIFY(!firstValidSphere.isNull());
float expectedRadius = static_cast<float>((1 + qSqrt(3.*(10)*(10)))/2.);
QVERIFY(qFuzzyCompare(firstValidSphere.radius(), expectedRadius));
}
void nullSphereExpandToContainPoint() {
auto defaultSphere = Qt3DRender::Render::Sphere();
defaultSphere.expandToContain(Vector3D(5,5,5));
QVERIFY(!defaultSphere.isNull());
QVERIFY(defaultSphere.center() == Vector3D(5,5,5));
QVERIFY(qFuzzyIsNull(defaultSphere.radius()));
}
void nullSphereExpandToOrigin() {
auto defaultSphere = Qt3DRender::Render::Sphere();
defaultSphere.expandToContain(Vector3D(0,0,0));
QVERIFY(!defaultSphere.isNull());
QVERIFY(defaultSphere.center() == Vector3D(0,0,0));
QVERIFY(qFuzzyIsNull(defaultSphere.radius()));
}
void ritterSphereCubePoints() {
QVector<Vector3D> cubePts={
Vector3D(-0.5, -0.5, 0.5),
Vector3D( 0.5, -0.5, -0.5),
Vector3D(-0.5, 0.5, -0.5),
Vector3D( 0.5, 0.5, -0.5),
Vector3D(-0.5, -0.5, -0.5),
Vector3D( 0.5, -0.5, 0.5),
Vector3D(-0.5, 0.5, 0.5),
Vector3D( 0.5, 0.5, 0.5)
};
auto ritterSphere=Qt3DRender::Render::Sphere::fromPoints(cubePts);
QVERIFY(!ritterSphere.isNull());
QVERIFY(qFuzzyIsNull(ritterSphere.center().x()));
QVERIFY(qFuzzyIsNull(ritterSphere.center().y()));
QVERIFY(qFuzzyIsNull(ritterSphere.center().z()));
QVERIFY(qFuzzyCompare(ritterSphere.radius(), static_cast<float>(qSqrt(3)/2)));
}
void ritterSphereRandomPoints() {
QVector<Vector3D> randomPts={
Vector3D(-81, 55, 46),
Vector3D(-91, -73, -42),
Vector3D(-50, -76, -77),
Vector3D(-40, 63, 58),
Vector3D(-28, -2, -57),
Vector3D(84, 17, 33),
Vector3D(53, 11, -49),
Vector3D(-7, -24, -86),
Vector3D(-89, 6, 76),
Vector3D(46, -18, -27)
};
auto ritterSphere = Qt3DRender::Render::Sphere::fromPoints(randomPts);
QVERIFY(!ritterSphere.isNull());
QVERIFY(qFuzzyCompare(ritterSphere.center().x(), 17.f));
QVERIFY(qFuzzyCompare(ritterSphere.center().y(), -29.5f));
QVERIFY(qFuzzyCompare(ritterSphere.center().z(), -22.0f));
QVERIFY(qFuzzyCompare(ritterSphere.radius(), 148.66152831179963f));
}
void ritterSphereOnePoint() {
QVector<Vector3D> singlePt={
Vector3D(-0.5, -0.5, -0.5),
};
auto ritterSphere = Qt3DRender::Render::Sphere::fromPoints(singlePt);
QVERIFY(!ritterSphere.isNull());
QVERIFY(qFuzzyCompare(ritterSphere.center().x(), -0.5f));
QVERIFY(qFuzzyCompare(ritterSphere.center().y(), -0.5f));
QVERIFY(qFuzzyCompare(ritterSphere.center().z(), -0.5f));
QVERIFY(qFuzzyIsNull(ritterSphere.radius()));
}
void checkExtraGeometries_data()
{
QTest::addColumn<QString>("qmlFile");
QTest::addColumn<QVector3D>("sphereCenter");
QTest::addColumn<float>("sphereRadius");
QTest::newRow("SphereMesh") << "qrc:/sphere.qml" << QVector3D(0.f, 0.f, 0.f) << 1.f;
QTest::newRow("CubeMesh") << "qrc:/cube.qml" << QVector3D(0.f, 0.f, 0.f) << static_cast<float>(qSqrt(3.)/2.); // not weird at all
}
void checkExtraGeometries()
{
// GIVEN
QFETCH(QString, qmlFile);
QFETCH(QVector3D, sphereCenter);
QFETCH(float, sphereRadius);
QUrl qmlUrl(qmlFile);
QmlSceneReader sceneReader(qmlUrl);
QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(sceneReader.root()));
QVERIFY(root);
QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
// Runs Required jobs
runRequiredJobs(test.data());
// THEN
QVERIFY(test->sceneRoot()->worldBoundingVolumeWithChildren());
const auto boundingSphere = test->sceneRoot()->worldBoundingVolumeWithChildren();
qDebug() << qmlFile << boundingSphere->radius() << boundingSphere->center();
QCOMPARE(boundingSphere->radius(), sphereRadius);
QVERIFY(qFuzzyIsNull(boundingSphere->center().x() - sphereCenter.x()));
QVERIFY(qFuzzyIsNull(boundingSphere->center().y() - sphereCenter.y()));
QVERIFY(qFuzzyIsNull(boundingSphere->center().z() - sphereCenter.z()));
}
void checkCustomGeometry_data()
{
QTest::addColumn<int>("drawVertexCount");
QTest::addColumn<int>("indexByteOffset");
QTest::addColumn<QVector3D>("expectedCenter");
QTest::addColumn<float>("expectedRadius");
QTest::addColumn<bool>("withPrimitiveRestart");
QTest::newRow("all") << 0 << 0 << QVector3D(0.0f, 0.0f, -75.0f) << 25.03997f << false;
QTest::newRow("first only") << 3 << 0 << QVector3D(0, 1, -100) << 1.0f << false;
QTest::newRow("second only") << 3 << int(3 * sizeof(ushort)) << QVector3D(0, -1, -50) << 1.0f << false;
QTest::newRow("all with primitive restart") << 0 << 0 << QVector3D(0.0f, 0.0f, -75.0f) << 25.03997f << true;
QTest::newRow("first only with primitive restart") << 4 << 0 << QVector3D(0, 1, -100) << 1.0f << true;
QTest::newRow("second only with primitive restart") << 4 << int(3 * sizeof(ushort)) << QVector3D(0, -1, -50) << 1.0f << true;
}
void checkCustomGeometry()
{
QFETCH(int, drawVertexCount);
QFETCH(int, indexByteOffset);
QFETCH(QVector3D, expectedCenter);
QFETCH(float, expectedRadius);
QFETCH(bool, withPrimitiveRestart);
// two triangles with different Z, and an index buffer
QByteArray vdata;
vdata.resize(6 * 3 * sizeof(float));
float *vp = reinterpret_cast<float *>(vdata.data());
*vp++ = -1.0f;
*vp++ = 1.0f;
*vp++ = -100.0f;
*vp++ = 0.0f;
*vp++ = 0.0f;
*vp++ = -100.0f;
*vp++ = 1.0f;
*vp++ = 1.0f;
*vp++ = -100.0f;
*vp++ = -1.0f;
*vp++ = -1.0f;
*vp++ = -50.0f;
*vp++ = 0.0f;
*vp++ = 0.0f;
*vp++ = -50.0f;
*vp++ = 1.0f;
*vp++ = -1.0f;
*vp++ = -50.0f;
QByteArray idata;
const int indexCount = withPrimitiveRestart ? 7 : 6;
idata.resize(indexCount * sizeof(ushort));
ushort *ip = reinterpret_cast<ushort *>(idata.data());
*ip++ = 0;
*ip++ = 1;
*ip++ = 2;
if (withPrimitiveRestart)
*ip++ = 65535;
*ip++ = 3;
*ip++ = 4;
*ip++ = 5;
QScopedPointer<Qt3DCore::QEntity> entity(new Qt3DCore::QEntity);
QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(entity.data()));
Qt3DRender::QBuffer *vbuffer = new Qt3DRender::QBuffer;
Qt3DRender::QBuffer *ibuffer = new Qt3DRender::QBuffer;
vbuffer->setData(vdata);
Qt3DRender::Render::Buffer *vbufferBackend = test->nodeManagers()->bufferManager()->getOrCreateResource(vbuffer->id());
vbufferBackend->setRenderer(test->renderer());
vbufferBackend->setManager(test->nodeManagers()->bufferManager());
simulateInitializationSync(vbuffer, vbufferBackend);
ibuffer->setData(idata);
Qt3DRender::Render::Buffer *ibufferBackend = test->nodeManagers()->bufferManager()->getOrCreateResource(ibuffer->id());
ibufferBackend->setRenderer(test->renderer());
ibufferBackend->setManager(test->nodeManagers()->bufferManager());
simulateInitializationSync(ibuffer, ibufferBackend);
Qt3DRender::QGeometry *g = new Qt3DRender::QGeometry;
for (int i = 0; i < 2; ++i)
g->addAttribute(new Qt3DRender::QAttribute);
const QVector<Qt3DRender::QAttribute *> attrs = g->attributes();
Qt3DRender::QAttribute *attr = attrs[0];
attr->setBuffer(vbuffer);
attr->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
attr->setVertexBaseType(Qt3DRender::QAttribute::Float);
attr->setVertexSize(3);
attr->setCount(6);
attr->setByteOffset(0);
attr->setByteStride(3 * sizeof(float));
attr = attrs[1];
attr->setBuffer(ibuffer);
attr->setAttributeType(Qt3DRender::QAttribute::IndexAttribute);
attr->setVertexBaseType(Qt3DRender::QAttribute::UnsignedShort);
attr->setVertexSize(1);
attr->setCount(indexCount);
attr->setByteOffset(indexByteOffset);
Qt3DRender::QGeometryRenderer *gr = new Qt3DRender::QGeometryRenderer;
gr->setVertexCount(drawVertexCount); // when 0, indexAttribute->count() is used instead
gr->setPrimitiveRestartEnabled(withPrimitiveRestart);
if (withPrimitiveRestart)
gr->setRestartIndexValue(65535);
gr->setGeometry(g);
entity->addComponent(gr);
Qt3DRender::Render::Attribute *attr0Backend = test->nodeManagers()->attributeManager()->getOrCreateResource(attrs[0]->id());
attr0Backend->setRenderer(test->renderer());
simulateInitializationSync(attrs[0], attr0Backend);
Qt3DRender::Render::Attribute *attr1Backend = test->nodeManagers()->attributeManager()->getOrCreateResource(attrs[1]->id());
attr1Backend->setRenderer(test->renderer());
simulateInitializationSync(attrs[1], attr1Backend);
Qt3DRender::Render::Geometry *gBackend = test->nodeManagers()->geometryManager()->getOrCreateResource(g->id());
gBackend->setRenderer(test->renderer());
simulateInitializationSync(g, gBackend);
Qt3DRender::Render::GeometryRenderer *grBackend = test->nodeManagers()->geometryRendererManager()->getOrCreateResource(gr->id());
grBackend->setRenderer(test->renderer());
grBackend->setManager(test->nodeManagers()->geometryRendererManager());
simulateInitializationSync(gr, grBackend);
Qt3DRender::Render::Entity *entityBackend = test->nodeManagers()->renderNodesManager()->getOrCreateResource(entity->id());
entityBackend->setRenderer(test->renderer());
simulateInitializationSync(entity.data(), entityBackend);
Qt3DRender::Render::CalculateBoundingVolumeJob calcBVolume;
calcBVolume.setManagers(test->nodeManagers());
calcBVolume.setRoot(test->sceneRoot());
calcBVolume.run();
Vector3D center = entityBackend->localBoundingVolume()->center();
float radius = entityBackend->localBoundingVolume()->radius();
qDebug() << radius << center;
QCOMPARE(radius, expectedRadius);
QCOMPARE(center.x(), expectedCenter.x());
QCOMPARE(center.y(), expectedCenter.y());
QCOMPARE(center.z(), expectedCenter.z());
}
void checkCustomPackedGeometry()
{
int drawVertexCount = 6;
QVector3D expectedCenter(0.0f, 0.0f, -75.0f);
float expectedRadius = 25.03997f;
// two triangles with different Z
QByteArray vdata;
vdata.resize(6 * 3 * sizeof(float));
float *vp = reinterpret_cast<float *>(vdata.data());
*vp++ = -1.0f;
*vp++ = 1.0f;
*vp++ = -100.0f;
*vp++ = 0.0f;
*vp++ = 0.0f;
*vp++ = -100.0f;
*vp++ = 1.0f;
*vp++ = 1.0f;
*vp++ = -100.0f;
*vp++ = -1.0f;
*vp++ = -1.0f;
*vp++ = -50.0f;
*vp++ = 0.0f;
*vp++ = 0.0f;
*vp++ = -50.0f;
*vp++ = 1.0f;
*vp++ = -1.0f;
*vp++ = -50.0f;
QScopedPointer<Qt3DCore::QEntity> entity(new Qt3DCore::QEntity);
QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(entity.data()));
Qt3DRender::QBuffer *vbuffer = new Qt3DRender::QBuffer;
vbuffer->setData(vdata);
Qt3DRender::Render::Buffer *vbufferBackend = test->nodeManagers()->bufferManager()->getOrCreateResource(vbuffer->id());
vbufferBackend->setRenderer(test->renderer());
vbufferBackend->setManager(test->nodeManagers()->bufferManager());
simulateInitializationSync(vbuffer, vbufferBackend);
Qt3DRender::QGeometry *g = new Qt3DRender::QGeometry;
g->addAttribute(new Qt3DRender::QAttribute);
const QVector<Qt3DRender::QAttribute *> attrs = g->attributes();
Qt3DRender::QAttribute *attr = attrs[0];
attr->setBuffer(vbuffer);
attr->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
attr->setVertexBaseType(Qt3DRender::QAttribute::Float);
attr->setVertexSize(3);
attr->setCount(6);
attr->setByteOffset(0);
attr->setByteStride(0);
Qt3DRender::QGeometryRenderer *gr = new Qt3DRender::QGeometryRenderer;
gr->setVertexCount(drawVertexCount);
gr->setGeometry(g);
entity->addComponent(gr);
Qt3DRender::Render::Attribute *attr0Backend = test->nodeManagers()->attributeManager()->getOrCreateResource(attrs[0]->id());
attr0Backend->setRenderer(test->renderer());
simulateInitializationSync(attrs[0], attr0Backend);
Qt3DRender::Render::Geometry *gBackend = test->nodeManagers()->geometryManager()->getOrCreateResource(g->id());
gBackend->setRenderer(test->renderer());
simulateInitializationSync(g, gBackend);
Qt3DRender::Render::GeometryRenderer *grBackend = test->nodeManagers()->geometryRendererManager()->getOrCreateResource(gr->id());
grBackend->setRenderer(test->renderer());
grBackend->setManager(test->nodeManagers()->geometryRendererManager());
simulateInitializationSync(gr, grBackend);
Qt3DRender::Render::Entity *entityBackend = test->nodeManagers()->renderNodesManager()->getOrCreateResource(entity->id());
entityBackend->setRenderer(test->renderer());
simulateInitializationSync(entity.data(), entityBackend);
Qt3DRender::Render::CalculateBoundingVolumeJob calcBVolume;
calcBVolume.setManagers(test->nodeManagers());
calcBVolume.setRoot(test->sceneRoot());
calcBVolume.run();
Vector3D center = entityBackend->localBoundingVolume()->center();
float radius = entityBackend->localBoundingVolume()->radius();
qDebug() << radius << center;
QCOMPARE(radius, expectedRadius);
QCOMPARE(center.x(), expectedCenter.x());
QCOMPARE(center.y(), expectedCenter.y());
QCOMPARE(center.z(), expectedCenter.z());
}
};
QTEST_MAIN(tst_BoundingSphere)
#include "tst_boundingsphere.moc"