diff options
-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 |