summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMahmoud Badri <mahmoud.badri@qt.io>2019-07-29 14:20:04 +0300
committerMahmoud Badri <mahmoud.badri@qt.io>2019-08-01 08:58:25 +0300
commit6063e055c5dd38c393f78842472d87304fe97229 (patch)
treeeeaabbf302dd2fccae2100265ebb08c68ce54bca
parente13ab913d2fe4d1b8d687713693b5a8bb5856e7c (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.h93
-rw-r--r--src/dm/systems/StudioAnimationSystem.cpp185
-rw-r--r--src/dm/systems/StudioAnimationSystem.h14
-rw-r--r--src/dm/systems/cores/AnimationCoreProducer.cpp13
-rw-r--r--src/dm/systems/cores/AnimationCoreProducer.h4
-rw-r--r--src/dm/systems/cores/SimpleAnimationCore.cpp13
-rw-r--r--src/dm/systems/cores/SimpleAnimationCore.h32
-rw-r--r--src/system/Qt3DSBezierEval.h16
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