diff options
author | Mahmoud Badri <mahmoud.badri@qt.io> | 2019-07-29 14:20:04 +0300 |
---|---|---|
committer | Mahmoud Badri <mahmoud.badri@qt.io> | 2019-08-01 08:58:25 +0300 |
commit | 6063e055c5dd38c393f78842472d87304fe97229 (patch) | |
tree | eeaabbf302dd2fccae2100265ebb08c68ce54bca | |
parent | e13ab913d2fe4d1b8d687713693b5a8bb5856e7c (diff) |
Support changing property animation type and curve editor
Add support for changing property animation type to either of Linear,
Easing, or Bezier. The core of the work will be in the Editor.
Task-number: QT3DS-704
Change-Id: I69a174919917d22e61aec2da8f72ed6696e33bff
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
-rw-r--r-- | src/dm/systems/Qt3DSDMAnimation.h | 93 | ||||
-rw-r--r-- | src/dm/systems/StudioAnimationSystem.cpp | 185 | ||||
-rw-r--r-- | src/dm/systems/StudioAnimationSystem.h | 14 | ||||
-rw-r--r-- | src/dm/systems/cores/AnimationCoreProducer.cpp | 13 | ||||
-rw-r--r-- | src/dm/systems/cores/AnimationCoreProducer.h | 4 | ||||
-rw-r--r-- | src/dm/systems/cores/SimpleAnimationCore.cpp | 13 | ||||
-rw-r--r-- | src/dm/systems/cores/SimpleAnimationCore.h | 32 | ||||
-rw-r--r-- | src/system/Qt3DSBezierEval.h | 16 |
8 files changed, 237 insertions, 133 deletions
diff --git a/src/dm/systems/Qt3DSDMAnimation.h b/src/dm/systems/Qt3DSDMAnimation.h index 9009efb..4cc8630 100644 --- a/src/dm/systems/Qt3DSDMAnimation.h +++ b/src/dm/systems/Qt3DSDMAnimation.h @@ -39,6 +39,11 @@ struct SLinearKeyframe { float m_KeyframeSeconds; float m_KeyframeValue; + + SLinearKeyframe() = default; + SLinearKeyframe(float seconds, float value) + : m_KeyframeSeconds(seconds) + , m_KeyframeValue(value) {} }; struct SBezierKeyframe : public SLinearKeyframe @@ -47,6 +52,15 @@ struct SBezierKeyframe : public SLinearKeyframe float m_InTangentValue; // value offset float m_OutTangentTime; // time offset in seconds float m_OutTangentValue; // value offset + + SBezierKeyframe() = default; + SBezierKeyframe(float seconds, float value, float tangentInTime, float tangentInValue, + float tangentOutTime, float tangentOutValue) + : SLinearKeyframe(seconds, value) + , m_InTangentTime(tangentInTime) + , m_InTangentValue(tangentInValue) + , m_OutTangentTime(tangentOutTime) + , m_OutTangentValue(tangentOutValue) {} }; typedef std::vector<SBezierKeyframe> TBezierKeyframeList; @@ -62,6 +76,12 @@ struct SEaseInEaseOutKeyframe : public SLinearKeyframe { float m_EaseIn; float m_EaseOut; + + SEaseInEaseOutKeyframe() = default; + SEaseInEaseOutKeyframe(float seconds, float value, float easeIn, float easeOut) + : SLinearKeyframe(seconds, value) + , m_EaseIn(easeIn) + , m_EaseOut(easeOut) {} }; } // namespace qt3dsdm @@ -92,8 +112,8 @@ namespace qt3dsdm { enum EAnimationType { EAnimationTypeNone = 0, EAnimationTypeLinear, - EAnimationTypeBezier, EAnimationTypeEaseInOut, + EAnimationTypeBezier, }; template <typename TDataType> @@ -246,7 +266,6 @@ public: virtual void GetAnimations(TAnimationInfoList &outAnimations, Qt3DSDMSlideHandle inMaster = Qt3DSDMSlideHandle(), Qt3DSDMSlideHandle inSlide = Qt3DSDMSlideHandle()) const = 0; - virtual void GetSpecificInstanceAnimations(Qt3DSDMSlideHandle inSlide, Qt3DSDMInstanceHandle inInstance, TAnimationHandleList &outAnimations) = 0; @@ -269,6 +288,7 @@ public: TKeyframeHandleList &outKeyframes) const = 0; virtual size_t GetKeyframeCount(Qt3DSDMAnimationHandle inAnimation) const = 0; virtual bool IsFirstKeyframe(Qt3DSDMKeyframeHandle inKeyframe) const = 0; + virtual bool IsLastKeyframe(Qt3DSDMKeyframeHandle inKeyframe) const = 0; virtual void OffsetAnimations(Qt3DSDMSlideHandle inSlide, Qt3DSDMInstanceHandle inInstance, long inOffset) = 0; @@ -293,22 +313,17 @@ typedef std::shared_ptr<IAnimationCore> TAnimationCorePtr; struct SGetOrSetKeyframeInfo { - float m_Value = 0.0; - float m_EaseIn = -1.f; - float m_EaseOut = -1.f; + qt3dsdm::TKeyframe m_keyframeData; bool m_AnimationTrackIsDynamic = false; - SGetOrSetKeyframeInfo(float inValue, float inEaseIn = -1.f, float inEaseOut = -1.f, - bool inDynamic = false) - : m_Value(inValue) - , m_EaseIn(inEaseIn) - , m_EaseOut(inEaseOut) + SGetOrSetKeyframeInfo(qt3dsdm::TKeyframe &keyframeData, bool inDynamic = false) + : m_keyframeData(keyframeData) , m_AnimationTrackIsDynamic(inDynamic) { } SGetOrSetKeyframeInfo() = default; - }; + /** * Interface from studio into the animation system that speaks * a language near to that of studio. Public interface. @@ -789,6 +804,33 @@ inline void GetEaseInOutValues(const TKeyframe &inValue, float &outEaseIn, float outEaseOut = inValue.visit<float>(theEaseOutGetter); } +struct BezierValuesGetter +{ + QVector<float> operator()(const SLinearKeyframe &) const { return {}; } + QVector<float> operator()(const SEaseInEaseOutKeyframe &) const { return {}; } + QVector<float> operator()(const SBezierKeyframe &inValue) const + { + return {inValue.m_InTangentTime, inValue.m_InTangentValue, + inValue.m_OutTangentTime, inValue.m_OutTangentValue}; + } + QVector<float> operator()() + { + QT3DS_ASSERT(false); + return {}; + } +}; +inline void getBezierValues(const TKeyframe &keyframe, float &tangentInTime, float &tangentInValue, + float &tangentOutTime, float &tangentOutValue) +{ + const QVector<float> values = keyframe.visit<QVector<float>>(BezierValuesGetter()); + if (!values.empty()) { + tangentInTime = values[0]; + tangentInValue = values[1]; + tangentOutTime = values[2]; + tangentOutValue = values[3]; + } +} + struct SEaseInSetter { float m_Value; @@ -834,6 +876,35 @@ inline TKeyframe SetEaseInOutValues(TKeyframe &inKeyframe, float inEaseIn, float return inKeyframe; } +struct BezierOffsetter +{ + float dt; // time offset in seconds + + TKeyframe operator()(SLinearKeyframe &inValue) const { return inValue; } + TKeyframe operator()(SEaseInEaseOutKeyframe &inValue) const { return inValue; } + TKeyframe operator()(SBezierKeyframe &inKeyframe) const + { + inKeyframe.m_InTangentTime += dt; + inKeyframe.m_OutTangentTime += dt; + + return inKeyframe; + } + TKeyframe operator()() + { + QT3DS_ASSERT(false); + return TKeyframe(); + } +}; + +// dt: time offset in seconds +inline TKeyframe offsetBezier(TKeyframe &inKeyframe, float dt) +{ + BezierOffsetter offsetter{dt}; + inKeyframe.visit<TKeyframe>(offsetter); + + return inKeyframe; +} + void GetKeyframesAsBezier(Qt3DSDMAnimationHandle inAnimation, const IAnimationCore &inAnimationCore, TBezierKeyframeList &outKeyframes); } diff --git a/src/dm/systems/StudioAnimationSystem.cpp b/src/dm/systems/StudioAnimationSystem.cpp index be33bb1..4ecae00 100644 --- a/src/dm/systems/StudioAnimationSystem.cpp +++ b/src/dm/systems/StudioAnimationSystem.cpp @@ -158,45 +158,84 @@ bool CStudioAnimationSystem::GetAnimatedInstancePropertyValue(Qt3DSDMSlideHandle bool KeyframeNear(const TKeyframe &inKeyframe, float inSeconds) { - return fabs(KeyframeTime(inKeyframe) - inSeconds) < .01; + return fabs(KeyframeTime(inKeyframe) - inSeconds) < .01f; } -Qt3DSDMKeyframeHandle CreateKeyframeExplicit(Qt3DSDMAnimationHandle inAnimation, float inValue, - float inSeconds, TAnimationCorePtr inAnimationCore, - float inEaseIn, float inEaseOut) + +Qt3DSDMKeyframeHandle CStudioAnimationSystem::CreateKeyframeExplicit( + Qt3DSDMAnimationHandle inAnimation, float inValue, float inSeconds, + TKeyframe keyframeData) { TKeyframeHandleList theKeyframes; - float theValue = inValue; - inAnimationCore->GetKeyframes(inAnimation, theKeyframes); + m_AnimationCore->GetKeyframes(inAnimation, theKeyframes); function<TKeyframe(Qt3DSDMKeyframeHandle)> theConverter( - std::bind(&IAnimationCore::GetKeyframeData, inAnimationCore, std::placeholders::_1)); + std::bind(&IAnimationCore::GetKeyframeData, m_AnimationCore, std::placeholders::_1)); TKeyframeHandleList::iterator theFind = std::find_if(theKeyframes.begin(), theKeyframes.end(), [theConverter, inSeconds](const Qt3DSDMKeyframeHandle &handle) { return KeyframeNear(theConverter(handle), inSeconds); }); - float theEaseIn = inEaseIn; - float theEaseOut = inEaseOut; - Qt3DSDMKeyframeHandle theKeyframe; - if (theFind != theKeyframes.end()) { - theKeyframe = *theFind; + if (keyframeData.getType()) { // not empty (paste keyframe case) + // offset control points time for bezier keyframes + offsetBezier(keyframeData, inSeconds - GetKeyframeSeconds(keyframeData)); + + keyframeData = SetKeyframeSeconds(keyframeData, inSeconds); + } else { // empty (insert new keyframe/change value case + EAnimationType animType = m_AnimationCore->GetAnimationInfo(inAnimation).m_AnimationType; + switch (animType) { + case EAnimationTypeLinear: + keyframeData = CreateLinearKeyframe(inSeconds, inValue); + break; - inAnimationCore->SetKeyframeData( - theKeyframe, CreateEaseInEaseOutKeyframe(inSeconds, theValue, theEaseIn, theEaseOut)); + case EAnimationTypeEaseInOut: { + float easeIn = m_SmoothInterpolation ? 100 : 0; + float easeOut = m_SmoothInterpolation ? 100 : 0; + keyframeData = CreateEaseInEaseOutKeyframe(inSeconds, inValue, easeIn, easeOut); + } break; + + case EAnimationTypeBezier: { + float timeIn, valueIn, timeOut, valueOut; + // if keyframe exists, offset control points values + if (theFind != theKeyframes.end()) { + TKeyframe kfData = m_AnimationCore->GetKeyframeData(*theFind); + getBezierValues(kfData, timeIn, valueIn, timeOut, valueOut); + float dValue = inValue - KeyframeValueValue(kfData); + valueIn += dValue; + valueOut += dValue; + } else { + valueIn = inValue; + valueOut = inValue; + timeIn = inSeconds - .5f; + timeOut = inSeconds + .5f; + } + keyframeData = CreateBezierKeyframe(inSeconds, inValue, timeIn, valueIn, + timeOut, valueOut); + } break; + + default: + Q_ASSERT(false); + break; + } + } + Qt3DSDMKeyframeHandle keyframeHandle; + if (theFind != theKeyframes.end()) { + keyframeHandle = *theFind; + m_AnimationCore->SetKeyframeData(keyframeHandle, keyframeData); } else { - theKeyframe = inAnimationCore->InsertKeyframe( - inAnimation, CreateEaseInEaseOutKeyframe(inSeconds, theValue, theEaseIn, theEaseOut)); + keyframeHandle = m_AnimationCore->InsertKeyframe(inAnimation, keyframeData); } - return theKeyframe; + + return keyframeHandle; } -Qt3DSDMKeyframeHandle CreateKeyframe(Qt3DSDMAnimationHandle inAnimation, const SValue &inValue, - float inSeconds, TAnimationCorePtr inAnimationCore, - float inEaseIn, float inEaseOut) +Qt3DSDMKeyframeHandle CStudioAnimationSystem::CreateKeyframe(Qt3DSDMAnimationHandle inAnimation, + const SValue &inValue, float inSeconds, + TAnimationCorePtr inAnimationCore) { SAnimationInfo theInfo(inAnimationCore->GetAnimationInfo(inAnimation)); + return CreateKeyframeExplicit(inAnimation, GetAnimationValue(theInfo.m_Index, inValue), - inSeconds, inAnimationCore, inEaseIn, inEaseOut); + inSeconds); } void MaybeAddAnimation(Qt3DSDMSlideHandle inSlide, Qt3DSDMInstanceHandle inInstance, @@ -219,17 +258,17 @@ void GetPresentAnimations(Qt3DSDMSlideHandle inSlide, Qt3DSDMInstanceHandle inIn const TAnimationFloatPairList &inAnimationPairs, TAnimationCorePtr inAnimationCore, TAnimationHandleList &outAnimations) { - function<void(Qt3DSDMAnimationHandle)> theOperation( - std::bind(MaybeAddAnimation, inSlide, inInstance, inProperty, - std::placeholders::_1, inAnimationCore, - std::ref(outAnimations))); - for (auto animation : inAnimationPairs) { MaybeAddAnimation(inSlide, inInstance, inProperty, animation.first, inAnimationCore, std::ref(outAnimations)); } if (outAnimations.empty()) { + function<void(Qt3DSDMAnimationHandle)> theOperation( + std::bind(MaybeAddAnimation, inSlide, inInstance, inProperty, + std::placeholders::_1, inAnimationCore, + std::ref(outAnimations))); + TAnimationHandleList theAnimationHandles; inAnimationCore->GetAnimations(theAnimationHandles); do_all(theAnimationHandles, theOperation); @@ -240,11 +279,12 @@ void GetPresentAnimations(Qt3DSDMSlideHandle inSlide, Qt3DSDMInstanceHandle inIn } void CreateAnimationAndAdd(Qt3DSDMSlideHandle inSlide, Qt3DSDMInstanceHandle inInstance, - Qt3DSDMPropertyHandle inProperty, size_t inIndex, - TAnimationCorePtr inAnimationCore, TAnimationHandleList &outAnimations) + Qt3DSDMPropertyHandle inProperty, qt3dsdm::EAnimationType animType, + size_t inIndex, TAnimationCorePtr inAnimationCore, + TAnimationHandleList &outAnimations) { outAnimations.push_back(inAnimationCore->CreateAnimation( - inSlide, inInstance, inProperty, inIndex, EAnimationTypeEaseInOut, false)); + inSlide, inInstance, inProperty, inIndex, animType, false)); } bool AnimationValueDiffers(Qt3DSDMAnimationHandle inAnimation, const SValue &inValue, @@ -266,61 +306,38 @@ bool AnimationExistsInPresentAnimations(const TAnimationFloatPair &inAnimation, std::placeholders::_1)); } -void DoKeyframeProperty(Qt3DSDMSlideHandle inSlide, Qt3DSDMInstanceHandle inInstance, - Qt3DSDMPropertyHandle inProperty, const SValue &inValue, float inTimeInSecs, - bool inDoDiffValue, TAnimationCorePtr inAnimationCore, - TAnimationFloatPairList &inAnimationFloatPairs, float inEaseIn, - float inEaseOut) +void CStudioAnimationSystem::DoKeyframeProperty(Qt3DSDMSlideHandle inSlide, + Qt3DSDMInstanceHandle inInstance, Qt3DSDMPropertyHandle inProperty, + const SValue &inValue, bool inDoDiffValue) { + TGraphSlidePair theGraphSlidePair = m_SlideGraphCore->GetAssociatedGraph(inInstance); + float inTimeInSecs = m_SlideCore->GetSlideTime(m_SlideGraphCore + ->GetGraphActiveSlide(theGraphSlidePair.first)); + size_t arity = GetVariantAnimatableArity(inValue); TAnimationHandleList thePresentAnimations; - GetPresentAnimations(inSlide, inInstance, inProperty, std::cref(inAnimationFloatPairs), - inAnimationCore, thePresentAnimations); - if (thePresentAnimations.empty()) + GetPresentAnimations(inSlide, inInstance, inProperty, std::cref(m_AnimationFloatPairs), + m_AnimationCore, thePresentAnimations); + if (thePresentAnimations.empty()) { + // default newly created keyframes to EaseInOut do_times(arity, std::bind(CreateAnimationAndAdd, inSlide, inInstance, inProperty, - std::placeholders::_1, - inAnimationCore, std::ref(thePresentAnimations))); + EAnimationTypeEaseInOut, std::placeholders::_1, + m_AnimationCore, std::ref(thePresentAnimations))); + } if (!inDoDiffValue || find_if(thePresentAnimations.begin(), thePresentAnimations.end(), std::bind(AnimationValueDiffers, - std::placeholders::_1, inValue, inTimeInSecs, inAnimationCore)) + std::placeholders::_1, inValue, inTimeInSecs, m_AnimationCore)) != thePresentAnimations.end()) { do_all(thePresentAnimations, - std::bind(CreateKeyframe, std::placeholders::_1, - std::cref(inValue), inTimeInSecs, inAnimationCore, - inEaseIn, inEaseOut)); - erase_if(inAnimationFloatPairs, std::bind(AnimationExistsInPresentAnimations, + std::bind(&CStudioAnimationSystem::CreateKeyframe, this, std::placeholders::_1, + std::cref(inValue), inTimeInSecs, m_AnimationCore)); + erase_if(m_AnimationFloatPairs, std::bind(AnimationExistsInPresentAnimations, std::placeholders::_1, std::ref(thePresentAnimations))); } } -void DoKeyframeProperty(Qt3DSDMSlideHandle inSlide, Qt3DSDMInstanceHandle inInstance, - Qt3DSDMPropertyHandle inProperty, const SValue &inValue, bool inDoDiffValue, - TAnimationCorePtr inAnimationCore, TSlideGraphCorePtr inSlideGraphCore, - TSlideCorePtr inSlideCore, TAnimationFloatPairList &inAnimationFloatPairs, - float inEaseIn, float inEaseOut) -{ - TGraphSlidePair theGraphSlidePair = inSlideGraphCore->GetAssociatedGraph(inInstance); - float theCurrentTime = - inSlideCore->GetSlideTime(inSlideGraphCore->GetGraphActiveSlide(theGraphSlidePair.first)); - DoKeyframeProperty(inSlide, inInstance, inProperty, inValue, theCurrentTime, inDoDiffValue, - inAnimationCore, inAnimationFloatPairs, inEaseIn, inEaseOut); -} - -void DoKeyframeProperty(Qt3DSDMSlideHandle inSlide, Qt3DSDMInstanceHandle inInstance, - Qt3DSDMPropertyHandle inProperty, const SValue &inValue, bool inDoDiffValue, - TAnimationCorePtr inAnimationCore, TSlideGraphCorePtr inSlideGraphCore, - TSlideCorePtr inSlideCore, TAnimationFloatPairList &inAnimationFloatPairs, - bool inSmoothInterpolation) -{ - float theEaseIn = 0.0f, theEaseOut = 0.0f; - if (inSmoothInterpolation) - theEaseIn = theEaseOut = 100.f; - DoKeyframeProperty(inSlide, inInstance, inProperty, inValue, inDoDiffValue, inAnimationCore, - inSlideGraphCore, inSlideCore, inAnimationFloatPairs, theEaseIn, theEaseOut); -} - TAnimationFloatPair CreateAnimationFloatPair(Qt3DSDMAnimationHandle inAnimation, const SValue &inValue, TAnimationCorePtr inAnimationCore) @@ -346,14 +363,9 @@ bool CStudioAnimationSystem::SetAnimatedInstancePropertyValue(Qt3DSDMSlideHandle { size_t arity = GetVariantAnimatableArity(inValue); if (arity > 0) { - if (m_AutoKeyframe && IsPropertyAnimated(inInstance, inProperty)) // prerequisite for - // autoset-keyframes is - // that the property is - // already animated. - { - DoKeyframeProperty(inSlide, inInstance, inProperty, inValue, true, m_AnimationCore, - m_SlideGraphCore, m_SlideCore, m_AnimationFloatPairs, - m_SmoothInterpolation); + // prerequisite for autoset-keyframes is that the property is already animated. + if (m_AutoKeyframe && IsPropertyAnimated(inInstance, inProperty)) { + DoKeyframeProperty(inSlide, inInstance, inProperty, inValue, true); return true; } @@ -366,7 +378,6 @@ bool CStudioAnimationSystem::SetAnimatedInstancePropertyValue(Qt3DSDMSlideHandle std::ref(m_AnimationFloatPairs), std::cref(inValue), m_AnimationCore)); - if (m_Consumer && m_refreshCallback) { // Only create a single refresh per transaction stack if (((CTransactionConsumer *)m_Consumer.get())->m_TransactionList.size() == 0) { @@ -470,8 +481,7 @@ void CStudioAnimationSystem::Animate(Qt3DSDMInstanceHandle inInstance, if (!theFound) DoKeyframeProperty(theApplicableSlide, inInstance, inProperty, theValue.toOldSkool(), - true, m_AnimationCore, m_SlideGraphCore, m_SlideCore, - m_AnimationFloatPairs, m_SmoothInterpolation); + true); } } @@ -510,8 +520,7 @@ void CStudioAnimationSystem::KeyframeProperty(Qt3DSDMInstanceHandle inInstance, GetApplicableGraphAndSlide(inInstance, inProperty, theValue.toOldSkool()); if (theApplicableSlide.Valid()) DoKeyframeProperty(theApplicableSlide, inInstance, inProperty, theValue.toOldSkool(), - inDoDiffValue, m_AnimationCore, m_SlideGraphCore, m_SlideCore, - m_AnimationFloatPairs, m_SmoothInterpolation); + inDoDiffValue); } void CStudioAnimationSystem::SetOrCreateKeyframe(Qt3DSDMInstanceHandle inInstance, Qt3DSDMPropertyHandle inProperty, @@ -525,22 +534,22 @@ void CStudioAnimationSystem::SetOrCreateKeyframe(Qt3DSDMInstanceHandle inInstanc if (arity) { theApplicableSlide = m_SlideSystem->GetApplicableSlide(inInstance, inProperty); if (theApplicableSlide.Valid()) { - TAnimationHandleList thePresentAnimations; GetPresentAnimations(theApplicableSlide, inInstance, inProperty, std::cref(m_AnimationFloatPairs), m_AnimationCore, thePresentAnimations); size_t numIterations = std::min(inNumInfos, arity); if (thePresentAnimations.empty()) { + qt3dsdm::EAnimationType animType = inKeyframeInfo[0].m_keyframeData.getType(); for (size_t idx = 0, end = numIterations; idx < end; ++idx) { - CreateAnimationAndAdd(theApplicableSlide, inInstance, inProperty, idx, + CreateAnimationAndAdd(theApplicableSlide, inInstance, inProperty, animType, idx, m_AnimationCore, thePresentAnimations); } } for (size_t idx = 0, end = numIterations; idx < end; ++idx) { - CreateKeyframeExplicit(thePresentAnimations[idx], inKeyframeInfo[idx].m_Value, - inTimeInSeconds, m_AnimationCore, - inKeyframeInfo[idx].m_EaseIn, inKeyframeInfo[idx].m_EaseOut); + CreateKeyframeExplicit(thePresentAnimations[idx], + KeyframeValueValue(inKeyframeInfo[idx].m_keyframeData), + inTimeInSeconds, inKeyframeInfo[idx].m_keyframeData); if (inKeyframeInfo[idx].m_AnimationTrackIsDynamic) m_AnimationCore->SetFirstKeyframeDynamic(thePresentAnimations[idx], true); } diff --git a/src/dm/systems/StudioAnimationSystem.h b/src/dm/systems/StudioAnimationSystem.h index e6fdf75..5331490 100644 --- a/src/dm/systems/StudioAnimationSystem.h +++ b/src/dm/systems/StudioAnimationSystem.h @@ -126,8 +126,18 @@ private: const SValue &inValue); void OverrideChannelIfAnimated(Qt3DSDMSlideHandle inSlide, Qt3DSDMInstanceHandle inInstance, - Qt3DSDMPropertyHandle inProperty, size_t inIndex, float inSeconds, - bool &ioAnimated, SValue &outValue) const; + Qt3DSDMPropertyHandle inProperty, size_t inIndex, + float inSeconds, bool &ioAnimated, SValue &outValue) const; + + void DoKeyframeProperty(Qt3DSDMSlideHandle inSlide, Qt3DSDMInstanceHandle inInstance, + Qt3DSDMPropertyHandle inProperty, const SValue &inValue, + bool inDoDiffValue); + + Qt3DSDMKeyframeHandle CreateKeyframe(Qt3DSDMAnimationHandle inAnimation, const SValue &inValue, + float inSeconds, TAnimationCorePtr inAnimationCore); + Qt3DSDMKeyframeHandle CreateKeyframeExplicit(Qt3DSDMAnimationHandle inAnimation, float inValue, + float inSeconds, TKeyframe kfData = {}); + }; } diff --git a/src/dm/systems/cores/AnimationCoreProducer.cpp b/src/dm/systems/cores/AnimationCoreProducer.cpp index 14d1824..d42ac1e 100644 --- a/src/dm/systems/cores/AnimationCoreProducer.cpp +++ b/src/dm/systems/cores/AnimationCoreProducer.cpp @@ -342,7 +342,7 @@ void CAnimationCoreProducer::OffsetAnimations(Qt3DSDMSlideHandle inSlide, Qt3DSDMInstanceHandle inInstance, long inMillisecondOffset) { - float theOffsetSeconds = static_cast<float>(inMillisecondOffset) / 1000.f; + float dt = static_cast<float>(inMillisecondOffset) / 1000.f; // time offset in seconds for (THandleObjectMap::const_iterator iter = m_Data->m_Objects.begin(), end = m_Data->m_Objects.end(); iter != end; ++iter) { @@ -351,14 +351,13 @@ void CAnimationCoreProducer::OffsetAnimations(Qt3DSDMSlideHandle inSlide, for (size_t keyframeIdx = 0, keyframeEnd = theTrack->m_Keyframes.size(); keyframeIdx < keyframeEnd; ++keyframeIdx) { Qt3DSDMKeyframeHandle theKeyframeHandle(theTrack->m_Keyframes[keyframeIdx]); - TKeyframe theCurrentKeyframe = m_Data->GetKeyframeData(theKeyframeHandle); + TKeyframe kfData = m_Data->GetKeyframeData(theKeyframeHandle); - float seconds = qt3dsdm::GetKeyframeSeconds(theCurrentKeyframe); + // offset control points for bezier keyframes + offsetBezier(kfData, dt); - theCurrentKeyframe = - qt3dsdm::SetKeyframeSeconds(theCurrentKeyframe, seconds + theOffsetSeconds); - - SetKeyframeData(theKeyframeHandle, theCurrentKeyframe); + kfData = SetKeyframeSeconds(kfData, GetKeyframeSeconds(kfData) + dt); + SetKeyframeData(theKeyframeHandle, kfData); } } } diff --git a/src/dm/systems/cores/AnimationCoreProducer.h b/src/dm/systems/cores/AnimationCoreProducer.h index 17603d6..0eb6fbd 100644 --- a/src/dm/systems/cores/AnimationCoreProducer.h +++ b/src/dm/systems/cores/AnimationCoreProducer.h @@ -97,6 +97,10 @@ public: { return m_Data->IsFirstKeyframe(inKeyframe); } + bool IsLastKeyframe(Qt3DSDMKeyframeHandle inKeyframe) const override + { + return m_Data->IsLastKeyframe(inKeyframe); + } void OffsetAnimations(Qt3DSDMSlideHandle inSlide, Qt3DSDMInstanceHandle inInstance, long inMillisecondOffset) override; diff --git a/src/dm/systems/cores/SimpleAnimationCore.cpp b/src/dm/systems/cores/SimpleAnimationCore.cpp index 00d6df4..24e9694 100644 --- a/src/dm/systems/cores/SimpleAnimationCore.cpp +++ b/src/dm/systems/cores/SimpleAnimationCore.cpp @@ -303,6 +303,17 @@ bool CSimpleAnimationCore::IsFirstKeyframe(Qt3DSDMKeyframeHandle inKeyframe) con return false; } +bool CSimpleAnimationCore::IsLastKeyframe(Qt3DSDMKeyframeHandle inKeyframe) const +{ + Qt3DSDMAnimationHandle theAnimation = GetAnimationForKeyframe(inKeyframe); + if (theAnimation.Valid()) { + const SAnimationTrack *theItem = GetAnimationNF(theAnimation, m_Objects); + return theItem->m_Keyframes.size() && theItem->m_Keyframes[theItem->m_Keyframes.size() - 1] + == inKeyframe; + } + return false; +} + void CSimpleAnimationCore::OffsetAnimations(Qt3DSDMSlideHandle /*inSlide*/, Qt3DSDMInstanceHandle /*inInstance*/, long /*inOffset*/) { @@ -382,7 +393,7 @@ float CSimpleAnimationCore::EvaluateAnimation(Qt3DSDMAnimationHandle inAnimation return 0.0f; CheckKeyframesSorted(theItem, m_Objects); // Default to linear for now. - SLinearKeyframe theKeyframe = { 0 }; + SLinearKeyframe theKeyframe; theKeyframe.m_KeyframeSeconds = inSeconds; TKeyframe theSearchKey(theKeyframe); function<TKeyframe(int)> theIntToKeyframe( diff --git a/src/dm/systems/cores/SimpleAnimationCore.h b/src/dm/systems/cores/SimpleAnimationCore.h index cb4c415..d1b5245 100644 --- a/src/dm/systems/cores/SimpleAnimationCore.h +++ b/src/dm/systems/cores/SimpleAnimationCore.h @@ -48,27 +48,17 @@ struct pair_hash { namespace qt3dsdm { struct SAnimationTrack : public CHandleObject { - int m_Slide; - int m_Instance; - int m_Property; - EAnimationType m_AnimationType; - size_t m_Index; + int m_Slide = 0; + int m_Instance = 0; + int m_Property = 0; + EAnimationType m_AnimationType = EAnimationTypeLinear; + size_t m_Index = 0; TKeyframeHandleList m_Keyframes; - bool m_KeyframesDirty; - bool m_FirstKeyframeDynamic; - bool m_ArtistEdited; - - SAnimationTrack() - : m_Slide(0) - , m_Instance(0) - , m_Property(0) - , m_AnimationType(EAnimationTypeLinear) - , m_Index(0) - , m_KeyframesDirty(false) - , m_FirstKeyframeDynamic(false) - , m_ArtistEdited(true) - { - } + bool m_KeyframesDirty = false; + bool m_FirstKeyframeDynamic = false; + bool m_ArtistEdited = true; + + SAnimationTrack() = default; SAnimationTrack(int inHandle, Qt3DSDMSlideHandle inSlide, Qt3DSDMInstanceHandle inInstance, Qt3DSDMPropertyHandle inProperty, size_t inIndex, EAnimationType inAnimationType, @@ -79,7 +69,6 @@ struct SAnimationTrack : public CHandleObject , m_Property(inProperty) , m_AnimationType(inAnimationType) , m_Index(inIndex) - , m_KeyframesDirty(false) , m_FirstKeyframeDynamic(inFirstKeyframeDynamic) , m_ArtistEdited(inArtistEdited) { @@ -159,6 +148,7 @@ public: // Use void GetKeyframes(Qt3DSDMAnimationHandle inAnimation, TKeyframeHandleList &outKeyframes) const override; size_t GetKeyframeCount(Qt3DSDMAnimationHandle inAnimation) const override; bool IsFirstKeyframe(Qt3DSDMKeyframeHandle inKeyframe) const override; + bool IsLastKeyframe(Qt3DSDMKeyframeHandle inKeyframe) const override; // Only implemented in the producer for now. void OffsetAnimations(Qt3DSDMSlideHandle inSlide, Qt3DSDMInstanceHandle inInstance, long inOffset) override; diff --git a/src/system/Qt3DSBezierEval.h b/src/system/Qt3DSBezierEval.h index c4d733a..46f8a3d 100644 --- a/src/system/Qt3DSBezierEval.h +++ b/src/system/Qt3DSBezierEval.h @@ -147,7 +147,16 @@ inline FLOAT EvaluateInverseBezierCurve(const FLOAT inP0, const FLOAT inP1, cons } } else { INT32 theNumRoots = CCubicRoots::SolveCubic(theConstants, theSolution); - theResult = static_cast<FLOAT>(theSolution[theNumRoots / 3]); + INT32 solutionIndex = theNumRoots / 3; + theResult = static_cast<FLOAT>(theSolution[solutionIndex]); + + // if the result is not within bounds, correct solutionIndex to pick the right solution + // TODO: in rare situations the 3 solutions for the cubic equation are all invalid. It's + // worth investigating. + if (theResult <= 0) + theResult = static_cast<FLOAT>(theSolution[solutionIndex - 1]); + else if (theResult >= 1) + theResult = static_cast<FLOAT>(theSolution[solutionIndex + 1]); } return theResult; @@ -157,7 +166,6 @@ inline FLOAT EvaluateBezierKeyframe(FLOAT inTime, FLOAT inTime1, FLOAT inValue1, FLOAT inC1Value, FLOAT inC2Time, FLOAT inC2Value, FLOAT inTime2, FLOAT inValue2) { - // The special case of C1Time=0 and C2Time=0 is used to indicate Studio-native animation. // Studio uses a simplified version of the bezier animation where the time control points // are equally spaced between the starting and ending times. This avoids calling the expensive @@ -171,12 +179,14 @@ inline FLOAT EvaluateBezierKeyframe(FLOAT inTime, FLOAT inTime1, FLOAT inValue1, } else { // Compute the "s" parameter on the Bezier given the time theParameter = EvaluateInverseBezierCurve(inTime1, inC1Time, inC2Time, inTime2, inTime); + if (theParameter <= 0.0f) return inValue1; + if (theParameter >= 1.0f) return inValue2; } return EvaluateBezierCurve(inValue1, inC1Value, inC2Value, inValue2, theParameter); } -} +} // namespace Qt3DStudio |