File indexing completed on 2024-05-12 15:58:40

0001 /*
0002  *  SPDX-FileCopyrightText: 2015 Jouni Pentikäinen <joupent@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 #ifndef _KIS_SCALAR_KEYFRAME_CHANNEL_H
0007 #define _KIS_SCALAR_KEYFRAME_CHANNEL_H
0008 
0009 #include "kis_keyframe_channel.h"
0010 
0011 
0012 /** @brief This structure represents an optional limited range of
0013  * values that be handled by KisScalarKeyframeChannel.
0014 */
0015 struct ScalarKeyframeLimits {
0016     qreal lower;
0017     qreal upper;
0018 
0019     ScalarKeyframeLimits(qreal x, qreal y){
0020         KIS_ASSERT(x != y);
0021 
0022         // Supports (high, low) or (low, high) assignment.
0023         lower = x < y ? x : y;
0024         upper = x > y ? x : y;
0025     }
0026 
0027     /** Clamp input value within limits. */
0028     qreal clamp(qreal value){
0029         value = value < lower ? lower : value;
0030         value = value > upper ? upper : value;
0031         return value;
0032     }
0033 };
0034 
0035 
0036 /** @brief The KisScalarKeyframe class is a concrete subclass of KisKeyframe
0037  * that wraps a scalar value and interpolation parameters.
0038 */
0039 class KRITAIMAGE_EXPORT KisScalarKeyframe : public KisKeyframe
0040 {
0041     Q_OBJECT
0042 public:
0043     /** @brief Controls the type of interpolation between
0044      * this KisScalarKeyframe and the next. */
0045     enum InterpolationMode {
0046         Constant, /**< Constant value until the next keyframe. */
0047         Linear, /**< Linear interpolation between this keyframe and the next. */
0048         Bezier /**< Bezier curve between this keyframe and the next,
0049                  controlled by individual tangent handles on each. */
0050     };
0051 
0052     /** @brief Controls the behavior of the left and right
0053      * tangents on a given keyframe for different curve shapes. */
0054     enum TangentsMode {
0055         Sharp, /**< Independent control of each tangent for sudden, sharp curve changes. */
0056         Smooth /**< Tangents are locked inline for smooth transitions across key values. */
0057     };
0058 
0059     KisScalarKeyframe(qreal value, QSharedPointer<ScalarKeyframeLimits> limits);
0060     KisScalarKeyframe(qreal value, InterpolationMode interpMode, TangentsMode tangentMode, QPointF leftTangent, QPointF rightTangent, QSharedPointer<ScalarKeyframeLimits> limits);
0061 
0062     KisKeyframeSP duplicate(KisKeyframeChannel* newChannel = 0) override;
0063 
0064     void setValue(qreal val, KUndo2Command* parentUndoCmd = nullptr);
0065     qreal value() const;
0066 
0067     void setInterpolationMode(InterpolationMode mode, KUndo2Command* parentUndoCmd = nullptr);
0068     InterpolationMode interpolationMode() const;
0069 
0070     void setTangentsMode(TangentsMode mode, KUndo2Command* parentUndoCmd = nullptr);
0071     TangentsMode tangentsMode() const;
0072 
0073     void setInterpolationTangents(QPointF leftTangent, QPointF rightTangent, KUndo2Command* parentUndoCmd = nullptr);
0074     QPointF leftTangent() const;
0075     QPointF rightTangent() const;
0076 
0077     void setLimits(QSharedPointer<ScalarKeyframeLimits> limits);
0078 
0079     /** @brief For now, scalar keyframes have a callback connection to
0080      * the channel that owns them in order to signal that their
0081      * internal state has changed. Created by the channel.
0082      */
0083     QMetaObject::Connection valueChangedChannelConnection;
0084 
0085     // Friend class for commands to avoid multi-signal calls..
0086     friend class KisScalarKeyframeUpdateCommand;
0087 
0088 Q_SIGNALS:
0089     void sigChanged(const KisScalarKeyframe* scalarKey);
0090 
0091 private:
0092     qreal m_value; /**< Scalar value of this keyframe. Optionally clamped to m_channelLimtis. */
0093     InterpolationMode m_interpolationMode;
0094     TangentsMode m_tangentsMode;
0095     QPointF m_leftTangent; /**< Controls part of between this and PREVIOUS keyframe. */
0096     QPointF m_rightTangent; /**< Controls part of between this and NEXT keyframe. */
0097 
0098     /** Weak pointer back to the owning channel's limits,
0099      * optionally used when setting the value of a keyframe
0100      * to conform to the limited range of its current channel,
0101      * Should change if keyframe is moved to a different channel.
0102      */
0103     QWeakPointer<ScalarKeyframeLimits> m_channelLimits;
0104 };
0105 
0106 
0107 /** @brief The KisScalarKeyframeChannel is a concrete KisKeyframeChannel
0108  * subclass that stores and manages KisScalarKeyframes.
0109  *
0110  * This class maps units of time (in frames) to points along a curve for
0111  * the animation of various interpolated scalar parameters within Krita.
0112  * Each scalar channel can be provided with default values and interpolation modes,
0113  * as well as an optional ScalarKeyframeLimits object that can be used
0114  * to limit the range of possible values.
0115  *
0116  * Generally, each scalar channel will be represented as an individual curve
0117  * within Krita's KisAnimationCurvesDocker.
0118 */
0119 class KRITAIMAGE_EXPORT KisScalarKeyframeChannel : public KisKeyframeChannel
0120 {
0121     Q_OBJECT
0122 public:
0123     KisScalarKeyframeChannel(const KoID& id, KisDefaultBoundsBaseSP bounds);
0124     KisScalarKeyframeChannel(const KisScalarKeyframeChannel &rhs);
0125     ~KisScalarKeyframeChannel() override;
0126 
0127     /** Utility for adding keyframe with non-default value. */
0128     void addScalarKeyframe(int time, qreal value, KUndo2Command *parentUndoCmd = nullptr);
0129 
0130     QSharedPointer<ScalarKeyframeLimits> limits() const;
0131     /** Limit channel within scalar value range. */
0132     void setLimits(qreal low, qreal high);
0133     /** Remove limits, allowing channel to operate within any range of values. */
0134     void removeLimits();
0135 
0136     /** @brief Quickly get the interpolated value at the given time. */
0137     qreal valueAt(int time) const;
0138     qreal currentValue() { return valueAt(currentTime()); }
0139 
0140     bool isCurrentTimeAffectedBy(int keyTime);
0141 
0142     void setDefaultValue(qreal value);
0143     void setDefaultInterpolationMode(KisScalarKeyframe::InterpolationMode mode);
0144 
0145     static QPointF interpolate(QPointF point1, QPointF rightTangent, QPointF leftTangent, QPointF point2, qreal t);
0146 
0147     virtual void insertKeyframe(int time, KisKeyframeSP keyframe, KUndo2Command *parentUndoCmd = nullptr) override;
0148     virtual void removeKeyframe(int time, KUndo2Command *parentUndoCmd = nullptr) override;
0149     virtual KisTimeSpan affectedFrames(int time) const override;
0150     virtual KisTimeSpan identicalFrames(int time) const override;
0151 
0152 Q_SIGNALS:
0153     void sigKeyframeChanged(const KisKeyframeChannel *channel, int time);
0154 
0155 private:
0156     static qreal findCubicCurveParameter(int time0, qreal delta0, qreal delta1, int time1, int time);
0157     static qreal cubicBezier(qreal p0, qreal delta1, qreal delta2, qreal p3, qreal t);
0158     static void normalizeTangents(const QPointF point1, QPointF &rightTangent, QPointF &leftTangent, const QPointF point2);
0159 
0160     virtual KisKeyframeSP createKeyframe() override;
0161     virtual QRect affectedRect(int time) const override;
0162     virtual QPair<int, KisKeyframeSP> loadKeyframe(const QDomElement &keyframeNode) override;
0163     virtual void saveKeyframe(KisKeyframeSP keyframe, QDomElement keyframeElement, const QString &layerFilename) override;
0164 
0165     struct Private;
0166     QScopedPointer<Private> m_d;
0167 };
0168 
0169 #endif