summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Krus <mike.krus@kdab.com>2019-10-03 11:10:40 +0100
committerMike Krus <mike.krus@kdab.com>2019-10-08 12:48:24 +0100
commite504957c8437a24c30a9525a04cba91c91049a4f (patch)
tree1c55bfa56d5a17e9f6452bfade4e98aff3e4d99e
parent06567dc188c9302c5f2a4f9f86e8157051448f03 (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.cpp199
-rw-r--r--src/render/geometry/skeleton_p.h31
-rw-r--r--src/render/jobs/loadskeletonjob.cpp211
-rw-r--r--src/render/jobs/loadskeletonjob_p.h18
-rw-r--r--tests/auto/render/skeleton/tst_skeleton.cpp64
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)