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 /src/render/geometry | |
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>
Diffstat (limited to 'src/render/geometry')
-rw-r--r-- | src/render/geometry/skeleton.cpp | 199 | ||||
-rw-r--r-- | src/render/geometry/skeleton_p.h | 31 |
2 files changed, 21 insertions, 209 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 |