diff options
author | Mike Krus <mike.krus@kdab.com> | 2019-10-03 11:10:40 +0100 |
---|---|---|
committer | Mike Krus <mike.krus@kdab.com> | 2019-10-08 12:48:24 +0100 |
commit | e504957c8437a24c30a9525a04cba91c91049a4f (patch) | |
tree | 1c55bfa56d5a17e9f6452bfade4e98aff3e4d99e | |
parent | 06567dc188c9302c5f2a4f9f86e8157051448f03 (diff) |
Move skeleton loading code to job
Also removes last couple of messages updating backend to frontend.
Change-Id: I65056c7cf5ff06efab9c9a205f843ed882f9c0be
Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
-rw-r--r-- | src/render/geometry/skeleton.cpp | 199 | ||||
-rw-r--r-- | src/render/geometry/skeleton_p.h | 31 | ||||
-rw-r--r-- | src/render/jobs/loadskeletonjob.cpp | 211 | ||||
-rw-r--r-- | src/render/jobs/loadskeletonjob_p.h | 18 | ||||
-rw-r--r-- | tests/auto/render/skeleton/tst_skeleton.cpp | 64 |
5 files changed, 240 insertions, 283 deletions
diff --git a/src/render/geometry/skeleton.cpp b/src/render/geometry/skeleton.cpp index 2fb74d1c1..839a1a056 100644 --- a/src/render/geometry/skeleton.cpp +++ b/src/render/geometry/skeleton.cpp @@ -36,24 +36,19 @@ #include "skeleton_p.h" -#include <Qt3DCore/qjoint.h> -#include <Qt3DCore/qpropertyupdatedchange.h> - #include <QCoreApplication> #include <QFile> #include <QFileInfo> +#include <Qt3DCore/qjoint.h> #include <Qt3DRender/private/abstractrenderer_p.h> -#include <Qt3DRender/private/gltfskeletonloader_p.h> #include <Qt3DRender/private/managers_p.h> #include <Qt3DRender/private/nodemanagers_p.h> #include <Qt3DRender/private/renderlogging_p.h> -#include <Qt3DRender/private/qurlhelper_p.h> #include <Qt3DCore/private/qskeletoncreatedchange_p.h> #include <Qt3DCore/private/qskeleton_p.h> #include <Qt3DCore/private/qskeletonloader_p.h> #include <Qt3DCore/private/qmath3d_p.h> -#include <Qt3DCore/private/qabstractnodefactory_p.h> QT_BEGIN_NAMESPACE @@ -146,192 +141,8 @@ void Skeleton::syncFromFrontEnd(const QNode *frontEnd, bool firstTime) void Skeleton::setStatus(QSkeletonLoader::Status status) { - if (status != m_status) { + if (status != m_status) m_status = status; - Qt3DCore::QPropertyUpdatedChangePtr e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId()); - e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); - e->setPropertyName("status"); - e->setValue(QVariant::fromValue(m_status)); - notifyObservers(e); - } -} - -void Skeleton::loadSkeleton() -{ - qCDebug(Jobs) << Q_FUNC_INFO << m_source; - clearData(); - - // Load the data - switch (m_dataType) { - case File: - loadSkeletonFromUrl(); - break; - - case Data: - loadSkeletonFromData(); - break; - - default: - Q_UNREACHABLE(); - } - - // If using a loader inform the frontend of the status change. - // Don't bother if asked to create frontend joints though. When - // the backend gets notified of those joints we'll update the - // status at that point. - if (m_dataType == File && !m_createJoints) { - if (jointCount() == 0) - setStatus(QSkeletonLoader::Error); - else - setStatus(QSkeletonLoader::Ready); - } - - qCDebug(Jobs) << "Loaded skeleton data:" << *this; -} - -void Skeleton::loadSkeletonFromUrl() -{ - // TODO: Handle remote files - QString filePath = Qt3DRender::QUrlHelper::urlToLocalFileOrQrc(m_source); - QFileInfo info(filePath); - if (!info.exists()) { - qWarning() << "Could not open skeleton file:" << filePath; - setStatus(Qt3DCore::QSkeletonLoader::Error); - return; - } - - QFile file(filePath); - if (!file.open(QIODevice::ReadOnly)) { - qWarning() << "Could not open skeleton file:" << filePath; - setStatus(Qt3DCore::QSkeletonLoader::Error); - return; - } - - // TODO: Make plugin based for more file type support. For now gltf or native - const QString ext = info.suffix(); - if (ext == QLatin1String("gltf")) { - GLTFSkeletonLoader loader; - loader.load(&file); - m_skeletonData = loader.createSkeleton(m_name); - - // If the user has requested it, create the frontend nodes for the joints - // and send them to the (soon to be owning) QSkeletonLoader. - if (m_createJoints) { - std::unique_ptr<QJoint> rootJoint(createFrontendJoints(m_skeletonData)); - if (!rootJoint) { - qWarning() << "Failed to create frontend joints"; - setStatus(Qt3DCore::QSkeletonLoader::Error); - return; - } - - // Move the QJoint tree to the main thread and notify the - // corresponding QSkeletonLoader - const auto appThread = QCoreApplication::instance()->thread(); - rootJoint->moveToThread(appThread); - - auto e = QJointChangePtr::create(peerId()); - e->setDeliveryFlags(Qt3DCore::QSceneChange::Nodes); - e->setPropertyName("rootJoint"); - e->data = std::move(rootJoint); - notifyObservers(e); - - // Clear the skeleton data. It will be recreated from the - // frontend joints. A little bit inefficient but ensures - // that joints created this way and via QSkeleton go through - // the same code path. - m_skeletonData = SkeletonData(); - } - } else if (ext == QLatin1String("json")) { - // TODO: Support native skeleton type - } else { - qWarning() << "Unknown skeleton file type:" << ext; - setStatus(Qt3DCore::QSkeletonLoader::Error); - return; - } - m_skinningPalette.resize(m_skeletonData.joints.size()); -} - -void Skeleton::loadSkeletonFromData() -{ - // Recurse down through the joint hierarchy and process it into - // the vector of joints used within SkeletonData. The recursion - // ensures that a parent always appears before its children in - // the vector of JointInfo objects. - // - // In addition, we set up a mapping from the joint ids to the - // index of the corresponding JointInfo object in the vector. - // This will allow us to easily update entries in the vector of - // JointInfos when a Joint node marks itself as dirty. - const int rootParentIndex = -1; - processJointHierarchy(m_rootJointId, rootParentIndex, m_skeletonData); - m_skinningPalette.resize(m_skeletonData.joints.size()); -} - -Qt3DCore::QJoint *Skeleton::createFrontendJoints(const SkeletonData &skeletonData) const -{ - if (skeletonData.joints.isEmpty()) - return nullptr; - - // Create frontend joints from the joint info objects - QVector<QJoint *> frontendJoints; - const int jointCount = skeletonData.joints.size(); - frontendJoints.reserve(jointCount); - for (int i = 0; i < jointCount; ++i) { - const QMatrix4x4 &inverseBindMatrix = skeletonData.joints[i].inverseBindPose; - const QString &jointName = skeletonData.jointNames[i]; - const Qt3DCore::Sqt &localPose = skeletonData.localPoses[i]; - frontendJoints.push_back(createFrontendJoint(jointName, localPose, inverseBindMatrix)); - } - - // Now go through and resolve the parent for each joint - for (int i = 0; i < frontendJoints.size(); ++i) { - const auto parentIndex = skeletonData.joints[i].parentIndex; - if (parentIndex == -1) - continue; - - // It's not enough to just set up the QObject parent-child relationship. - // We need to explicitly add the child to the parent's list of joints so - // that information is then propagated to the backend. - frontendJoints[parentIndex]->addChildJoint(frontendJoints[i]); - } - - return frontendJoints[0]; -} - -Qt3DCore::QJoint *Skeleton::createFrontendJoint(const QString &jointName, - const Qt3DCore::Sqt &localPose, - const QMatrix4x4 &inverseBindMatrix) const -{ - auto joint = QAbstractNodeFactory::createNode<QJoint>("QJoint"); - joint->setTranslation(localPose.translation); - joint->setRotation(localPose.rotation); - joint->setScale(localPose.scale); - joint->setInverseBindMatrix(inverseBindMatrix); - joint->setName(jointName); - return joint; -} - -void Skeleton::processJointHierarchy(Qt3DCore::QNodeId jointId, - int parentJointIndex, - SkeletonData &skeletonData) -{ - // Lookup the joint, create a JointInfo, and add an entry to the index map - Joint *joint = m_renderer->nodeManagers()->jointManager()->lookupResource(jointId); - Q_ASSERT(joint); - joint->setOwningSkeleton(m_skeletonHandle); - const JointInfo jointInfo(joint, parentJointIndex); - skeletonData.joints.push_back(jointInfo); - skeletonData.localPoses.push_back(joint->localPose()); - skeletonData.jointNames.push_back(joint->name()); - - const int jointIndex = skeletonData.joints.size() - 1; - const HJoint jointHandle = m_jointManager->lookupHandle(jointId); - skeletonData.jointIndices.insert(jointHandle, jointIndex); - - // Recurse to the children - const auto childIds = joint->childJointIds(); - for (const auto childJointId : childIds) - processJointHierarchy(childJointId, jointIndex, skeletonData); } void Skeleton::clearData() @@ -343,6 +154,12 @@ void Skeleton::clearData() m_skeletonData.jointIndices.clear(); } +void Skeleton::setSkeletonData(const SkeletonData &data) +{ + m_skeletonData = data; + m_skinningPalette.resize(m_skeletonData.joints.size()); +} + // Called from UpdateSkinningPaletteJob void Skeleton::setLocalPose(HJoint jointHandle, const Qt3DCore::Sqt &localPose) { diff --git a/src/render/geometry/skeleton_p.h b/src/render/geometry/skeleton_p.h index 6bddbb93b..eb9551f07 100644 --- a/src/render/geometry/skeleton_p.h +++ b/src/render/geometry/skeleton_p.h @@ -75,6 +75,12 @@ class SkeletonManager; class Q_AUTOTEST_EXPORT Skeleton : public BackendNode { public: + enum SkeletonDataType { + Unknown, + File, + Data + }; + Skeleton(); void setSkeletonManager(SkeletonManager *skeletonManager) { m_skeletonManager = skeletonManager; } @@ -89,6 +95,8 @@ public: Qt3DCore::QSkeletonLoader::Status status() const { return m_status; } QUrl source() const { return m_source; } + SkeletonDataType dataType() const { return m_dataType; } + bool createJoints() const { return m_createJoints; } void setName(const QString &name) { m_name = name; } QString name() const { return m_name; } @@ -101,34 +109,21 @@ public: Qt3DCore::QNodeId rootJointId() const { return m_rootJointId; } // Called from jobs - void loadSkeleton(); void setLocalPose(HJoint jointHandle, const Qt3DCore::Sqt &localPose); QVector<QMatrix4x4> calculateSkinningMatrixPalette(); + void clearData(); + void setSkeletonData(const SkeletonData &data); + const SkeletonData &skeletonData() const { return m_skeletonData; } + SkeletonData skeletonData() { return m_skeletonData; } + // Allow unit tests to set the data type -#if !defined(QT_BUILD_INTERNAL) -private: -#endif - enum SkeletonDataType { - Unknown, - File, - Data - }; #if defined(QT_BUILD_INTERNAL) public: void setDataType(SkeletonDataType dataType) { m_dataType = dataType; } #endif private: - void loadSkeletonFromUrl(); - void loadSkeletonFromData(); - Qt3DCore::QJoint *createFrontendJoints(const SkeletonData &skeletonData) const; - Qt3DCore::QJoint *createFrontendJoint(const QString &jointName, - const Qt3DCore::Sqt &localPose, - const QMatrix4x4 &inverseBindMatrix) const; - void processJointHierarchy(Qt3DCore::QNodeId jointId, int parentJointIndex, SkeletonData &skeletonData); - void clearData(); - QVector<QMatrix4x4> m_skinningPalette; // QSkeletonLoader Properties diff --git a/src/render/jobs/loadskeletonjob.cpp b/src/render/jobs/loadskeletonjob.cpp index 0f38538e9..7bd54b542 100644 --- a/src/render/jobs/loadskeletonjob.cpp +++ b/src/render/jobs/loadskeletonjob.cpp @@ -35,12 +35,18 @@ ****************************************************************************/ #include "loadskeletonjob_p.h" +#include <Qt3DCore/qjoint.h> #include <Qt3DCore/qabstractskeleton.h> -#include <Qt3DCore/private/qaspectmanager_p.h> +#include <Qt3DCore/qskeletonloader.h> #include <Qt3DCore/private/qabstractskeleton_p.h> -#include <Qt3DRender/private/nodemanagers_p.h> +#include <Qt3DCore/private/qabstractnodefactory_p.h> +#include <Qt3DCore/private/qaspectmanager_p.h> +#include <Qt3DCore/private/qskeletonloader_p.h> #include <Qt3DRender/private/managers_p.h> +#include <Qt3DRender/private/nodemanagers_p.h> #include <Qt3DRender/private/job_common_p.h> +#include <Qt3DRender/private/qurlhelper_p.h> +#include <Qt3DRender/private/gltfskeletonloader_p.h> QT_BEGIN_NAMESPACE @@ -50,12 +56,13 @@ namespace Render { class LoadSkeletonJobPrivate : public Qt3DCore::QAspectJobPrivate { public: - LoadSkeletonJobPrivate() : m_backendSkeleton(nullptr) { } + LoadSkeletonJobPrivate() : m_backendSkeleton(nullptr), m_loadedRootJoint(nullptr) { } ~LoadSkeletonJobPrivate() override { } void postFrame(Qt3DCore::QAspectManager *manager) override; Skeleton *m_backendSkeleton; + Qt3DCore::QJoint* m_loadedRootJoint; }; LoadSkeletonJob::LoadSkeletonJob(const HSkeleton &handle) @@ -66,10 +73,6 @@ LoadSkeletonJob::LoadSkeletonJob(const HSkeleton &handle) SET_JOB_RUN_STAT_TYPE(this, JobTypes::LoadSkeleton, 0) } -LoadSkeletonJob::~LoadSkeletonJob() -{ -} - void LoadSkeletonJob::run() { Q_D(LoadSkeletonJob); @@ -78,8 +81,189 @@ void LoadSkeletonJob::run() Skeleton *skeleton = m_nodeManagers->skeletonManager()->data(m_handle); if (skeleton != nullptr) { d->m_backendSkeleton = skeleton; - skeleton->loadSkeleton(); + loadSkeleton(skeleton); + } +} + +void LoadSkeletonJob::loadSkeleton(Skeleton *skeleton) +{ + qCDebug(Jobs) << Q_FUNC_INFO << skeleton->source(); + skeleton->clearData(); + + // Load the data + switch (skeleton->dataType()) { + case Skeleton::File: + loadSkeletonFromUrl(skeleton); + break; + + case Skeleton::Data: + loadSkeletonFromData(skeleton); + break; + + default: + Q_UNREACHABLE(); + } + + // If using a loader inform the frontend of the status change. + // Don't bother if asked to create frontend joints though. When + // the backend gets notified of those joints we'll update the + // status at that point. + if (skeleton->dataType() == Skeleton::File && !skeleton->createJoints()) { + if (skeleton->jointCount() == 0) + skeleton->setStatus(Qt3DCore::QSkeletonLoader::Error); + else + skeleton->setStatus(Qt3DCore::QSkeletonLoader::Ready); + } + + qCDebug(Jobs) << "Loaded skeleton data:" << *skeleton; +} + +void LoadSkeletonJob::loadSkeletonFromUrl(Skeleton *skeleton) +{ + Q_D(LoadSkeletonJob); + + using namespace Qt3DCore; + + // TODO: Handle remote files + QString filePath = Qt3DRender::QUrlHelper::urlToLocalFileOrQrc(skeleton->source()); + QFileInfo info(filePath); + if (!info.exists()) { + qWarning() << "Could not open skeleton file:" << filePath; + skeleton->setStatus(Qt3DCore::QSkeletonLoader::Error); + return; + } + + QFile file(filePath); + if (!file.open(QIODevice::ReadOnly)) { + qWarning() << "Could not open skeleton file:" << filePath; + skeleton->setStatus(QSkeletonLoader::Error); + return; + } + + // TODO: Make plugin based for more file type support. For now gltf or native + const QString ext = info.suffix(); + SkeletonData skeletonData; + if (ext == QLatin1String("gltf")) { + GLTFSkeletonLoader loader; + loader.load(&file); + skeletonData = loader.createSkeleton(skeleton->name()); + + // If the user has requested it, create the frontend nodes for the joints + // and send them to the (soon to be owning) QSkeletonLoader. + if (skeleton->createJoints()) { + QJoint *rootJoint = createFrontendJoints(skeletonData); + if (!rootJoint) { + qWarning() << "Failed to create frontend joints"; + skeleton->setStatus(QSkeletonLoader::Error); + return; + } + + // Move the QJoint tree to the main thread and notify the + // corresponding QSkeletonLoader + const auto appThread = QCoreApplication::instance()->thread(); + rootJoint->moveToThread(appThread); + + d->m_loadedRootJoint = rootJoint; + + // Clear the skeleton data. It will be recreated from the + // frontend joints. A little bit inefficient but ensures + // that joints created this way and via QSkeleton go through + // the same code path. + skeletonData = SkeletonData(); + } + } else if (ext == QLatin1String("json")) { + // TODO: Support native skeleton type + } else { + qWarning() << "Unknown skeleton file type:" << ext; + skeleton->setStatus(QSkeletonLoader::Error); + return; + } + + skeleton->setSkeletonData(skeletonData); +} + +void LoadSkeletonJob::loadSkeletonFromData(Skeleton *skeleton) +{ + // Recurse down through the joint hierarchy and process it into + // the vector of joints used within SkeletonData. The recursion + // ensures that a parent always appears before its children in + // the vector of JointInfo objects. + // + // In addition, we set up a mapping from the joint ids to the + // index of the corresponding JointInfo object in the vector. + // This will allow us to easily update entries in the vector of + // JointInfos when a Joint node marks itself as dirty. + const int rootParentIndex = -1; + auto skeletonData = skeleton->skeletonData(); + processJointHierarchy(skeleton->rootJointId(), rootParentIndex, skeletonData); + skeleton->setSkeletonData(skeletonData); +} + +Qt3DCore::QJoint *LoadSkeletonJob::createFrontendJoints(const SkeletonData &skeletonData) const +{ + if (skeletonData.joints.isEmpty()) + return nullptr; + + // Create frontend joints from the joint info objects + QVector<Qt3DCore::QJoint *> frontendJoints; + const int jointCount = skeletonData.joints.size(); + frontendJoints.reserve(jointCount); + for (int i = 0; i < jointCount; ++i) { + const QMatrix4x4 &inverseBindMatrix = skeletonData.joints[i].inverseBindPose; + const QString &jointName = skeletonData.jointNames[i]; + const Qt3DCore::Sqt &localPose = skeletonData.localPoses[i]; + frontendJoints.push_back(createFrontendJoint(jointName, localPose, inverseBindMatrix)); } + + // Now go through and resolve the parent for each joint + for (int i = 0; i < frontendJoints.size(); ++i) { + const auto parentIndex = skeletonData.joints[i].parentIndex; + if (parentIndex == -1) + continue; + + // It's not enough to just set up the QObject parent-child relationship. + // We need to explicitly add the child to the parent's list of joints so + // that information is then propagated to the backend. + frontendJoints[parentIndex]->addChildJoint(frontendJoints[i]); + } + + return frontendJoints[0]; +} + +Qt3DCore::QJoint *LoadSkeletonJob::createFrontendJoint(const QString &jointName, + const Qt3DCore::Sqt &localPose, + const QMatrix4x4 &inverseBindMatrix) const +{ + auto joint = Qt3DCore::QAbstractNodeFactory::createNode<Qt3DCore::QJoint>("QJoint"); + joint->setTranslation(localPose.translation); + joint->setRotation(localPose.rotation); + joint->setScale(localPose.scale); + joint->setInverseBindMatrix(inverseBindMatrix); + joint->setName(jointName); + return joint; +} + +void LoadSkeletonJob::processJointHierarchy(Qt3DCore::QNodeId jointId, + int parentJointIndex, + SkeletonData &skeletonData) +{ + // Lookup the joint, create a JointInfo, and add an entry to the index map + Joint *joint = m_nodeManagers->jointManager()->lookupResource(jointId); + Q_ASSERT(joint); + joint->setOwningSkeleton(m_handle); + const JointInfo jointInfo(joint, parentJointIndex); + skeletonData.joints.push_back(jointInfo); + skeletonData.localPoses.push_back(joint->localPose()); + skeletonData.jointNames.push_back(joint->name()); + + const int jointIndex = skeletonData.joints.size() - 1; + const HJoint jointHandle = m_nodeManagers->jointManager()->lookupHandle(jointId); + skeletonData.jointIndices.insert(jointHandle, jointIndex); + + // Recurse to the children + const auto childIds = joint->childJointIds(); + for (const auto &childJointId : childIds) + processJointHierarchy(childJointId, jointIndex, skeletonData); } void LoadSkeletonJobPrivate::postFrame(Qt3DCore::QAspectManager *manager) @@ -97,6 +281,17 @@ void LoadSkeletonJobPrivate::postFrame(Qt3DCore::QAspectManager *manager) dnode->m_jointNames = m_backendSkeleton->jointNames(); dnode->m_localPoses = m_backendSkeleton->localPoses(); dnode->update(); + + QSkeletonLoader *loaderNode = qobject_cast<QSkeletonLoader *>(node); + if (loaderNode) { + QSkeletonLoaderPrivate *dloaderNode = static_cast<QSkeletonLoaderPrivate *>(QSkeletonLoaderPrivate::get(loaderNode)); + dloaderNode->setStatus(m_backendSkeleton->status()); + + if (m_loadedRootJoint) { + dloaderNode->m_rootJoint = m_loadedRootJoint; + m_loadedRootJoint = nullptr; + } + } } } // namespace Render diff --git a/src/render/jobs/loadskeletonjob_p.h b/src/render/jobs/loadskeletonjob_p.h index e841e5e4f..0cc09da3d 100644 --- a/src/render/jobs/loadskeletonjob_p.h +++ b/src/render/jobs/loadskeletonjob_p.h @@ -51,11 +51,15 @@ #include <Qt3DCore/qaspectjob.h> #include <QtCore/qsharedpointer.h> - +#include <Qt3DRender/private/skeletondata_p.h> #include <Qt3DRender/private/handle_types_p.h> QT_BEGIN_NAMESPACE +namespace Qt3DCore { +class QJoint; +} + namespace Qt3DRender { namespace Render { @@ -66,12 +70,22 @@ class LoadSkeletonJob : public Qt3DCore::QAspectJob { public: explicit LoadSkeletonJob(const HSkeleton &handle); - ~LoadSkeletonJob(); void setNodeManagers(NodeManagers *nodeManagers) { m_nodeManagers = nodeManagers; } protected: void run() override; + void loadSkeleton(Skeleton *skeleton); + void loadSkeletonFromUrl(Skeleton *skeleton); + void loadSkeletonFromData(Skeleton *skeleton); + Qt3DCore::QJoint *createFrontendJoints(const SkeletonData &skeletonData) const; + Qt3DCore::QJoint *createFrontendJoint(const QString &jointName, + const Qt3DCore::Sqt &localPose, + const QMatrix4x4 &inverseBindMatrix) const; + void processJointHierarchy(Qt3DCore::QNodeId jointId, + int parentJointIndex, + SkeletonData &skeletonData); + HSkeleton m_handle; NodeManagers *m_nodeManagers; diff --git a/tests/auto/render/skeleton/tst_skeleton.cpp b/tests/auto/render/skeleton/tst_skeleton.cpp index c72f98a89..6af055fb0 100644 --- a/tests/auto/render/skeleton/tst_skeleton.cpp +++ b/tests/auto/render/skeleton/tst_skeleton.cpp @@ -220,30 +220,6 @@ private Q_SLOTS: QTest::newRow("inverseBind") << m << localPose << name << joint; } - void checkCreateFrontendJoint() - { - // GIVEN - Skeleton backendSkeleton; - QFETCH(QMatrix4x4, inverseBindMatrix); - QFETCH(Qt3DCore::Sqt, localPose); - QFETCH(QString, jointName); - QFETCH(QJoint *, expectedJoint); - - // WHEN - const QJoint *actualJoint = backendSkeleton.createFrontendJoint(jointName, localPose, inverseBindMatrix); - - // THEN - QCOMPARE(actualJoint->scale(), expectedJoint->scale()); - QCOMPARE(actualJoint->rotation(), expectedJoint->rotation()); - QCOMPARE(actualJoint->translation(), expectedJoint->translation()); - QCOMPARE(actualJoint->inverseBindMatrix(), expectedJoint->inverseBindMatrix()); - QCOMPARE(actualJoint->name(), expectedJoint->name()); - - // Cleanup - delete actualJoint; - delete expectedJoint; - } - void checkCreateFrontendJoints_data() { QTest::addColumn<SkeletonData>("skeletonData"); @@ -307,46 +283,6 @@ private Q_SLOTS: QTest::newRow("deep") << skeletonData << rootJoint; } - - void checkCreateFrontendJoints() - { - // GIVEN - Skeleton backendSkeleton; - QFETCH(SkeletonData, skeletonData); - QFETCH(QJoint *, expectedRootJoint); - - // WHEN - QJoint *actualRootJoint = backendSkeleton.createFrontendJoints(skeletonData); - - // THEN - if (skeletonData.joints.isEmpty()) { - QVERIFY(actualRootJoint == expectedRootJoint); // nullptr - return; - } - - // Linearise the tree of joints and check them against the skeletonData - QVector<QJoint *> joints = linearizeTree(actualRootJoint); - QCOMPARE(joints.size(), skeletonData.joints.size()); - for (int i = 0; i < joints.size(); ++i) { - // Check the translations match - QCOMPARE(joints[i]->translation(), skeletonData.localPoses[i].translation); - } - - // Now we know the order of Joints match. Check the parents match too - for (int i = 0; i < joints.size(); ++i) { - // Get parent index from joint info - const int parentIndex = skeletonData.joints[i].parentIndex; - if (parentIndex == -1) { - QVERIFY(joints[i]->parent() == nullptr); - } else { - QCOMPARE(joints[i]->parent(), joints[parentIndex]); - } - } - - // Cleanup - delete actualRootJoint; - delete expectedRootJoint; - } }; QTEST_APPLESS_MAIN(tst_Skeleton) |