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