19 m_interpolationMode(Constant),
20 m_tangentsMode(Smooth),
21 m_channelLimits(limits)
26 QPointF leftTangent, QPointF rightTangent,
29 m_interpolationMode(interpMode),
30 m_tangentsMode(tangentMode),
31 m_leftTangent(leftTangent),
32 m_rightTangent(rightTangent),
33 m_channelLimits(limits)
178 Q_FOREACH (
int time, rhs.
constKeys().keys()) {
191 scalarKey = keyframeAt<KisScalarKeyframe>(time);
195 scalarKey->setValue(
value, parentUndoCmd);
208 foreach (
const int &time, keyEntries) {
210 scalarKey->setLimits(
m_d->limits);
211 scalarKey->setValue(scalarKey->value());
227 qreal result = qQNaN();
231 result = activeKey->value();
233 switch (activeKey->interpolationMode()) {
235 result = activeKey->value();
240 const qreal activeKeyValue = activeKey->value();
241 const qreal nextKeyValue = keyframeAt<KisScalarKeyframe>(nextKeyTime)->value();
242 const int interpolationLength = (nextKeyTime - activeKeyTime);
243 if (interpolationLength > 0) {
244 result = activeKeyValue + (nextKeyValue - activeKeyValue) * (time - activeKeyTime) / (interpolationLength);
246 result = activeKeyValue;
253 QPointF point0 = QPointF(activeKeyTime, activeKey->value());
254 QPointF point1 = QPointF(nextKeyTime, nextKey->value());
256 QPointF tangent0 = activeKey->rightTangent();
257 QPointF tangent1 = nextKey->leftTangent();
272 result = nextKeyframe->value();
280 return m_d->limits->clamp(result);
297 m_d->defaultInterpolationMode = mode;
304 qreal x =
cubicBezier(point1.x(), rightTangent.x(), leftTangent.x(), point2.x(), t);
305 qreal y =
cubicBezier(point1.y(), rightTangent.y(), leftTangent.y(), point2.y(), t);
313 if (scalarKeyframe) {
314 scalarKeyframe->valueChangedChannelConnection =
315 QObject::connect(scalarKeyframe.data(),
319 Q_EMIT sigKeyframeChanged(this, time);
330 disconnect(keyframe->valueChangedChannelConnection);
354 if (!firstScalarKey) {
369 if ( activeScalarKey &&
381 if (!activeScalarKey &&
keyframeAt(nextKeyTime)) {
395 if (time == time0)
return 0.0;
396 if (time == time1)
return 1.0;
402 qreal t = (max_t + min_t) / 2;
403 qreal time_t =
cubicBezier(time0, delta0, delta1, time1, t);
405 if (time_t < time - 0.05) {
407 }
else if (time_t > time + 0.05) {
417 qreal
p1 =
p0 + delta1;
418 qreal
p2 =
p3 + delta2;
421 return c*c*c *
p0 + 3*c*c*t *
p1 + 3*c*t*t *
p2 + t*t*t *
p3;
430 float interval = point2.x() - point1.x();
431 if (rightTangent.x() < 0) rightTangent *= 0;
432 if (leftTangent.x() > 0) leftTangent *= 0;
434 if (rightTangent.x() > interval) {
435 rightTangent *= interval / rightTangent.x();
437 if (leftTangent.x() < -interval) {
438 leftTangent *= interval / -leftTangent.x();
462 Q_UNUSED(layerFilename);
465 const qreal
value = scalarKey->value();
468 QString interpolationMode;
473 QString tangentsMode;
477 keyframeElement.setAttribute(
"interpolation", interpolationMode);
478 keyframeElement.setAttribute(
"tangents", tangentsMode);
485 int time = keyframeNode.toElement().attribute(
"time").toInt();
491 keyframe->setValue(
value);
495 QString interpolationMode = keyframeNode.toElement().attribute(
"interpolation");
496 if (interpolationMode ==
"constant") {
498 }
else if (interpolationMode ==
"linear") {
500 }
else if (interpolationMode ==
"bezier") {
504 QString tangentsMode = keyframeNode.toElement().attribute(
"tangents");
505 if (tangentsMode ==
"smooth") {
507 }
else if (tangentsMode ==
"sharp") {
512 QPointF rightTangent;
515 scalarKey->setInterpolationTangents(leftTangent, rightTangent);
517 return QPair<int, KisKeyframeSP>(time, keyframe);
float value(const T *src, size_t ch)
KisKeyframeChannel stores and manages KisKeyframes. Maps units of time to virtual keyframe values....
QSet< int > allKeyframeTimes() const
Get a set of all integer times that map to a keyframe.
int previousKeyframeTime(const int time) const
virtual void insertKeyframe(int time, KisKeyframeSP keyframe, KUndo2Command *parentUndoCmd=nullptr)
Insert an existing keyframe into the channel at the specified time.
virtual void removeKeyframe(int time, KUndo2Command *parentUndoCmd=nullptr)
Remove a keyframe from the channel at the specified time.
int firstKeyframeTime() const
KisKeyframeSP keyframeAt(int time) const
Get a keyframe at specified time. Used primarily when the value of a given keyframe is needed.
static void copyKeyframe(const KisKeyframeChannel *sourceChannel, int sourceTime, KisKeyframeChannel *targetChannel, int targetTime, KUndo2Command *parentUndoCmd=nullptr)
Copy a keyframe across channel(s) at the specified times.
const TimeKeyframeMap & constKeys() const
void addKeyframe(int time, KUndo2Command *parentUndoCmd=nullptr)
Add a new keyframe to the channel at the specified time.
virtual KisTimeSpan affectedFrames(int time) const
Get the set of frames affected by any changes to the value or content of the active keyframe at the g...
int activeKeyframeTime() const
int lastKeyframeTime() const
Q_DECL_DEPRECATED void workaroundBrokenFrameTimeBug(int *time)
Between Krita 4.1 and 4.4 Krita had a bug which resulted in creating frames with negative time stamp....
int nextKeyframeTime(const int time) const
Krita's base keyframe class. Mainly contained by KisKeyframeChannels. A core part of Krita's animatio...
The KisScalarKeyframeChannel is a concrete KisKeyframeChannel subclass that stores and manages KisSca...
KisScalarKeyframeChannel(const KoID &id, KisDefaultBoundsBaseSP bounds)
virtual KisTimeSpan affectedFrames(int time) const override
Get the set of frames affected by any changes to the value or content of the active keyframe at the g...
virtual QRect affectedRect(int time) const override
bool isCurrentTimeAffectedBy(int keyTime)
void setDefaultInterpolationMode(KisScalarKeyframe::InterpolationMode mode)
qreal valueAt(int time) const
Quickly get the interpolated value at the given time.
static void normalizeTangents(const QPointF point1, QPointF &rightTangent, QPointF &leftTangent, const QPointF point2)
static qreal cubicBezier(qreal p0, qreal delta1, qreal delta2, qreal p3, qreal t)
virtual KisTimeSpan identicalFrames(int time) const override
Get a span of times for which the channel gives identical results compared to frame at a given time....
static qreal findCubicCurveParameter(int time0, qreal delta0, qreal delta1, int time1, int time)
virtual void saveKeyframe(KisKeyframeSP keyframe, QDomElement keyframeElement, const QString &layerFilename) override
QScopedPointer< Private > m_d
void setDefaultValue(qreal value)
virtual KisKeyframeSP createKeyframe() override
Virtual keyframe creation function. Derived classes implement this function based on the needs of the...
void addScalarKeyframe(int time, qreal value, KUndo2Command *parentUndoCmd=nullptr)
virtual QPair< int, KisKeyframeSP > loadKeyframe(const QDomElement &keyframeNode) override
virtual void removeKeyframe(int time, KUndo2Command *parentUndoCmd=nullptr) override
Remove a keyframe from the channel at the specified time.
static QPointF interpolate(QPointF point1, QPointF rightTangent, QPointF leftTangent, QPointF point2, qreal t)
QSharedPointer< ScalarKeyframeLimits > limits() const
void setLimits(qreal low, qreal high)
~KisScalarKeyframeChannel() override
virtual void insertKeyframe(int time, KisKeyframeSP keyframe, KUndo2Command *parentUndoCmd=nullptr) override
Insert an existing keyframe into the channel at the specified time.
The KisScalarKeyframe class is a concrete subclass of KisKeyframe that wraps a scalar value and inter...
KisScalarKeyframe(qreal value, QSharedPointer< ScalarKeyframeLimits > limits)
InterpolationMode
Controls the type of interpolation between this KisScalarKeyframe and the next.
InterpolationMode interpolationMode() const
KisKeyframeSP duplicate(KisKeyframeChannel *newChannel=0) override
friend class KisScalarKeyframeUpdateCommand
QPointF rightTangent() const
TangentsMode m_tangentsMode
void setValue(qreal val, KUndo2Command *parentUndoCmd=nullptr)
InterpolationMode m_interpolationMode
void sigChanged(const KisScalarKeyframe *scalarKey)
QPointF leftTangent() const
void setInterpolationTangents(QPointF leftTangent, QPointF rightTangent, KUndo2Command *parentUndoCmd=nullptr)
void setInterpolationMode(InterpolationMode mode, KUndo2Command *parentUndoCmd=nullptr)
TangentsMode
Controls the behavior of the left and right tangents on a given keyframe for different curve shapes.
void setTangentsMode(TangentsMode mode, KUndo2Command *parentUndoCmd=nullptr)
QWeakPointer< ScalarKeyframeLimits > m_channelLimits
TangentsMode tangentsMode() const
void setLimits(QSharedPointer< ScalarKeyframeLimits > limits)
bool contains(int time) const
static KisTimeSpan infinite(int start)
static KisTimeSpan fromTimeToTime(int start, int end)
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
#define KIS_ASSERT_RECOVER_BREAK(cond)
QSharedPointer< T > toQShared(T *ptr)
void saveValue(QDomElement *parent, const QString &tag, const QSize &size)
double toDouble(const QString &str, bool *ok=nullptr)
bool loadValue(const QDomElement &e, float *v)
QString toString(const QString &value)
virtual QRect exactBounds() const
KisScalarKeyframe::InterpolationMode defaultInterpolationMode
QSharedPointer< ScalarKeyframeLimits > limits
Private(const Private &rhs)
This structure represents an optional limited range of values that be handled by KisScalarKeyframeCha...