Krita Source Code Documentation
Loading...
Searching...
No Matches
KisScalarKeyframeChannel Class Reference

The KisScalarKeyframeChannel is a concrete KisKeyframeChannel subclass that stores and manages KisScalarKeyframes. More...

#include <kis_scalar_keyframe_channel.h>

+ Inheritance diagram for KisScalarKeyframeChannel:

Classes

struct  Private
 

Public Member Functions

void addScalarKeyframe (int time, qreal value, KUndo2Command *parentUndoCmd=nullptr)
 
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 given time.
 
qreal currentValue ()
 
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. NOTE: This set may be different than the set of affected frames due to interpolation.
 
virtual void insertKeyframe (int time, KisKeyframeSP keyframe, KUndo2Command *parentUndoCmd=nullptr) override
 Insert an existing keyframe into the channel at the specified time.
 
bool isCurrentTimeAffectedBy (int keyTime)
 
 KisScalarKeyframeChannel (const KisScalarKeyframeChannel &rhs)
 
 KisScalarKeyframeChannel (const KoID &id, KisDefaultBoundsBaseSP bounds)
 
QSharedPointer< ScalarKeyframeLimitslimits () const
 
virtual void removeKeyframe (int time, KUndo2Command *parentUndoCmd=nullptr) override
 Remove a keyframe from the channel at the specified time.
 
void removeLimits ()
 
void setDefaultInterpolationMode (KisScalarKeyframe::InterpolationMode mode)
 
void setDefaultValue (qreal value)
 
void setLimits (qreal low, qreal high)
 
qreal valueAt (int time) const
 Quickly get the interpolated value at the given time.
 
 ~KisScalarKeyframeChannel () override
 
- Public Member Functions inherited from KisKeyframeChannel
KisKeyframeSP activeKeyframeAt (int time) const
 
template<class KeyframeType >
QSharedPointer< KeyframeType > activeKeyframeAt (int time) const
 
int activeKeyframeTime () const
 
int activeKeyframeTime (int time) const
 Get the time of the active keyframe. Useful for snapping any time to that of the most recent keyframe.
 
void addKeyframe (int time, KUndo2Command *parentUndoCmd=nullptr)
 Add a new keyframe to the channel at the specified time.
 
QSet< int > allKeyframeTimes () const
 Get a set of all integer times that map to a keyframe.
 
int channelHash () const
 Calculates a pseudo-unique hash based on the relevant internal state of the channel.
 
void copyKeyframe (int sourceTime, int targetTime, KUndo2Command *parentUndoCmd=nullptr)
 
int firstKeyframeTime () const
 
QString id () const
 
KisKeyframeSP keyframeAt (int time) const
 Get a keyframe at specified time. Used primarily when the value of a given keyframe is needed.
 
template<class KeyframeType >
QSharedPointer< KeyframeType > keyframeAt (int time) const
 
int keyframeCount () const
 
 KisKeyframeChannel (const KisKeyframeChannel &rhs)
 
 KisKeyframeChannel (const KoID &id, KisDefaultBoundsBaseSP bounds)
 
int lastKeyframeTime () const
 
virtual void loadXML (const QDomElement &channelNode)
 
int lookupKeyframeTime (KisKeyframeSP toLookup)
 Search for the time for a given keyframe. (Reverse map lookup, so use sparingly.)
 
void moveKeyframe (int sourceTime, int targetTime, KUndo2Command *parentUndoCmd=nullptr)
 
QString name () const
 
int nextKeyframeTime (const int time) const
 
KisNodeWSP node () const
 
int previousKeyframeTime (const int time) const
 
void setDefaultBounds (KisDefaultBoundsBaseSP bounds)
 
void setNode (KisNodeWSP node)
 
void swapKeyframes (int timeA, int timeB, KUndo2Command *parentUndoCmd=nullptr)
 
virtual QDomElement toXML (QDomDocument doc, const QString &layerFilename)
 
 ~KisKeyframeChannel () override
 

Static Public Member Functions

static QPointF interpolate (QPointF point1, QPointF rightTangent, QPointF leftTangent, QPointF point2, qreal t)
 
- Static Public Member Functions inherited from KisKeyframeChannel
static KoID channelIdToKoId (const QString &id)
 
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.
 
static void moveKeyframe (KisKeyframeChannel *sourceChannel, int sourceTime, KisKeyframeChannel *targetChannel, int targetTime, KUndo2Command *parentUndoCmd=nullptr)
 Move a keyframe across channel(s) at the specified times.
 
static void swapKeyframes (KisKeyframeChannel *channelA, int timeA, KisKeyframeChannel *channelB, int timeB, KUndo2Command *parentUndoCmd=nullptr)
 Swap two keyframes across channel(s) at the specified times.
 

Private Member Functions

virtual QRect affectedRect (int time) const override
 
virtual KisKeyframeSP createKeyframe () override
 Virtual keyframe creation function. Derived classes implement this function based on the needs of their specific KisKeyframe subclasses.
 
virtual QPair< int, KisKeyframeSPloadKeyframe (const QDomElement &keyframeNode) override
 
virtual void saveKeyframe (KisKeyframeSP keyframe, QDomElement keyframeElement, const QString &layerFilename) override
 

Static Private Member Functions

static qreal cubicBezier (qreal p0, qreal delta1, qreal delta2, qreal p3, qreal t)
 
static qreal findCubicCurveParameter (int time0, qreal delta0, qreal delta1, int time1, int time)
 
static void normalizeTangents (const QPointF point1, QPointF &rightTangent, QPointF &leftTangent, const QPointF point2)
 

Private Attributes

QScopedPointer< Privatem_d
 

Additional Inherited Members

- Signals inherited from KisKeyframeChannel
void sigAddedKeyframe (const KisKeyframeChannel *channel, int time)
 This signal is emitted just AFTER a keyframe was added to the channel.
 
void sigAnyKeyframeChange ()
 
void sigKeyframeAboutToBeRemoved (const KisKeyframeChannel *channel, int time)
 This signal is emitted just BEFORE a keyframe is removed from the channel.
 
void sigKeyframeChanged (const KisKeyframeChannel *channel, int time)
 This signal is emitted just AFTER a non-raster keyframe was changed its value.
 
void sigKeyframeHasBeenRemoved (const KisKeyframeChannel *channel, int time)
 This signal is emitted just AFTER a keyframe is removed from the channel.
 
- Static Public Attributes inherited from KisKeyframeChannel
static const KoID Opacity = KoID("opacity", ki18n("Opacity"))
 
static const KoID PositionX = KoID("transform_pos_x", ki18n("Position (X)"))
 
static const KoID PositionY = KoID("transform_pos_y", ki18n("Position (Y)"))
 
static const KoID Raster = KoID("content", ki18n("Content"))
 
static const KoID RotationX = KoID("transform_rotation_x", ki18n("Rotation (X)"))
 
static const KoID RotationY = KoID("transform_rotation_y", ki18n("Rotation (Y)"))
 
static const KoID RotationZ = KoID("transform_rotation_z", ki18n("Rotation (Z)"))
 
static const KoID ScaleX = KoID("transform_scale_x", ki18n("Scale (X)"))
 
static const KoID ScaleY = KoID("transform_scale_y", ki18n("Scale (Y)"))
 
static const KoID ShearX = KoID("transform_shear_x", ki18n("Shear (X)"))
 
static const KoID ShearY = KoID("transform_shear_y", ki18n("Shear (Y)"))
 
static const KoID TransformArguments
 
- Protected Types inherited from KisKeyframeChannel
typedef QMap< int, KisKeyframeSPTimeKeyframeMap
 
- Protected Member Functions inherited from KisKeyframeChannel
const TimeKeyframeMapconstKeys () const
 
int currentTime () const
 
TimeKeyframeMapkeys ()
 
virtual void removeKeyframeImpl (int time, KUndo2Command *parentUndoCmd)
 
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. The bug has been fixed, but there might be some files still in the wild.
 

Detailed Description

The KisScalarKeyframeChannel is a concrete KisKeyframeChannel subclass that stores and manages KisScalarKeyframes.

This class maps units of time (in frames) to points along a curve for the animation of various interpolated scalar parameters within Krita. Each scalar channel can be provided with default values and interpolation modes, as well as an optional ScalarKeyframeLimits object that can be used to limit the range of possible values.

Generally, each scalar channel will be represented as an individual curve within Krita's KisAnimationCurvesDocker.

Definition at line 119 of file kis_scalar_keyframe_channel.h.

Constructor & Destructor Documentation

◆ KisScalarKeyframeChannel() [1/2]

KisScalarKeyframeChannel::KisScalarKeyframeChannel ( const KoID & id,
KisDefaultBoundsBaseSP bounds )

Definition at line 167 of file kis_scalar_keyframe_channel.cpp.

169 , m_d(new Private)
170{
171}
KisKeyframeChannel(const KoID &id, KisDefaultBoundsBaseSP bounds)
#define bounds(x, a, b)

◆ KisScalarKeyframeChannel() [2/2]

KisScalarKeyframeChannel::KisScalarKeyframeChannel ( const KisScalarKeyframeChannel & rhs)

Definition at line 173 of file kis_scalar_keyframe_channel.cpp.

174 : KisKeyframeChannel(rhs)
175{
176 m_d.reset(new Private(*rhs.m_d));
177
178 Q_FOREACH (int time, rhs.constKeys().keys()) {
179 KisKeyframeChannel::copyKeyframe(&rhs, time, this, time);
180 }
181}
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

References KisKeyframeChannel::constKeys(), KisKeyframeChannel::copyKeyframe(), and m_d.

◆ ~KisScalarKeyframeChannel()

KisScalarKeyframeChannel::~KisScalarKeyframeChannel ( )
override

Definition at line 183 of file kis_scalar_keyframe_channel.cpp.

184{
185}

Member Function Documentation

◆ addScalarKeyframe()

void KisScalarKeyframeChannel::addScalarKeyframe ( int time,
qreal value,
KUndo2Command * parentUndoCmd = nullptr )

Utility for adding keyframe with non-default value.

Definition at line 187 of file kis_scalar_keyframe_channel.cpp.

187 {
188 KisScalarKeyframeSP scalarKey = keyframeAt<KisScalarKeyframe>(time);
189 if (!scalarKey) {
190 addKeyframe(time, parentUndoCmd);
191 scalarKey = keyframeAt<KisScalarKeyframe>(time);
192 }
193
194 if (scalarKey) {
195 scalarKey->setValue(value, parentUndoCmd);
196 }
197}
float value(const T *src, size_t ch)
void addKeyframe(int time, KUndo2Command *parentUndoCmd=nullptr)
Add a new keyframe to the channel at the specified time.

References KisKeyframeChannel::addKeyframe(), and value().

◆ affectedFrames()

KisTimeSpan KisScalarKeyframeChannel::affectedFrames ( int time) const
overridevirtual

Get the set of frames affected by any changes to the value or content of the active keyframe at the given time.

Reimplemented from KisKeyframeChannel.

Definition at line 336 of file kis_scalar_keyframe_channel.cpp.

337{
339
340 const int activeKeyTime = activeKeyframeTime(time);
341 const int previousKeyTime = previousKeyframeTime(activeKeyTime);
342 const KisScalarKeyframeSP prevScalarKey = keyframeAt<KisScalarKeyframe>(previousKeyTime);
343
344 if(prevScalarKey) {
345 // In the case that a previous keyframe is present with a non-constant interpolation mode,
346 // the affected frames must include all the frames just after the previous keyframe.
347 if (prevScalarKey->interpolationMode() == KisScalarKeyframe::Constant) {
348 return normalSpan;
349 } else {
350 return normalSpan | KisTimeSpan::fromTimeToTime(previousKeyTime + 1, activeKeyTime);
351 }
352 } else {
353 const KisScalarKeyframeSP firstScalarKey = keyframeAt<KisScalarKeyframe>(firstKeyframeTime());
354 if (!firstScalarKey) {
355 return KisTimeSpan::infinite(0);
356 }
357 return normalSpan | KisTimeSpan::fromTimeToTime(0, activeKeyTime);
358 }
359}
int previousKeyframeTime(const int time) const
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...
static KisTimeSpan infinite(int start)
static KisTimeSpan fromTimeToTime(int start, int end)

References KisKeyframeChannel::activeKeyframeTime(), KisKeyframeChannel::affectedFrames(), KisScalarKeyframe::Constant, KisKeyframeChannel::firstKeyframeTime(), KisTimeSpan::fromTimeToTime(), KisTimeSpan::infinite(), and KisKeyframeChannel::previousKeyframeTime().

◆ affectedRect()

QRect KisScalarKeyframeChannel::affectedRect ( int time) const
overrideprivatevirtual

The rect that is affected by a frame at the given time

Implements KisKeyframeChannel.

Definition at line 449 of file kis_scalar_keyframe_channel.cpp.

450{
451 Q_UNUSED(time);
452
453 if (node()) {
454 return node()->exactBounds();
455 } else {
456 return QRect();
457 }
458}
virtual QRect exactBounds() const

References KisBaseNode::exactBounds(), and KisKeyframeChannel::node().

◆ createKeyframe()

KisKeyframeSP KisScalarKeyframeChannel::createKeyframe ( )
overrideprivatevirtual

Virtual keyframe creation function. Derived classes implement this function based on the needs of their specific KisKeyframe subclasses.

Implements KisKeyframeChannel.

Definition at line 442 of file kis_scalar_keyframe_channel.cpp.

443{
444 KisScalarKeyframe *keyframe = new KisScalarKeyframe(m_d->defaultValue, m_d->limits);
445 keyframe->setInterpolationMode(m_d->defaultInterpolationMode);
446 return toQShared(keyframe);
447}
The KisScalarKeyframe class is a concrete subclass of KisKeyframe that wraps a scalar value and inter...
void setInterpolationMode(InterpolationMode mode, KUndo2Command *parentUndoCmd=nullptr)
QSharedPointer< T > toQShared(T *ptr)

References m_d, KisScalarKeyframe::setInterpolationMode(), and toQShared().

◆ cubicBezier()

qreal KisScalarKeyframeChannel::cubicBezier ( qreal p0,
qreal delta1,
qreal delta2,
qreal p3,
qreal t )
staticprivate

Definition at line 416 of file kis_scalar_keyframe_channel.cpp.

416 {
417 qreal p1 = p0 + delta1;
418 qreal p2 = p3 + delta2;
419
420 qreal c = 1-t;
421 return c*c*c * p0 + 3*c*c*t * p1 + 3*c*t*t * p2 + t*t*t * p3;
422}
QPointF p0
QPointF p2
QPointF p3
QPointF p1

References p0, p1, p2, and p3.

◆ currentValue()

qreal KisScalarKeyframeChannel::currentValue ( )
inline

Definition at line 138 of file kis_scalar_keyframe_channel.h.

138{ return valueAt(currentTime()); }
qreal valueAt(int time) const
Quickly get the interpolated value at the given time.

◆ findCubicCurveParameter()

qreal KisScalarKeyframeChannel::findCubicCurveParameter ( int time0,
qreal delta0,
qreal delta1,
int time1,
int time )
staticprivate

Definition at line 393 of file kis_scalar_keyframe_channel.cpp.

394{
395 if (time == time0) return 0.0;
396 if (time == time1) return 1.0;
397
398 qreal min_t = 0.0;
399 qreal max_t = 1.0;
400
401 while (true) {
402 qreal t = (max_t + min_t) / 2;
403 qreal time_t = cubicBezier(time0, delta0, delta1, time1, t);
404
405 if (time_t < time - 0.05) {
406 min_t = t;
407 } else if (time_t > time + 0.05) {
408 max_t = t;
409 } else {
410 // Close enough
411 return t;
412 }
413 }
414}
static qreal cubicBezier(qreal p0, qreal delta1, qreal delta2, qreal p3, qreal t)

References cubicBezier().

◆ identicalFrames()

KisTimeSpan KisScalarKeyframeChannel::identicalFrames ( int time) const
overridevirtual

Get a span of times for which the channel gives identical results compared to frame at a given time. NOTE: This set may be different than the set of affected frames due to interpolation.

Reimplemented from KisKeyframeChannel.

Definition at line 361 of file kis_scalar_keyframe_channel.cpp.

362{
363 //Failsafe == no keys should mean all frames are identical!
364 if (allKeyframeTimes().count() == 0) {
365 return KisTimeSpan::infinite(0);
366 }
367
368 KisScalarKeyframeSP activeScalarKey = activeKeyframeAt<KisScalarKeyframe>(time);
369 if ( activeScalarKey &&
370 activeScalarKey->interpolationMode() != KisScalarKeyframe::Constant &&
371 activeScalarKey != keyframeAt(lastKeyframeTime()) ) {
372 //TODO: Two keyframes should be considered identical if linear with same value..
373 //TODO: Also, if bezier with same value AND tangents lie between points.
374 // (tangenty == keyframey)
375 return KisTimeSpan::fromTimeToTime(time, time);
376 }
377
378 const int nextKeyTime = nextKeyframeTime(time);
379
380 //Before the first frame => there's no active frame but a valid next frame.
381 if (!activeScalarKey && keyframeAt(nextKeyTime)) {
382 return KisTimeSpan::fromTimeToTime(0, nextKeyTime);
383 }
384
385 //No next frame, all frames after are identical.
386 if (!keyframeAt(nextKeyTime)) {
388 }
389
390 return KisTimeSpan::fromTimeToTime(activeKeyframeTime(time), nextKeyTime - 1);
391}
QSet< int > allKeyframeTimes() const
Get a set of all integer times that map to a keyframe.
KisKeyframeSP keyframeAt(int time) const
Get a keyframe at specified time. Used primarily when the value of a given keyframe is needed.
int nextKeyframeTime(const int time) const

References KisKeyframeChannel::activeKeyframeTime(), KisKeyframeChannel::allKeyframeTimes(), KisScalarKeyframe::Constant, KisTimeSpan::fromTimeToTime(), KisTimeSpan::infinite(), KisKeyframeChannel::keyframeAt(), KisKeyframeChannel::lastKeyframeTime(), and KisKeyframeChannel::nextKeyframeTime().

◆ insertKeyframe()

void KisScalarKeyframeChannel::insertKeyframe ( int time,
KisKeyframeSP keyframe,
KUndo2Command * parentUndoCmd = nullptr )
overridevirtual

Insert an existing keyframe into the channel at the specified time.

Reimplemented from KisKeyframeChannel.

Definition at line 310 of file kis_scalar_keyframe_channel.cpp.

311{
312 KisScalarKeyframeSP scalarKeyframe = keyframe.dynamicCast<KisScalarKeyframe>();
313 if (scalarKeyframe) {
314 scalarKeyframe->valueChangedChannelConnection =
315 QObject::connect(scalarKeyframe.data(),
317 [this, time](const KisScalarKeyframe* key){
318 Q_UNUSED(key);
319 Q_EMIT sigKeyframeChanged(this, time);
320 });
321 }
322
323 KisKeyframeChannel::insertKeyframe(time, keyframe, parentUndoCmd);
324}
virtual void insertKeyframe(int time, KisKeyframeSP keyframe, KUndo2Command *parentUndoCmd=nullptr)
Insert an existing keyframe into the channel at the specified time.
void sigChanged(const KisScalarKeyframe *scalarKey)

References KisKeyframeChannel::insertKeyframe(), and KisScalarKeyframe::sigChanged().

◆ interpolate()

QPointF KisScalarKeyframeChannel::interpolate ( QPointF point1,
QPointF rightTangent,
QPointF leftTangent,
QPointF point2,
qreal t )
static

Definition at line 300 of file kis_scalar_keyframe_channel.cpp.

301{
302 normalizeTangents(point1, rightTangent, leftTangent, point2);
303
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);
306
307 return QPointF(x,y);
308}
static void normalizeTangents(const QPointF point1, QPointF &rightTangent, QPointF &leftTangent, const QPointF point2)

References cubicBezier(), and normalizeTangents().

◆ isCurrentTimeAffectedBy()

bool KisScalarKeyframeChannel::isCurrentTimeAffectedBy ( int keyTime)

Definition at line 286 of file kis_scalar_keyframe_channel.cpp.

286 {
288}
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...
bool contains(int time) const

References KisKeyframeChannel::activeKeyframeTime(), affectedFrames(), KisTimeSpan::contains(), and KisKeyframeChannel::currentTime().

◆ limits()

QSharedPointer< ScalarKeyframeLimits > KisScalarKeyframeChannel::limits ( ) const

Definition at line 199 of file kis_scalar_keyframe_channel.cpp.

200{
201 return m_d->limits;
202}

References m_d.

◆ loadKeyframe()

QPair< int, KisKeyframeSP > KisScalarKeyframeChannel::loadKeyframe ( const QDomElement & keyframeNode)
overrideprivatevirtual

Implements KisKeyframeChannel.

Definition at line 483 of file kis_scalar_keyframe_channel.cpp.

484{
485 int time = keyframeNode.toElement().attribute("time").toInt();
487
488 qreal value = KisDomUtils::toDouble(keyframeNode.toElement().attribute("value"));
489
490 KisScalarKeyframeSP keyframe = createKeyframe().dynamicCast<KisScalarKeyframe>();
491 keyframe->setValue(value);
492
493 KisScalarKeyframeSP scalarKey = keyframe.dynamicCast<KisScalarKeyframe>();
494
495 QString interpolationMode = keyframeNode.toElement().attribute("interpolation");
496 if (interpolationMode == "constant") {
497 scalarKey->setInterpolationMode(KisScalarKeyframe::Constant);
498 } else if (interpolationMode == "linear") {
499 scalarKey->setInterpolationMode(KisScalarKeyframe::Linear);
500 } else if (interpolationMode == "bezier") {
501 scalarKey->setInterpolationMode(KisScalarKeyframe::Bezier);
502 }
503
504 QString tangentsMode = keyframeNode.toElement().attribute("tangents");
505 if (tangentsMode == "smooth") {
506 scalarKey->setTangentsMode(KisScalarKeyframe::Smooth);
507 } else if (tangentsMode == "sharp") {
508 scalarKey->setTangentsMode(KisScalarKeyframe::Sharp);
509 }
510
511 QPointF leftTangent;
512 QPointF rightTangent;
513 KisDomUtils::loadValue(keyframeNode, "leftTangent", &leftTangent);
514 KisDomUtils::loadValue(keyframeNode, "rightTangent", &rightTangent);
515 scalarKey->setInterpolationTangents(leftTangent, rightTangent);
516
517 return QPair<int, KisKeyframeSP>(time, keyframe);
518}
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....
virtual KisKeyframeSP createKeyframe() override
Virtual keyframe creation function. Derived classes implement this function based on the needs of the...
double toDouble(const QString &str, bool *ok=nullptr)
bool loadValue(const QDomElement &e, float *v)

References KisScalarKeyframe::Bezier, KisScalarKeyframe::Constant, createKeyframe(), KisScalarKeyframe::Linear, KisDomUtils::loadValue(), KisScalarKeyframe::Sharp, KisScalarKeyframe::Smooth, KisDomUtils::toDouble(), value(), and KisKeyframeChannel::workaroundBrokenFrameTimeBug().

◆ normalizeTangents()

void KisScalarKeyframeChannel::normalizeTangents ( const QPointF point1,
QPointF & rightTangent,
QPointF & leftTangent,
const QPointF point2 )
staticprivate

Definition at line 424 of file kis_scalar_keyframe_channel.cpp.

425{
426 // To ensure that the curve is monotonic wrt time,
427 // check that control points lie between the endpoints.
428 // If not, force them into range by scaling down the tangents
429
430 float interval = point2.x() - point1.x();
431 if (rightTangent.x() < 0) rightTangent *= 0;
432 if (leftTangent.x() > 0) leftTangent *= 0;
433
434 if (rightTangent.x() > interval) {
435 rightTangent *= interval / rightTangent.x();
436 }
437 if (leftTangent.x() < -interval) {
438 leftTangent *= interval / -leftTangent.x();
439 }
440}

◆ removeKeyframe()

void KisScalarKeyframeChannel::removeKeyframe ( int time,
KUndo2Command * parentUndoCmd = nullptr )
overridevirtual

Remove a keyframe from the channel at the specified time.

Reimplemented from KisKeyframeChannel.

Definition at line 326 of file kis_scalar_keyframe_channel.cpp.

327{
328 KisScalarKeyframeSP keyframe = keyframeAt<KisScalarKeyframe>(time);
329 if (keyframe) {
330 disconnect(keyframe->valueChangedChannelConnection);
331 }
332
333 KisKeyframeChannel::removeKeyframe(time, parentUndoCmd);
334}
virtual void removeKeyframe(int time, KUndo2Command *parentUndoCmd=nullptr)
Remove a keyframe from the channel at the specified time.

References KisKeyframeChannel::removeKeyframe().

◆ removeLimits()

void KisScalarKeyframeChannel::removeLimits ( )

Remove limits, allowing channel to operate within any range of values.

Definition at line 215 of file kis_scalar_keyframe_channel.cpp.

216{
217 if (m_d->limits) {
218 m_d->limits.reset();
219 }
220}

References m_d.

◆ saveKeyframe()

void KisScalarKeyframeChannel::saveKeyframe ( KisKeyframeSP keyframe,
QDomElement keyframeElement,
const QString & layerFilename )
overrideprivatevirtual

Implements KisKeyframeChannel.

Definition at line 460 of file kis_scalar_keyframe_channel.cpp.

461{
462 Q_UNUSED(layerFilename);
463 KisScalarKeyframeSP scalarKey = keyframe.dynamicCast<KisScalarKeyframe>();
465 const qreal value = scalarKey->value();
466 keyframeElement.setAttribute("value", KisDomUtils::toString(value));
467
468 QString interpolationMode;
469 if (scalarKey->interpolationMode() == KisScalarKeyframe::Constant) interpolationMode = "constant";
470 if (scalarKey->interpolationMode() == KisScalarKeyframe::Linear) interpolationMode = "linear";
471 if (scalarKey->interpolationMode() == KisScalarKeyframe::Bezier) interpolationMode = "bezier";
472
473 QString tangentsMode;
474 if (scalarKey->tangentsMode() == KisScalarKeyframe::Smooth) tangentsMode = "smooth";
475 if (scalarKey->tangentsMode() == KisScalarKeyframe::Sharp) tangentsMode = "sharp";
476
477 keyframeElement.setAttribute("interpolation", interpolationMode);
478 keyframeElement.setAttribute("tangents", tangentsMode);
479 KisDomUtils::saveValue(&keyframeElement, "leftTangent", scalarKey->leftTangent());
480 KisDomUtils::saveValue(&keyframeElement, "rightTangent", scalarKey->rightTangent());
481}
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
void saveValue(QDomElement *parent, const QString &tag, const QSize &size)
QString toString(const QString &value)

References KisScalarKeyframe::Bezier, KisScalarKeyframe::Constant, KIS_SAFE_ASSERT_RECOVER_RETURN, KisScalarKeyframe::Linear, KisDomUtils::saveValue(), KisScalarKeyframe::Sharp, KisScalarKeyframe::Smooth, KisDomUtils::toString(), and value().

◆ setDefaultInterpolationMode()

void KisScalarKeyframeChannel::setDefaultInterpolationMode ( KisScalarKeyframe::InterpolationMode mode)

Definition at line 295 of file kis_scalar_keyframe_channel.cpp.

296{
297 m_d->defaultInterpolationMode = mode;
298}

References m_d.

◆ setDefaultValue()

void KisScalarKeyframeChannel::setDefaultValue ( qreal value)

Definition at line 290 of file kis_scalar_keyframe_channel.cpp.

291{
292 m_d->defaultValue = value;
293}

References m_d, and value().

◆ setLimits()

void KisScalarKeyframeChannel::setLimits ( qreal low,
qreal high )

Limit channel within scalar value range.

Definition at line 204 of file kis_scalar_keyframe_channel.cpp.

205{
206 m_d->limits = toQShared(new ScalarKeyframeLimits(low, high));
207 QSet<int> keyEntries = allKeyframeTimes();
208 foreach (const int &time, keyEntries) {
209 KisScalarKeyframeSP scalarKey = keyframeAt<KisScalarKeyframe>(time);
210 scalarKey->setLimits(m_d->limits);
211 scalarKey->setValue(scalarKey->value());
212 }
213}
This structure represents an optional limited range of values that be handled by KisScalarKeyframeCha...

References KisKeyframeChannel::allKeyframeTimes(), m_d, and toQShared().

◆ valueAt()

qreal KisScalarKeyframeChannel::valueAt ( int time) const

Quickly get the interpolated value at the given time.

Definition at line 222 of file kis_scalar_keyframe_channel.cpp.

223{
224 const int activeKeyTime = activeKeyframeTime(time);
225 KisScalarKeyframeSP activeKey = keyframeAt<KisScalarKeyframe>(activeKeyTime);
226 KisScalarKeyframeSP nextKeyframe = keyframeAt<KisScalarKeyframe>(nextKeyframeTime(time));
227 qreal result = qQNaN();
228
229 if (activeKey) {
230 if (!nextKeyframe) {
231 result = activeKey->value();
232 } else {
233 switch (activeKey->interpolationMode()) {
235 result = activeKey->value();
236 break;
237 }
239 const int nextKeyTime = nextKeyframeTime(time);
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);
245 } else {
246 result = activeKeyValue;
247 }
248 break;
249 }
251 const int nextKeyTime = nextKeyframeTime(time);
252 const KisScalarKeyframeSP nextKey = keyframeAt<KisScalarKeyframe>(nextKeyTime);
253 QPointF point0 = QPointF(activeKeyTime, activeKey->value());
254 QPointF point1 = QPointF(nextKeyTime, nextKey->value());
255
256 QPointF tangent0 = activeKey->rightTangent();
257 QPointF tangent1 = nextKey->leftTangent();
258
259 normalizeTangents(point0, tangent0, tangent1, point1);
260 qreal t = KisScalarKeyframeChannel::findCubicCurveParameter(point0.x(), tangent0.x(), tangent1.x(), point1.x(), time);
261 result = KisScalarKeyframeChannel::interpolate(point0, tangent0, tangent1, point1, t).y();
262 break;
263 }
264 default: {
266 break;
267 }
268 }
269 }
270 } else {
271 if (nextKeyframe) {
272 result = nextKeyframe->value();
273 } else {
274 return qQNaN();
275 }
276 }
277
278 // Output value must be also be clamped to account for interpolation.
279 if (m_d->limits) {
280 return m_d->limits->clamp(result);
281 } else {
282 return result;
283 }
284}
static qreal findCubicCurveParameter(int time0, qreal delta0, qreal delta1, int time1, int time)
static QPointF interpolate(QPointF point1, QPointF rightTangent, QPointF leftTangent, QPointF point2, qreal t)
#define KIS_ASSERT_RECOVER_BREAK(cond)
Definition kis_assert.h:65

References KisKeyframeChannel::activeKeyframeTime(), KisScalarKeyframe::Bezier, KisScalarKeyframe::Constant, findCubicCurveParameter(), interpolate(), KIS_ASSERT_RECOVER_BREAK, KisScalarKeyframe::Linear, m_d, KisKeyframeChannel::nextKeyframeTime(), and normalizeTangents().

Member Data Documentation

◆ m_d

QScopedPointer<Private> KisScalarKeyframeChannel::m_d
private

Definition at line 163 of file kis_scalar_keyframe_channel.h.


The documentation for this class was generated from the following files: