From f0f5a2de1da2e05e3587d2a6486687ebbe649339 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Thu, 28 Mar 2019 08:31:42 +0100 Subject: Animations: handle variable length properties For that we know determine the expected number of channel components for a given property in the frontend where we have access to both the type and the value rather than in the backend using the type only. Change-Id: I75aca20d43dd1b3db316c303af041acd557c07e4 Reviewed-by: Sean Harmer --- src/animation/backend/animationutils.cpp | 110 ++++++++++----------- src/animation/backend/animationutils_p.h | 37 ++++--- src/animation/backend/channelmapping.cpp | 5 + src/animation/backend/channelmapping_p.h | 4 + src/animation/frontend/qabstractchannelmapping_p.h | 2 +- src/animation/frontend/qchannelmapping.cpp | 78 ++++++++++++++- src/animation/frontend/qchannelmapping_p.h | 10 +- 7 files changed, 172 insertions(+), 74 deletions(-) (limited to 'src') diff --git a/src/animation/backend/animationutils.cpp b/src/animation/backend/animationutils.cpp index c876fcb87..30db10e3b 100644 --- a/src/animation/backend/animationutils.cpp +++ b/src/animation/backend/animationutils.cpp @@ -58,36 +58,6 @@ QT_BEGIN_NAMESPACE namespace Qt3DAnimation { namespace Animation { -int componentsForType(int type) -{ - int componentCount = 1; - switch (type) { - case QMetaType::Float: - case QVariant::Double: - componentCount = 1; - break; - - case QVariant::Vector2D: - componentCount = 2; - break; - - case QVariant::Vector3D: - case QVariant::Color: - componentCount = 3; - break; - - case QVariant::Vector4D: - case QVariant::Quaternion: - componentCount = 4; - break; - - default: - qWarning() << "Unhandled animation type"; - } - - return componentCount; -} - inline QVector valueToVector(const QVector3D &value) { return { value.x(), value.y(), value.z() }; @@ -178,7 +148,10 @@ double phaseFromElapsedTime(double t_current_local, later be used as part of the format vector in the formatClipResults() function to remap the channels into the standard W, X, Y, Z order required by QQuaternion. */ -ComponentIndices channelComponentsToIndices(const Channel &channel, int dataType, int offset) +ComponentIndices channelComponentsToIndices(const Channel &channel, + int dataType, + int expectedComponentCount, + int offset) { #if defined Q_COMPILER_UNIFORM_INIT static const QVector standardSuffixes = { 'X', 'Y', 'Z', 'W' }; @@ -192,20 +165,22 @@ ComponentIndices channelComponentsToIndices(const Channel &channel, int dataType switch (dataType) { case QVariant::Quaternion: - return channelComponentsToIndicesHelper(channel, dataType, offset, quaternionSuffixes); + return channelComponentsToIndicesHelper(channel, expectedComponentCount, + offset, quaternionSuffixes); case QVariant::Color: - return channelComponentsToIndicesHelper(channel, dataType, offset, colorSuffixes); + return channelComponentsToIndicesHelper(channel, expectedComponentCount, + offset, colorSuffixes); default: - return channelComponentsToIndicesHelper(channel, dataType, offset, standardSuffixes); + return channelComponentsToIndicesHelper(channel, expectedComponentCount, + offset, standardSuffixes); } } ComponentIndices channelComponentsToIndicesHelper(const Channel &channel, - int dataType, + int expectedComponentCount, int offset, const QVector &suffixes) { - const int expectedComponentCount = componentsForType(dataType); const int actualComponentCount = channel.channelComponents.size(); if (actualComponentCount != expectedComponentCount) { qWarning() << "Data type expects" << expectedComponentCount @@ -329,30 +304,44 @@ ClipResults evaluateClipAtPhase(AnimationClip *clip, float phase) return evaluateClipAtLocalTime(clip, localTime); } +template +Container mapChannelResultsToContainer(const MappingData &mappingData, + const QVector &channelResults) +{ + Container r; + r.reserve(channelResults.size()); + + const ComponentIndices channelIndices = mappingData.channelIndices; + for (const int channelIndex : channelIndices) + r.push_back(channelResults.at(channelIndex)); + + return r; +} + QVariant buildPropertyValue(const MappingData &mappingData, const QVector &channelResults) { - QVariant v; + const int vectorOfFloatType = qMetaTypeId>(); + + if (mappingData.type == vectorOfFloatType) + return QVariant::fromValue(channelResults); switch (mappingData.type) { case QMetaType::Float: case QVariant::Double: { - v = QVariant::fromValue(channelResults[mappingData.channelIndices[0]]); - break; + return QVariant::fromValue(channelResults[mappingData.channelIndices[0]]); } case QVariant::Vector2D: { const QVector2D vector(channelResults[mappingData.channelIndices[0]], channelResults[mappingData.channelIndices[1]]); - v = QVariant::fromValue(vector); - break; + return QVariant::fromValue(vector); } case QVariant::Vector3D: { const QVector3D vector(channelResults[mappingData.channelIndices[0]], channelResults[mappingData.channelIndices[1]], channelResults[mappingData.channelIndices[2]]); - v = QVariant::fromValue(vector); - break; + return QVariant::fromValue(vector); } case QVariant::Vector4D: { @@ -360,8 +349,7 @@ QVariant buildPropertyValue(const MappingData &mappingData, const QVector channelResults[mappingData.channelIndices[1]], channelResults[mappingData.channelIndices[2]], channelResults[mappingData.channelIndices[3]]); - v = QVariant::fromValue(vector); - break; + return QVariant::fromValue(vector); } case QVariant::Quaternion: { @@ -370,24 +358,28 @@ QVariant buildPropertyValue(const MappingData &mappingData, const QVector channelResults[mappingData.channelIndices[2]], channelResults[mappingData.channelIndices[3]]); q.normalize(); - v = QVariant::fromValue(q); - break; + return QVariant::fromValue(q); } case QVariant::Color: { - const QColor color = QColor::fromRgbF(channelResults[mappingData.channelIndices[0]], + const QColor color = + QColor::fromRgbF(channelResults[mappingData.channelIndices[0]], channelResults[mappingData.channelIndices[1]], channelResults[mappingData.channelIndices[2]]); - v = QVariant::fromValue(color); - break; + return QVariant::fromValue(color); } + case QVariant::List: { + const QVariantList results = mapChannelResultsToContainer( + mappingData, channelResults); + return QVariant::fromValue(results); + } default: qWarning() << "Unhandled animation type" << mappingData.type; break; } - return v; + return QVariant(); } QVector preparePropertyChanges(Qt3DCore::QNodeId animatorId, @@ -540,7 +532,11 @@ QVector buildPropertyMappings(const QVector &chann } // Try to find matching channel name and type - const ChannelNameAndType nameAndType = { mapping->channelName(), mapping->type(), mapping->peerId() }; + const ChannelNameAndType nameAndType = { mapping->channelName(), + mapping->type(), + mapping->componentCount(), + mapping->peerId() + }; const int index = channelNamesAndTypes.indexOf(nameAndType); if (index != -1) { // Do we have any animation data for this channel? If not, don't bother @@ -645,7 +641,10 @@ QVector buildRequiredChannelsAndTypes(Handler *handler, case ChannelMapping::ChannelMappingType: case ChannelMapping::CallbackMappingType: { // Get the name and type - const ChannelNameAndType nameAndType{ mapping->channelName(), mapping->type(), mappingId }; + const ChannelNameAndType nameAndType{ mapping->channelName(), + mapping->type(), + mapping->componentCount(), + mappingId }; // Add if not already contained if (!namesAndTypes.contains(nameAndType)) @@ -694,7 +693,7 @@ QVector assignChannelComponentIndices(const QVector &targetCh const int baseIndex = clip->channelComponentBaseIndex(clipChannelIndex); const auto channelIndices = channelComponentsToIndices(clip->channels()[clipChannelIndex], targetChannel.type, + targetChannel.componentCount, baseIndex); std::copy(channelIndices.begin(), channelIndices.end(), formatIt); @@ -909,7 +909,7 @@ QVector defaultValueForChannel(Handler *handler, } // Everything else gets all zeros - const int componentCount = componentsForType(channelDescription.type); + const int componentCount = mapping->componentCount(); result = QVector(componentCount, 0.0f); break; } diff --git a/src/animation/backend/animationutils_p.h b/src/animation/backend/animationutils_p.h index 42402c5ec..bded12bd2 100644 --- a/src/animation/backend/animationutils_p.h +++ b/src/animation/backend/animationutils_p.h @@ -134,7 +134,7 @@ struct ChannelNameAndType int jointIndex; Qt3DCore::QNodeId mappingId; JointTransformComponent jointTransformComponent; - float pad; // Unused + int componentCount; static const int invalidIndex = -1; @@ -145,11 +145,12 @@ struct ChannelNameAndType , jointIndex(-1) , mappingId() , jointTransformComponent(NoTransformComponent) - , pad(0) + , componentCount(-1) {} ChannelNameAndType(const QString &_name, int _type, + int componentCount, Qt3DCore::QNodeId _mappingId = Qt3DCore::QNodeId(), int _jointIndex = invalidIndex) : jointName() @@ -158,7 +159,7 @@ struct ChannelNameAndType , jointIndex(_jointIndex) , mappingId(_mappingId) , jointTransformComponent(NoTransformComponent) - , pad(0) + , componentCount(componentCount) {} ChannelNameAndType(const QString &_name, @@ -170,8 +171,20 @@ struct ChannelNameAndType , jointIndex(invalidIndex) , mappingId() , jointTransformComponent(_jointTransformComponent) - , pad(0) - {} + , componentCount(-1) + { + switch (_jointTransformComponent) { + case NoTransformComponent: + break; + case Scale: + case Translation: + componentCount = 3; + break; + case Rotation: + componentCount = 4; + break; + }; + } bool operator==(const ChannelNameAndType &rhs) const { @@ -179,7 +192,8 @@ struct ChannelNameAndType && type == rhs.type && jointIndex == rhs.jointIndex && mappingId == rhs.mappingId - && jointTransformComponent == rhs.jointTransformComponent; + && jointTransformComponent == rhs.jointTransformComponent + && componentCount == rhs.componentCount; } }; @@ -192,7 +206,8 @@ inline QDebug operator<<(QDebug dbg, const ChannelNameAndType &nameAndType) << "mappingId =" << nameAndType.mappingId << "jointIndex =" << nameAndType.jointIndex << "jointName =" << nameAndType.jointName - << "jointTransformComponent =" << nameAndType.jointTransformComponent; + << "jointTransformComponent =" << nameAndType.jointTransformComponent + << "componentCount =" << nameAndType.componentCount; return dbg; } #endif @@ -288,9 +303,6 @@ inline bool isValidNormalizedTime(float t) return !(t < 0.0f) && !(t > 1.0f); } -Q_AUTOTEST_EXPORT -int componentsForType(int type); - Q_AUTOTEST_EXPORT ClipEvaluationData evaluationDataForClip(AnimationClip *clip, const AnimatorEvaluationData &animatorData); @@ -298,11 +310,12 @@ ClipEvaluationData evaluationDataForClip(AnimationClip *clip, Q_AUTOTEST_EXPORT ComponentIndices channelComponentsToIndices(const Channel &channel, int dataType, - int offset = 0); + int expectedComponentCount, + int offset); Q_AUTOTEST_EXPORT ComponentIndices channelComponentsToIndicesHelper(const Channel &channelGroup, - int dataType, + int expectedComponentCount, int offset, const QVector &suffixes); diff --git a/src/animation/backend/channelmapping.cpp b/src/animation/backend/channelmapping.cpp index ecae8bbae..d8572a074 100644 --- a/src/animation/backend/channelmapping.cpp +++ b/src/animation/backend/channelmapping.cpp @@ -55,6 +55,7 @@ ChannelMapping::ChannelMapping() , m_targetId() , m_property() , m_type(static_cast(QVariant::Invalid)) + , m_componentCount(0) , m_propertyName(nullptr) , m_callback(nullptr) , m_callbackFlags(0) @@ -74,6 +75,7 @@ void ChannelMapping::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePt m_targetId = data.targetId; m_property = data.property; m_type = data.type; + m_componentCount = data.componentCount; m_propertyName = data.propertyName; m_mappingType = ChannelMappingType; break; @@ -108,6 +110,7 @@ void ChannelMapping::cleanup() m_property.clear(); m_type = static_cast(QVariant::Invalid); m_propertyName = nullptr; + m_componentCount = 0; m_callback = nullptr; m_callbackFlags = 0; m_skeletonId = Qt3DCore::QNodeId(); @@ -128,6 +131,8 @@ void ChannelMapping::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) m_type = change->value().toInt(); else if (change->propertyName() == QByteArrayLiteral("propertyName")) m_propertyName = static_cast(const_cast(change->value().value())); + else if (change->propertyName() == QByteArrayLiteral("componentCount")) + m_componentCount = change->value().toInt(); else if (change->propertyName() == QByteArrayLiteral("callback")) m_callback = static_cast(change->value().value()); else if (change->propertyName() == QByteArrayLiteral("callbackFlags")) diff --git a/src/animation/backend/channelmapping_p.h b/src/animation/backend/channelmapping_p.h index 82de5c7b4..5159adae2 100644 --- a/src/animation/backend/channelmapping_p.h +++ b/src/animation/backend/channelmapping_p.h @@ -93,6 +93,9 @@ public: void setPropertyName(const char *propertyName) { m_propertyName = propertyName; } const char *propertyName() const { return m_propertyName; } + void setComponentCount(int componentCount) { m_componentCount = componentCount; } + int componentCount() const { return m_componentCount; } + void setCallback(QAnimationCallback *callback) { m_callback = callback; } QAnimationCallback *callback() const { return m_callback; } @@ -114,6 +117,7 @@ private: Qt3DCore::QNodeId m_targetId; QString m_property; int m_type; + int m_componentCount; const char *m_propertyName; // TODO: Properties from QCallbackMapping diff --git a/src/animation/frontend/qabstractchannelmapping_p.h b/src/animation/frontend/qabstractchannelmapping_p.h index 1a1de4ba9..2d77ee265 100644 --- a/src/animation/frontend/qabstractchannelmapping_p.h +++ b/src/animation/frontend/qabstractchannelmapping_p.h @@ -60,7 +60,7 @@ namespace Qt3DAnimation { class QAbstractChannelMapping; -class QAbstractChannelMappingPrivate : public Qt3DCore::QNodePrivate +class Q_AUTOTEST_EXPORT QAbstractChannelMappingPrivate : public Qt3DCore::QNodePrivate { public: QAbstractChannelMappingPrivate(); diff --git a/src/animation/frontend/qchannelmapping.cpp b/src/animation/frontend/qchannelmapping.cpp index 0d9150c50..0dbe68c8c 100644 --- a/src/animation/frontend/qchannelmapping.cpp +++ b/src/animation/frontend/qchannelmapping.cpp @@ -47,6 +47,61 @@ QT_BEGIN_NAMESPACE namespace Qt3DAnimation { +namespace { + +template +int componentCountForValue(const T &) +{ + return 0; +} + +template<> +int componentCountForValue>(const QVector &v) +{ + return v.size(); +} + +template<> +int componentCountForValue(const QVariantList &v) +{ + return v.size(); +} + + +int componentCountForType(int type, const QVariant &value) +{ + const int vectorOfFloatTypeId = qMetaTypeId>(); + + if (type == vectorOfFloatTypeId) + return componentCountForValue>(value.value>()); + + switch (type) { + case QMetaType::Float: + case QVariant::Double: + return 1; + + case QVariant::Vector2D: + return 2; + + case QVariant::Vector3D: + case QVariant::Color: + return 3; + + case QVariant::Vector4D: + case QVariant::Quaternion: + return 4; + + case QVariant::List: + return componentCountForValue(value.toList()); + + default: + qWarning() << "Unhandled animation type"; + return 0; + } +} + +} // anonymous + QChannelMappingPrivate::QChannelMappingPrivate() : QAbstractChannelMappingPrivate() , m_channelName() @@ -54,6 +109,7 @@ QChannelMappingPrivate::QChannelMappingPrivate() , m_property() , m_propertyName(nullptr) , m_type(static_cast(QVariant::Invalid)) + , m_componentCount(0) { m_mappingType = QChannelMappingCreatedChangeBase::ChannelMapping; } @@ -63,9 +119,10 @@ QChannelMappingPrivate::QChannelMappingPrivate() Find the type of the property specified on the target node */ -void QChannelMappingPrivate::updatePropertyNameAndType() +void QChannelMappingPrivate::updatePropertyNameTypeAndComponentCount() { int type; + int componentCount = 0; const char *propertyName = nullptr; if (!m_target || m_property.isNull()) { @@ -76,8 +133,8 @@ void QChannelMappingPrivate::updatePropertyNameAndType() QMetaProperty mp = mo->property(propertyIndex); propertyName = mp.name(); type = mp.userType(); + const QVariant currentValue = m_target->property(mp.name()); if (type == QMetaType::QVariant) { - QVariant currentValue = m_target->property(mp.name()); if (currentValue.isValid()) { type = currentValue.userType(); } else { @@ -85,6 +142,7 @@ void QChannelMappingPrivate::updatePropertyNameAndType() "Set a value first in order to be able to determine the type."); } } + componentCount = componentCountForType(type, currentValue); } if (m_type != type) { @@ -98,6 +156,17 @@ void QChannelMappingPrivate::updatePropertyNameAndType() notifyObservers(e); } + if (m_componentCount != componentCount) { + m_componentCount = componentCount; + + // Send update to the backend + Q_Q(QChannelMapping); + auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(q->id()); + e->setPropertyName("componentCount"); + e->setValue(QVariant(m_componentCount)); + notifyObservers(e); + } + if (qstrcmp(m_propertyName, propertyName) != 0) { m_propertyName = propertyName; @@ -178,7 +247,7 @@ void QChannelMapping::setTarget(Qt3DCore::QNode *target) d->registerDestructionHelper(d->m_target, &QChannelMapping::setTarget, d->m_target); emit targetChanged(target); - d->updatePropertyNameAndType(); + d->updatePropertyNameTypeAndComponentCount(); } void QChannelMapping::setProperty(const QString &property) @@ -189,7 +258,7 @@ void QChannelMapping::setProperty(const QString &property) d->m_property = property; emit propertyChanged(property); - d->updatePropertyNameAndType(); + d->updatePropertyNameTypeAndComponentCount(); } Qt3DCore::QNodeCreatedChangeBasePtr QChannelMapping::createNodeCreationChange() const @@ -201,6 +270,7 @@ Qt3DCore::QNodeCreatedChangeBasePtr QChannelMapping::createNodeCreationChange() data.targetId = Qt3DCore::qIdForNode(d->m_target); data.property = d->m_property; data.type = d->m_type; + data.componentCount = d->m_componentCount; data.propertyName = d->m_propertyName; return creationChange; } diff --git a/src/animation/frontend/qchannelmapping_p.h b/src/animation/frontend/qchannelmapping_p.h index b7de3b821..6a3f1afc5 100644 --- a/src/animation/frontend/qchannelmapping_p.h +++ b/src/animation/frontend/qchannelmapping_p.h @@ -50,25 +50,27 @@ #include #include +#include QT_BEGIN_NAMESPACE namespace Qt3DAnimation { -class QChannelMappingPrivate : public QAbstractChannelMappingPrivate +class Q_AUTOTEST_EXPORT QChannelMappingPrivate : public QAbstractChannelMappingPrivate { public: QChannelMappingPrivate(); Q_DECLARE_PUBLIC(QChannelMapping) - void updatePropertyNameAndType(); + void updatePropertyNameTypeAndComponentCount(); QString m_channelName; Qt3DCore::QNode *m_target; QString m_property; const char *m_propertyName; int m_type; + int m_componentCount; }; struct QChannelMappingData @@ -77,6 +79,7 @@ struct QChannelMappingData Qt3DCore::QNodeId targetId; QString property; int type; + int componentCount; const char *propertyName; }; @@ -85,4 +88,7 @@ struct QChannelMappingData QT_END_NAMESPACE +// Used to define the meta type id +Q_DECLARE_METATYPE(QVector) // LCOV_EXCL_LINE + #endif // QT3DANIMATION_QCHANNELMAPPING_P_H -- cgit v1.2.3