diff options
author | Christian Strømme <christian.stromme@qt.io> | 2018-12-12 17:02:25 +0100 |
---|---|---|
committer | Christian Stromme <christian.stromme@qt.io> | 2019-01-08 15:42:25 +0000 |
commit | 7ffe0aff86fc78cb6c673f1b6041bfacd4e481b6 (patch) | |
tree | 979912c9acc59ecd138a200a19bad849c588c82e /src | |
parent | 5de34146f23df4aad5c3d6ffcc01b1915b3b34f8 (diff) |
Some improvments to the new animation code
- The animation tracks for a slide are now stored in one continuous
block of memory.
- The master slide has its own animator, which means it can technically
be run on its own.
- Building the animation tracks are now much more simple and clean, but
it does now assume that the tracks in the UIP are grouped correctly.
- +++
Change-Id: Ib3a87975e6014170fefecdc909d50b6ea81929cd
Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/runtime/animator/q3dsanimator.cpp | 103 | ||||
-rw-r--r-- | src/runtime/animator/q3dsanimator_p.h | 92 | ||||
-rw-r--r-- | src/runtime/slideplayerng/q3dsanimationmanagerng.cpp | 216 | ||||
-rw-r--r-- | src/runtime/slideplayerng/q3dsslideplayerng.cpp | 29 | ||||
-rw-r--r-- | src/runtime/slideplayerng/q3dsslideplayerng_p.h | 2 |
5 files changed, 207 insertions, 235 deletions
diff --git a/src/runtime/animator/q3dsanimator.cpp b/src/runtime/animator/q3dsanimator.cpp index b5d53f6..fed5985 100644 --- a/src/runtime/animator/q3dsanimator.cpp +++ b/src/runtime/animator/q3dsanimator.cpp @@ -35,8 +35,8 @@ QT_BEGIN_NAMESPACE -bool evaluateAnimation(const Q3DSNodeAnimation::KeyFrameList::const_iterator &cbegin, - const Q3DSNodeAnimation::KeyFrameList::const_iterator &cend, +bool evaluateAnimation(const Q3DSAnimator::AnimationDataList::const_iterator &cbegin, + const Q3DSAnimator::AnimationDataList::const_iterator &cend, float time, float *value) { @@ -46,40 +46,40 @@ bool evaluateAnimation(const Q3DSNodeAnimation::KeyFrameList::const_iterator &cb if (size < 2) { if (size == 0) return false; - *value = cbegin->value; + *value = cbegin->keyFrameData.value; } else { - if (time >= cend->time) { - *value = cend->value; - } else if (time <= cbegin->time) { - *value = cbegin->value; + if (time >= cend->keyFrameData.time) { + *value = cend->keyFrameData.value; + } else if (time <= cbegin->keyFrameData.time) { + *value = cbegin->keyFrameData.value; } else { - const auto foundIt = std::find_if(cbegin, cend, [time](const Q3DSAnimationUtils::KeyFrame &kf) { return (kf.time >= time); }); + const auto foundIt = std::find_if(cbegin, cend, [time](const Q3DSAnimationData &data) { return (data.keyFrameData.time >= time); }); const auto previous = (foundIt != cbegin) ? (foundIt - 1) : foundIt; - *value = Q3DSAnimationUtils::evaluateBezierKeyframe(time, (*previous), (*foundIt)); + Q_ASSERT(foundIt->type == Q3DSAnimationData::DataType::KeyFrame && previous->type == Q3DSAnimationData::DataType::KeyFrame); + *value = Q3DSAnimationUtils::evaluateBezierKeyframe(time, (*previous).keyFrameData, (*foundIt).keyFrameData); } } return !qFuzzyCompare(*value, oldValue); } -void syncDirtyProperties(const QVector<Q3DSNodeAnimation::DirtyProperty> &dirtyProperties) +void syncDirtyProperties(const Q3DSAnimator::DirtyPropertyList &dirtyProperties) { Q3DSGraphObject *target; qint8 changeFlags; qint16 pid; QVariant::Type type; for (const auto &dirtyProperty : dirtyProperties) { - target = dirtyProperty.target; + target = dirtyProperty.target->target; Q_ASSERT(target); - const auto &property = dirtyProperty.it; - pid = property->pid; - type = property->type; + pid = dirtyProperty.target->pid; + type = dirtyProperty.target->type; if (Q_UNLIKELY(pid == -1 || type == QVariant::Invalid)) { qCWarning(lcAnim, "Property update failed for id %d and with type %d", pid, type); return; } - const auto &vec3 = property->vec3; - changeFlags = property->changeFlags; + const auto &vec3 = dirtyProperty.value; + changeFlags = dirtyProperty.target->changeFlags; static const auto toTargetVariant = [](QVariant::Type type, const QVector3D &v) { switch (int(type)) { case QVariant::Double: @@ -108,55 +108,40 @@ void syncDirtyProperties(const QVector<Q3DSNodeAnimation::DirtyProperty> &dirtyP } } -void evaluateNodesAt(const Q3DSAnimator::AnimationList::const_iterator &animBegin, - const Q3DSAnimator::AnimationList::const_iterator &animEnd, +void evaluateNodesAt(Q3DSAnimator::AnimationDataList::const_iterator cit, + const Q3DSAnimator::AnimationDataList::const_iterator cend, float time, Q3DSAnimator::DirtyPropertyList *dirtyList, bool sync) { - using Components = Q3DSNodeAnimation::Property::Components; - - auto animIt = animBegin; - Q3DSGraphObject *target = nullptr; - while (animIt != animEnd) { - target = animIt->target; - Q_ASSERT(target); - const auto &properties = animIt->properties; - auto propertiesIt = properties.cbegin(); - const auto &propertiesEnd = properties.cend(); - const auto &keyFrames = animIt->keyFrames; - while (propertiesIt != propertiesEnd) { - auto &v = propertiesIt->vec3; - const auto &components = propertiesIt->componentFlags; - if (Q_UNLIKELY(components == Components::None)) { - qWarning("Property animation without no component specified!"); - continue; - } - // If sync is set to true we mark all as dirty to make sure the target property and the - // animation node values are in sync. - bool changed = sync; - if (components & Components::X) { - const auto cbegin = keyFrames.cbegin() + propertiesIt->components[0].offset; - const auto cend = cbegin + propertiesIt->components[0].size - 1; - changed |= evaluateAnimation(cbegin, cend, time, &v[0]); - } - if (components & Components::Y) { - const auto cbegin = keyFrames.cbegin() + propertiesIt->components[1].offset; - const auto cend = cbegin + propertiesIt->components[1].size - 1; - changed |= evaluateAnimation(cbegin, cend, time, &v[1]); - } - if (components & Components::Z) { - const auto cbegin = keyFrames.cbegin() + propertiesIt->components[2].offset; - const auto cend = cbegin + propertiesIt->components[2].size - 1; - changed |= evaluateAnimation(cbegin, cend, time, &v[2]); - } + QVector3D vec3; + // If sync is set to true we mark all as dirty to make sure the target property and the + // animation node values are in sync. + bool changed = sync; + while (cit != cend) { + if (cit->type == Q3DSAnimationData::DataType::Component) { + const auto &componentData = cit->componentData; + const auto &component = componentData.component; + + const auto cKfBegin = cit + 1; + const auto cKfEnd = cKfBegin + componentData.size - 1; + Q_ASSERT(cKfBegin->type == Q3DSAnimationData::DataType::KeyFrame + && cKfEnd->type == Q3DSAnimationData::DataType::KeyFrame); + changed |= evaluateAnimation(cKfBegin, cKfEnd, time, &componentData.value); + vec3[static_cast<int>(component)] = componentData.value; + cit = cKfEnd + 1; // Next should be either a component or a target (last kf + 1) + Q_ASSERT(cit->type == Q3DSAnimationData::DataType::Component + || cit->type == Q3DSAnimationData::DataType::Target); + } + if (cit->type == Q3DSAnimationData::DataType::Target) { if (changed) - dirtyList->push_back({propertiesIt, target}); - - ++propertiesIt; + dirtyList->push_back({&cit->targetData, std::move(vec3)}); + changed = sync; // reset the changed value + ++cit; } - ++animIt; + + Q_ASSERT(cit == cend || cit->type == Q3DSAnimationData::DataType::Component); } } @@ -168,7 +153,7 @@ void Q3DSAnimator::goToTime(float time, bool sync) localTime = time; dirtyList.clear(); - evaluateNodesAt(animationList.cbegin(), animationList.cend(), localTime, &dirtyList, sync); + evaluateNodesAt(animationDataList.cbegin(), animationDataList.cend(), localTime, &dirtyList, sync); syncDirtyProperties(dirtyList); if (timeChangeCallback) diff --git a/src/runtime/animator/q3dsanimator_p.h b/src/runtime/animator/q3dsanimator_p.h index 6a61c5c..53659af 100644 --- a/src/runtime/animator/q3dsanimator_p.h +++ b/src/runtime/animator/q3dsanimator_p.h @@ -53,50 +53,54 @@ QT_BEGIN_NAMESPACE class Q3DSGraphObject; class Q3DSSlide; -struct Q3DSNodeAnimation +struct Q3DSAnimationData { - using KeyFrameList = QVector<Q3DSAnimationUtils::KeyFrame>; - - struct Property + enum class DataType : quint8 { - enum class Components : quint8 { - None, - X = 0x1, - Y = 0x2, - Z = 0x4, - Dynamic = 0x10 - }; - struct Component - { - // Offset and length into the KeyFrameList - quint16 offset; - quint16 size; - } components[3]; - mutable QVector3D vec3; - qint16 pid; - qint8 changeFlags; - Components componentFlags; - QVariant::Type type; + Component, + KeyFrame, + Target, + }; + enum class Component : quint8 { + X, + Y, + Z + }; + struct ComponentData { + mutable float value; + quint16 size; + Component component; + bool dynamic; }; - using PropertyList = QVector<Property>; - using PropertyIterator = Q3DSNodeAnimation::PropertyList::const_iterator; + using KeyFrameData = Q3DSAnimationUtils::KeyFrame; - struct DirtyProperty - { - PropertyIterator it; + struct TargetData { Q3DSGraphObject *target; + QVariant::Type type; + qint16 pid; + qint8 changeFlags; + }; + + union { + ComponentData componentData; + KeyFrameData keyFrameData; + TargetData targetData; }; - Q3DSGraphObject *target; - PropertyList properties; - KeyFrameList keyFrames; // Should be ordered (x, y, z, x, ...) + DataType type; +}; + +Q_DECLARE_TYPEINFO(Q3DSAnimationData, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(Q3DSAnimationData::KeyFrameData, Q_MOVABLE_TYPE); + +struct Q3DSDirtyAnimationValue +{ + const Q3DSAnimationData::TargetData *target; + QVector3D value; }; -Q_DECLARE_TYPEINFO(Q3DSNodeAnimation, Q_MOVABLE_TYPE); -Q_DECLARE_TYPEINFO(Q3DSNodeAnimation::DirtyProperty, Q_MOVABLE_TYPE); -Q_DECLARE_TYPEINFO(Q3DSNodeAnimation::Property, Q_MOVABLE_TYPE); -Q_DECLARE_TYPEINFO(Q3DSNodeAnimation::Property::Component, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(Q3DSDirtyAnimationValue, Q_MOVABLE_TYPE); struct Q3DSAnimator { @@ -110,10 +114,10 @@ struct Q3DSAnimator bool active = false; PlayMode playMode = PlayMode::StopAtEnd; - using AnimationList = QVector<Q3DSNodeAnimation>; - AnimationList animationList; + using AnimationDataList = QVector<Q3DSAnimationData>; + AnimationDataList animationDataList; - using DirtyPropertyList = QVector<Q3DSNodeAnimation::DirtyProperty>; + using DirtyPropertyList = QVector<Q3DSDirtyAnimationValue>; DirtyPropertyList dirtyList; using EosCallback = std::function<void()>; @@ -128,17 +132,13 @@ struct Q3DSAnimator void advance(float dt); }; -inline constexpr quint8 operator &(const Q3DSNodeAnimation::Property::Components &l, - const Q3DSNodeAnimation::Property::Components &r) -{ return (static_cast<quint8>(l) & static_cast<quint8>(r)); } - -bool evaluateAnimation(const Q3DSNodeAnimation::KeyFrameList::const_iterator &cbegin, - const Q3DSNodeAnimation::KeyFrameList::const_iterator &cend, +bool evaluateAnimation(const Q3DSAnimator::AnimationDataList::const_iterator &cbegin, + const Q3DSAnimator::AnimationDataList::const_iterator &cend, float time, float *value); -void syncDirtyProperties(const QVector<Q3DSNodeAnimation::DirtyProperty> &dirtyProperties); -void evaluateNodesAt(const Q3DSAnimator::AnimationList::const_iterator &animBegin, - const Q3DSAnimator::AnimationList::const_iterator &animEnd, +void syncDirtyProperties(const Q3DSAnimator::DirtyPropertyList &dirtyProperties); +void evaluateNodesAt(Q3DSAnimator::AnimationDataList::const_iterator cit, + const Q3DSAnimator::AnimationDataList::const_iterator cend, float time, Q3DSAnimator::DirtyPropertyList *dirtyList, bool sync = false); diff --git a/src/runtime/slideplayerng/q3dsanimationmanagerng.cpp b/src/runtime/slideplayerng/q3dsanimationmanagerng.cpp index 396c826..116cb0d 100644 --- a/src/runtime/slideplayerng/q3dsanimationmanagerng.cpp +++ b/src/runtime/slideplayerng/q3dsanimationmanagerng.cpp @@ -62,15 +62,15 @@ static QVector3D toVector3D(const QVariant &qv) } }; -static Q3DSNodeAnimation::KeyFrameList buildKeyFramesForTrack(const Q3DSAnimationTrack &track) +static void addKeyFramesForTrack(const Q3DSAnimationTrack &track, Q3DSAnimator::AnimationDataList *kfl) { const auto type = track.type(); const auto &keyFrames = track.keyFrames(); const auto end = keyFrames.constEnd(); const auto begin = keyFrames.constBegin(); auto it = begin; - Q3DSNodeAnimation::KeyFrameList kfl; - kfl.reserve(keyFrames.size()); + Q3DSAnimationData keyFrameData; + keyFrameData.type = Q3DSAnimationData::DataType::KeyFrame; while (it != end) { switch (type) { case Q3DSAnimationTrack::EaseInOut: @@ -109,199 +109,175 @@ static Q3DSNodeAnimation::KeyFrameList buildKeyFramesForTrack(const Q3DSAnimatio const float p2t = qBound(previous->time, it->time - (dt * easeOut * adjustment), it->time); const float p2v = it->value; - kfl.append({it->time, it->value, {p1t, p1v}, {p2t, p2v}}); + keyFrameData.keyFrameData = {it->time, it->value, {p1t, p1v}, {p2t, p2v}}; + kfl->push_back(keyFrameData); } break; case Q3DSAnimationTrack::Bezier: - kfl.append({it->time, it->value, {it->c1time, it->c1value / 100.0f}, {it->c2time, it->c2value / 100.0f}}); + keyFrameData.keyFrameData = {it->time, it->value, {it->c1time, it->c1value / 100.0f}, {it->c2time, it->c2value / 100.0f}}; + kfl->push_back(keyFrameData); break; default: - kfl.append({it->time, it->value, {it->time, it->value}, {it->time, it->value}}); + keyFrameData.keyFrameData = {it->time, it->value, {it->time, it->value}, {it->time, it->value}}; + kfl->push_back(keyFrameData); break; } ++it; } - return kfl; } void Q3DSAnimationManagerNg::buildSlideAnimation(Q3DSSlide *slide, bool rebuild) { - // This code is ridicules, but it will do for now + if (!slide) + return; + Q3DSSlideAttached *data = slide->attached<Q3DSSlideAttached>(); Q_ASSERT(data); if (!data->animatorNg) data->animatorNg = new Q3DSAnimator; - if (!rebuild && !data->animatorNg->animationList.isEmpty()) + if (!rebuild && !data->animatorNg->animationDataList.isEmpty()) return; - auto &propertyTracks = data->animatorNg->animationList; - propertyTracks.clear(); - using ComponentTracks = QVarLengthArray<const Q3DSAnimationTrack *, 4>; - using PropTracks = QHash<QString, ComponentTracks>; - QHash<Q3DSGraphObject *, PropTracks> targetMap; - // TODO: Instead of using the property string we can use the property idx - // and the component id should be retrieveable from the track as an enum. - - const auto buildHelper = [&targetMap](Q3DSSlide *slide) { - if (!slide) - return; - - const bool isMaster = !slide->parent(); - const auto tracks = slide->animations(); - - for (const auto &track : tracks) { - auto target = track.target(); - auto foundIt = targetMap.find(target); - const auto split = track.property().split(QChar::fromLatin1('.')); - const auto propertyStr = split.at(0); - const int idx = (split.size() > 1) ? componentSuffixToIndex(*split.at(1).toLatin1()) : 0; - Q_ASSERT(idx >= 0 && idx <= 3); - if (foundIt == targetMap.constEnd()) { - ComponentTracks c { nullptr, nullptr, nullptr, nullptr }; - c.insert(idx, &track); - targetMap.insert(target, {{propertyStr, c}}); - } else { - auto foundIt2 = foundIt->find(propertyStr); - if (foundIt2 == foundIt->cend()) { - ComponentTracks c { nullptr, nullptr, nullptr, nullptr }; - c.insert(idx, &track); - foundIt->insert(propertyStr, c); - } else { - if (isMaster && foundIt2->at(idx)) - continue; - foundIt2->insert(idx, &track); - } - } - } - }; - - buildHelper(slide); - buildHelper(static_cast<Q3DSSlide *>(slide->parent())); - - Q3DSNodeAnimation nodeAnimation; // TODO: Reserve - for (auto targetIt = targetMap.cbegin(); targetIt != targetMap.cend(); ++targetIt) { - const auto target = targetIt.key(); - nodeAnimation.target = target; - nodeAnimation.properties.clear(); - nodeAnimation.keyFrames.clear(); - for (auto propTrack = targetIt->cbegin(); propTrack != targetIt->cend(); ++propTrack) { - Q3DSNodeAnimation::Property nodeProperty; - const auto &property = propTrack.key(); - const auto &atracks = propTrack.value(); - const int pid = Q3DSGraphObject::indexOfProperty(target, property.toLatin1()); + auto &animationDataList = data->animatorNg->animationDataList; + animationDataList.clear(); + + // NOTE: the assumption here is that tracks are ordered as, e.g., rotation.x, rotation.y... + const auto &tracks = slide->animations(); + auto cit = tracks.cbegin(); + const auto cend = tracks.cend(); + while (cit != cend) { + const auto &track = *cit; + const auto prop = track.property().split('.'); + const auto comp = (prop.size() > 1) ? Q3DSAnimationData::Component(componentSuffixToIndex(*prop.at(1).toLatin1())) + : Q3DSAnimationData::Component::X; + + // Structure: | Cx | K1..Kn | Cy | K1..Kn | Cz | K1..Kn | T | ... | + // 1. Create component data + Q3DSAnimationData component; + component.type = Q3DSAnimationData::DataType::Component; + component.componentData.component = comp; + component.componentData.size = quint16(track.keyFrames().size()); + component.componentData.dynamic = track.isDynamic(); + animationDataList.push_back(component); + + // 2. Add key frames for component track + addKeyFramesForTrack(track, &animationDataList); + + // 3. Add the target data (if we're at end, the target changes, or the property changes + if ((cit + 1) == cend || (cit->target() != (cit + 1)->target() || !(cit + 1)->property().startsWith(prop[0]))) { + Q3DSAnimationData targetData; + targetData.type = Q3DSAnimationData::DataType::Target; + targetData.targetData.target = track.target(); + + const int pid = Q3DSGraphObject::indexOfProperty(track.target(), prop[0].toLatin1()); Q_ASSERT(pid != -1); - QVector3D vec3; - quint8 compFlag = 0; - for (int compPos = 0; compPos != 3; ++compPos) { - const auto trackPtr = atracks.at(compPos); - if (!trackPtr) - continue; - - const auto componentKeyFrames = buildKeyFramesForTrack(*trackPtr); - // Get the start value, which is the value of the first kf. - if (componentKeyFrames.size() > 0) - vec3[compPos] = componentKeyFrames.at(0).value; - compFlag |= (1 << compPos); - const int offset = nodeAnimation.keyFrames.size(); - const int size = componentKeyFrames.size(); - nodeProperty.components[compPos].size = quint16(size); - nodeProperty.components[compPos].offset = quint16(offset); - nodeAnimation.keyFrames += componentKeyFrames; - if (trackPtr->isDynamic()) - compFlag |= static_cast<quint8>(Q3DSNodeAnimation::Property::Components::Dynamic); - } - - const int changeFlag = targetIt.key()->mapChangeFlags({{property}}); - nodeProperty.vec3 = vec3; - nodeProperty.changeFlags = qint8(changeFlag); - nodeProperty.componentFlags = static_cast<Q3DSNodeAnimation::Property::Components>(compFlag); - nodeProperty.pid = qint16(pid); + targetData.targetData.pid = qint16(pid); + targetData.targetData.changeFlags = qint8(track.target()->mapChangeFlags({{prop[0]}})); // TODO: Find a nice solution for getting the type... - nodeProperty.type = Q3DSGraphObject::readProperty(target, pid).type(); - nodeAnimation.properties.push_back(std::move(nodeProperty)); + const auto type = Q3DSGraphObject::readProperty(track.target(), pid).type(); + Q_ASSERT(type != QVariant::Invalid); + targetData.targetData.type = type; + animationDataList.push_back(targetData); } - - data->animatorNg->animationList.push_back(std::move(nodeAnimation)); + ++cit; } } void Q3DSAnimationManagerNg::updateDynamicKeyFrames(Q3DSSlide *slide) { + if (!slide) + return; + Q3DSSlideAttached *data = slide->attached<Q3DSSlideAttached>(); Q_ASSERT(data); if (!data->animatorNg) return; - auto &animations = data->animatorNg->animationList; - for (auto &animNode : animations) { - using Component = Q3DSNodeAnimation::Property::Components; - for (const auto &property : qAsConst(animNode.properties)) { - const auto vec3 = toVector3D(Q3DSGraphObject::readProperty(animNode.target, property.pid)); - if ((property.componentFlags & Component::Dynamic) == 0) - continue; - if (property.componentFlags & Component::X) { - auto &kf = *(animNode.keyFrames.begin() + property.components[0].offset); - kf.value = kf.c1.value = kf.c2.value = vec3[0]; - } - if (property.componentFlags & Component::Y) { - auto &kf = *(animNode.keyFrames.begin() + property.components[1].offset); - kf.value = kf.c1.value = kf.c2.value = vec3[1]; - } - if (property.componentFlags & Component::Z) { - auto &kf = *(animNode.keyFrames.begin() + property.components[2].offset); - kf.value = kf.c1.value = kf.c2.value = vec3[2]; + auto &animationDataList = data->animatorNg->animationDataList; + auto it = animationDataList.begin(); + const auto end = animationDataList.end(); + while (it != end) { + if (it->type == Q3DSAnimationData::DataType::Component && (it->componentData.dynamic)) { + // find the target and the components that needs to be updated + QVarLengthArray<Q3DSAnimationData *, 3> components; + const auto targetIt = std::find_if(it, end, [&components](Q3DSAnimationData &data) { + if (data.type == Q3DSAnimationData::DataType::Target) + return true; + else if (data.type == Q3DSAnimationData::DataType::Component && data.componentData.dynamic) + components.push_back(&data); + return false; + }); + + Q_ASSERT(targetIt != end && targetIt->type == Q3DSAnimationData::DataType::Target); + const auto vec3 = toVector3D(Q3DSGraphObject::readProperty(targetIt->targetData.target, targetIt->targetData.pid)); + // Update the first kf on each track + for (auto &component : components) { + if (component == nullptr) + break; + + Q_ASSERT(component->type == Q3DSAnimationData::DataType::Component); + if (component->componentData.size < 1) // No key-frames... + continue; + + auto kfData = (component + 1); + Q_ASSERT(kfData->type == Q3DSAnimationData::DataType::KeyFrame); + auto &kf = kfData->keyFrameData; + kf.value = kf.c1.value = kf.c2.value = vec3[static_cast<int>(component->componentData.component)]; + } + it = targetIt; } + ++it; } } void Q3DSAnimationManagerNg::setActive(Q3DSSlide *slide, bool active) { - if (slide->attached<Q3DSSlideAttached>()->animatorNg) + if (slide && slide->attached<Q3DSSlideAttached>()->animatorNg) slide->attached<Q3DSSlideAttached>()->animatorNg->active = active; } void Q3DSAnimationManagerNg::goToTime(Q3DSSlide *slide, float timeMs, bool sync) { - if (slide->attached<Q3DSSlideAttached>()->animatorNg) + if (slide && slide->attached<Q3DSSlideAttached>()->animatorNg) slide->attached<Q3DSSlideAttached>()->animatorNg->goToTime(timeMs / 1000.f, sync); } void Q3DSAnimationManagerNg::setRate(Q3DSSlide *slide, float rate) { - if (slide->attached<Q3DSSlideAttached>()->animatorNg) + if (slide && slide->attached<Q3DSSlideAttached>()->animatorNg) slide->attached<Q3DSSlideAttached>()->animatorNg->rate = rate; } void Q3DSAnimationManagerNg::setDuration(Q3DSSlide *slide, float durationMs) { - if (slide->attached<Q3DSSlideAttached>()->animatorNg) + if (slide && slide->attached<Q3DSSlideAttached>()->animatorNg) slide->attached<Q3DSSlideAttached>()->animatorNg->duration = durationMs / 1000.f; } void Q3DSAnimationManagerNg::setPlayMode(Q3DSSlide *slide, Q3DSSlide::PlayMode mode) { - if (slide->attached<Q3DSSlideAttached>()->animatorNg) + if (slide && slide->attached<Q3DSSlideAttached>()->animatorNg) slide->attached<Q3DSSlideAttached>()->animatorNg->playMode = mode; } void Q3DSAnimationManagerNg::setEosCallback(Q3DSSlide *slide, Q3DSAnimator::EosCallback cb) { - if (slide->attached<Q3DSSlideAttached>()->animatorNg) + if (slide && slide->attached<Q3DSSlideAttached>()->animatorNg) slide->attached<Q3DSSlideAttached>()->animatorNg->eosCallback = cb; } void Q3DSAnimationManagerNg::setTimeChangeCallback(Q3DSSlide *slide, Q3DSAnimator::TimeChangeCallback cb) { - if (slide->attached<Q3DSSlideAttached>()->animatorNg) + if (slide && slide->attached<Q3DSSlideAttached>()->animatorNg) slide->attached<Q3DSSlideAttached>()->animatorNg->timeChangeCallback = cb; } void Q3DSAnimationManagerNg::advance(Q3DSSlide *slide, float dtMs) { - if (slide->attached<Q3DSSlideAttached>()->animatorNg) + if (slide && slide->attached<Q3DSSlideAttached>()->animatorNg) slide->attached<Q3DSSlideAttached>()->animatorNg->advance(dtMs / 1000.f); } diff --git a/src/runtime/slideplayerng/q3dsslideplayerng.cpp b/src/runtime/slideplayerng/q3dsslideplayerng.cpp index cdba58c..1791384 100644 --- a/src/runtime/slideplayerng/q3dsslideplayerng.cpp +++ b/src/runtime/slideplayerng/q3dsslideplayerng.cpp @@ -185,6 +185,8 @@ void Q3DSSlidePlayerNg::advanceFrame(float dt) // NOTE: dt is in ms! Q3DSSlide *slide = m_data.slideDeck->currentSlide(); + if (slide->parent()) + Q3DSAnimationManagerNg::advance(static_cast<Q3DSSlide *>(slide->parent()), dt); Q3DSAnimationManagerNg::advance(slide, dt); forAllSlideComponents(static_cast<Q3DSSlide *>(slide->parent()), [dt](Q3DSComponentNode *component) { component->currentSlide()->attached<Q3DSSlideAttached>()->slidePlayer->advanceFrame(dt); @@ -464,7 +466,7 @@ void Q3DSSlidePlayerNg::reset() setInternalState(PlayerState::Idle); } -void Q3DSSlidePlayerNg::changeState(Q3DSSlide *slide, Q3DSSlidePlayerNg::PlayerState state, bool parentChanged = false) +void Q3DSSlidePlayerNg::changeState(Q3DSSlide *slide, Q3DSSlidePlayerNg::PlayerState state) { // The scene state is the slide and the player state is the state of the animation if (!slide) @@ -506,10 +508,6 @@ void Q3DSSlidePlayerNg::changeState(Q3DSSlide *slide, Q3DSSlidePlayerNg::PlayerS case PlayerState::Ready: // Reset to the initial state Q3DSAnimationManagerNg::setActive(slide, false); // Hide all objects - if (parentChanged) { - setObjectVisibility(static_cast<Q3DSSlide *>(slide->parent()), -1.0f); - forAllSlideComponents(static_cast<Q3DSSlide *>(slide->parent()), resetComponentState); - } setObjectVisibility(slide, -1.0f); forAllSlideComponents(slide, resetComponentState); break; @@ -552,8 +550,11 @@ void Q3DSSlidePlayerNg::setInternalState(Q3DSSlidePlayerNg::PlayerState newState if (activeSlide != currentSlide) { // If the slide changed, stop the previous slide first (skip if slide is already ready or stopped) // This is usually the case when e.g., changing slides, as the old slide will be stopped first. - if (activeSlide && (m_data.state != PlayerState::Stopped && m_data.state != PlayerState::Ready)) - changeState(activeSlide, PlayerState::Ready, parentChanged); + if (activeSlide && (m_data.state != PlayerState::Stopped && m_data.state != PlayerState::Ready)) { + if (parentChanged) + changeState(static_cast<Q3DSSlide *>(activeSlide), PlayerState::Ready); + changeState(activeSlide, PlayerState::Ready); + } // TODO: // 1. Build all animation once (might be option to release them, but we'll get back to that). @@ -570,6 +571,7 @@ void Q3DSSlidePlayerNg::setInternalState(Q3DSSlidePlayerNg::PlayerState newState m_component->setCurrentSlide(currentSlide); // Ensure that the slide's animation tracks are built + Q3DSAnimationManagerNg::buildSlideAnimation(static_cast<Q3DSSlide *>(currentSlide->parent())); Q3DSAnimationManagerNg::buildSlideAnimation(currentSlide); // If this is a real slide change (previous slide != null and != current), then // we need to update the dynamic key frames @@ -578,6 +580,7 @@ void Q3DSSlidePlayerNg::setInternalState(Q3DSSlidePlayerNg::PlayerState newState // All set, now apply the property changes for this slide. Note that the values might // be out of sync after this, but once the slide changes to playing/paused, the values // will be synced to match the values from the animator (based on the first kf values). + processPropertyChanges(static_cast<Q3DSSlide *>(currentSlide->parent())); processPropertyChanges(currentSlide); Q_ASSERT(currentSlide->attached<Q3DSSlideAttached>()->animatorNg); @@ -588,6 +591,11 @@ void Q3DSSlidePlayerNg::setInternalState(Q3DSSlidePlayerNg::PlayerState newState m_data.position = 0.0f; // Update duration, rate, and playmode + // If the current slide has a parent, then the parent inherits its child's mode, duration, etc. + Q3DSAnimationManagerNg::setPlayMode(static_cast<Q3DSSlide *>(currentSlide->parent()), currentSlide->playMode()); + Q3DSAnimationManagerNg::setDuration(static_cast<Q3DSSlide *>(currentSlide->parent()), m_data.duration); + Q3DSAnimationManagerNg::setRate(static_cast<Q3DSSlide *>(currentSlide->parent()), m_data.playbackRate); + Q3DSAnimationManagerNg::setPlayMode(currentSlide, currentSlide->playMode()); Q3DSAnimationManagerNg::setDuration(currentSlide, m_data.duration); Q3DSAnimationManagerNg::setRate(currentSlide, m_data.playbackRate); @@ -601,6 +609,7 @@ void Q3DSSlidePlayerNg::setInternalState(Q3DSSlidePlayerNg::PlayerState newState sendPositionChanged(time); }); + changeState(static_cast<Q3DSSlide *>(currentSlide->parent()), newState); changeState(currentSlide, newState); if (newState != PlayerState::Idle) { @@ -612,8 +621,10 @@ void Q3DSSlidePlayerNg::setInternalState(Q3DSSlidePlayerNg::PlayerState newState if (m_data.state != newState) { // The change didn't change but the state did, so call changeState() now! - if (currentSlide == activeSlide) - changeState(currentSlide, newState, parentChanged); + if (currentSlide == activeSlide) { + changeState(static_cast<Q3DSSlide *>(currentSlide->parent()), newState); + changeState(currentSlide, newState); + } m_data.state = newState; Q_EMIT stateChanged(m_data.state); } diff --git a/src/runtime/slideplayerng/q3dsslideplayerng_p.h b/src/runtime/slideplayerng/q3dsslideplayerng_p.h index 4e99d2d..cdec113 100644 --- a/src/runtime/slideplayerng/q3dsslideplayerng_p.h +++ b/src/runtime/slideplayerng/q3dsslideplayerng_p.h @@ -96,7 +96,7 @@ private: void init(); void reset(); - void changeState(Q3DSSlide *slide, Q3DSSlidePlayerNg::PlayerState state, bool parentChanged); + void changeState(Q3DSSlide *slide, Q3DSSlidePlayerNg::PlayerState state); void setInternalState(PlayerState newState); void onDurationChanged(float duration); void onSlideFinished(Q3DSSlide *slide); |