summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Lemire <paul.lemire@kdab.com>2019-03-28 08:31:42 +0100
committerPaul Lemire <paul.lemire@kdab.com>2019-04-03 13:00:08 +0000
commitf0f5a2de1da2e05e3587d2a6486687ebbe649339 (patch)
tree80cfacbe85d1a88571c169d38dc495b3df687937 /src
parent03234c59244ed77cb8eea5fca6b93741f40ca59d (diff)
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 <sean.harmer@kdab.com>
Diffstat (limited to 'src')
-rw-r--r--src/animation/backend/animationutils.cpp110
-rw-r--r--src/animation/backend/animationutils_p.h37
-rw-r--r--src/animation/backend/channelmapping.cpp5
-rw-r--r--src/animation/backend/channelmapping_p.h4
-rw-r--r--src/animation/frontend/qabstractchannelmapping_p.h2
-rw-r--r--src/animation/frontend/qchannelmapping.cpp78
-rw-r--r--src/animation/frontend/qchannelmapping_p.h10
7 files changed, 172 insertions, 74 deletions
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<float> 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<char> 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<char> &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<typename Container>
+Container mapChannelResultsToContainer(const MappingData &mappingData,
+ const QVector<float> &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<float> &channelResults)
{
- QVariant v;
+ const int vectorOfFloatType = qMetaTypeId<QVector<float>>();
+
+ 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<float>
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<float>
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<QVariantList>(
+ mappingData, channelResults);
+ return QVariant::fromValue(results);
+ }
default:
qWarning() << "Unhandled animation type" << mappingData.type;
break;
}
- return v;
+ return QVariant();
}
QVector<Qt3DCore::QSceneChangePtr> preparePropertyChanges(Qt3DCore::QNodeId animatorId,
@@ -540,7 +532,11 @@ QVector<MappingData> buildPropertyMappings(const QVector<ChannelMapping*> &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<ChannelNameAndType> 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<ComponentIndices> assignChannelComponentIndices(const QVector<ChannelNam
int baseIndex = 0;
for (const auto &entry : namesAndTypes) {
// Populate indices in order
- const int componentCount = componentsForType(entry.type);
+ const int componentCount = entry.componentCount;
ComponentIndices indices(componentCount);
std::iota(indices.begin(), indices.end(), baseIndex);
@@ -780,6 +779,7 @@ ClipFormat generateClipFormatIndices(const QVector<ChannelNameAndType> &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<float> defaultValueForChannel(Handler *handler,
}
// Everything else gets all zeros
- const int componentCount = componentsForType(channelDescription.type);
+ const int componentCount = mapping->componentCount();
result = QVector<float>(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
@@ -289,20 +304,18 @@ inline bool isValidNormalizedTime(float t)
}
Q_AUTOTEST_EXPORT
-int componentsForType(int type);
-
-Q_AUTOTEST_EXPORT
ClipEvaluationData evaluationDataForClip(AnimationClip *clip,
const AnimatorEvaluationData &animatorData);
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<char> &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<int>(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<int>(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 char *>(const_cast<const void *>(change->value().value<void *>()));
+ else if (change->propertyName() == QByteArrayLiteral("componentCount"))
+ m_componentCount = change->value().toInt();
else if (change->propertyName() == QByteArrayLiteral("callback"))
m_callback = static_cast<QAnimationCallback *>(change->value().value<void *>());
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<typename T>
+int componentCountForValue(const T &)
+{
+ return 0;
+}
+
+template<>
+int componentCountForValue<QVector<float>>(const QVector<float> &v)
+{
+ return v.size();
+}
+
+template<>
+int componentCountForValue<QVariantList>(const QVariantList &v)
+{
+ return v.size();
+}
+
+
+int componentCountForType(int type, const QVariant &value)
+{
+ const int vectorOfFloatTypeId = qMetaTypeId<QVector<float>>();
+
+ if (type == vectorOfFloatTypeId)
+ return componentCountForValue<QVector<float>>(value.value<QVector<float>>());
+
+ 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<QVariantList>(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<int>(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 <Qt3DAnimation/private/qabstractchannelmapping_p.h>
#include <Qt3DAnimation/qanimationcallback.h>
+#include <QVector>
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<float>) // LCOV_EXCL_LINE
+
#endif // QT3DANIMATION_QCHANNELMAPPING_P_H