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

0001 /*
0002  *  SPDX-FileCopyrightText: 2015 Jouni Pentikäinen <joupent@gmail.com>
0003  *  SPDX-FileCopyrightText: 2020 Emmet O 'Neill <emmetoneill.pdx@gmail.com>
0004  *  SPDX-FileCopyrightText: 2020 Eoin O 'Neill <eoinoneill1991@gmail.com>
0005  *
0006  *  SPDX-License-Identifier: GPL-2.0-or-later
0007  */
0008 
0009 #include "kis_keyframe_channel.h"
0010 #include "KoID.h"
0011 #include "kis_global.h"
0012 #include "kis_node.h"
0013 #include "kis_time_span.h"
0014 #include "kundo2command.h"
0015 #include "kis_image.h"
0016 #include "kis_image_animation_interface.h"
0017 #include "kis_keyframe_commands.h"
0018 #include "kis_scalar_keyframe_channel.h"
0019 #include "kis_mask.h"
0020 #include "kis_image.h"
0021 
0022 #include <QMap>
0023 
0024 
0025 const KoID KisKeyframeChannel::Raster = KoID("content", ki18n("Content"));
0026 const KoID KisKeyframeChannel::Opacity = KoID("opacity", ki18n("Opacity"));
0027 const KoID KisKeyframeChannel::PositionX = KoID("transform_pos_x", ki18n("Position (X)"));
0028 const KoID KisKeyframeChannel::PositionY = KoID("transform_pos_y", ki18n("Position (Y)"));
0029 const KoID KisKeyframeChannel::ScaleX = KoID("transform_scale_x", ki18n("Scale (X)"));
0030 const KoID KisKeyframeChannel::ScaleY = KoID("transform_scale_y", ki18n("Scale (Y)"));
0031 const KoID KisKeyframeChannel::ShearX = KoID("transform_shear_x", ki18n("Shear (X)"));
0032 const KoID KisKeyframeChannel::ShearY = KoID("transform_shear_y", ki18n("Shear (Y)"));
0033 const KoID KisKeyframeChannel::RotationX = KoID("transform_rotation_x", ki18n("Rotation (X)"));
0034 const KoID KisKeyframeChannel::RotationY = KoID("transform_rotation_y", ki18n("Rotation (Y)"));
0035 const KoID KisKeyframeChannel::RotationZ = KoID("transform_rotation_z", ki18n("Rotation (Z)"));
0036 
0037 
0038 struct KisKeyframeChannel::Private
0039 {
0040     Private(const KoID &temp_id, KisDefaultBoundsBaseSP tmp_bounds) {
0041         bounds = tmp_bounds;
0042         id = temp_id;
0043     }
0044 
0045     Private(const Private &rhs) {
0046         id = rhs.id;
0047         haveBrokenFrameTimeBug = rhs.haveBrokenFrameTimeBug;
0048     }
0049 
0050     KoID id;
0051     QMap<int, KisKeyframeSP> keys; /**< Maps unique times to individual keyframes. */
0052     KisDefaultBoundsBaseSP bounds; /**< Stores pixel dimensions as well as current time. */
0053 
0054     KisNodeWSP parentNode;
0055     bool haveBrokenFrameTimeBug = false;
0056 };
0057 
0058 
0059 KisKeyframeChannel::KisKeyframeChannel(const KoID &id, KisDefaultBoundsBaseSP bounds)
0060     : m_d(new Private(id, bounds))
0061 {
0062     // Added keyframes should fire channel updated signal..
0063     connect(this, &KisKeyframeChannel::sigAddedKeyframe, [](const KisKeyframeChannel *channel, int time) {
0064         channel->sigChannelUpdated(
0065                     channel->affectedFrames(time),
0066                     channel->affectedRect(time)
0067                     );
0068     });
0069 
0070     // Removing keyframes should fire channel updated signal..
0071     connect(this, &KisKeyframeChannel::sigRemovingKeyframe, [](const KisKeyframeChannel *channel, int time) {
0072         channel->sigChannelUpdated(
0073                    channel->affectedFrames(time),
0074                    channel->affectedRect(time)
0075                    );
0076     });
0077 }
0078 
0079 KisKeyframeChannel::KisKeyframeChannel(const KisKeyframeChannel &rhs)
0080     : KisKeyframeChannel(rhs.m_d->id, new KisDefaultBounds(nullptr))
0081 {
0082     m_d.reset(new Private(*rhs.m_d));
0083 }
0084 
0085 KisKeyframeChannel::~KisKeyframeChannel()
0086 {
0087 }
0088 
0089 void KisKeyframeChannel::addKeyframe(int time, KUndo2Command *parentUndoCmd)
0090 {
0091     KisKeyframeSP keyframe = createKeyframe();
0092     insertKeyframe(time, keyframe, parentUndoCmd);
0093 }
0094 
0095 void KisKeyframeChannel::insertKeyframe(int time, KisKeyframeSP keyframe, KUndo2Command *parentUndoCmd)
0096 {
0097     KIS_ASSERT(time >= 0);
0098     KIS_ASSERT(keyframe);
0099 
0100     if (m_d->keys.contains(time)) {
0101         // Properly remove overwritten frames.
0102         removeKeyframe(time, parentUndoCmd);
0103     }
0104 
0105     if (parentUndoCmd) {
0106         KUndo2Command* cmd = new KisInsertKeyframeCommand(this, time, keyframe, parentUndoCmd);
0107         Q_UNUSED(cmd);
0108     }
0109 
0110     m_d->keys.insert(time, keyframe);
0111     emit sigAddedKeyframe(this, time);
0112 }
0113 
0114 void KisKeyframeChannel::removeKeyframe(int time, KUndo2Command *parentUndoCmd)
0115 {
0116     if (parentUndoCmd) {
0117         KUndo2Command* cmd = new KisRemoveKeyframeCommand(this, time, parentUndoCmd);
0118         Q_UNUSED(cmd);
0119     }
0120 
0121     emit sigRemovingKeyframe(this, time);
0122     m_d->keys.remove(time);
0123 }
0124 
0125 void KisKeyframeChannel::moveKeyframe(KisKeyframeChannel *sourceChannel, int sourceTime, KisKeyframeChannel *targetChannel, int targetTime, KUndo2Command *parentUndoCmd)
0126 {
0127     KIS_ASSERT(sourceChannel && targetChannel);
0128 
0129     KisKeyframeSP sourceKeyframe = sourceChannel->keyframeAt(sourceTime);
0130     sourceChannel->removeKeyframe(sourceTime, parentUndoCmd);
0131 
0132     KisKeyframeSP targetKeyframe = sourceKeyframe;
0133     if (sourceChannel != targetChannel) {
0134         // When "moving" Keyframes between channels, a new copy is made for that channel.
0135         targetKeyframe = sourceKeyframe->duplicate(targetChannel);
0136     }
0137 
0138     targetChannel->insertKeyframe(targetTime, targetKeyframe, parentUndoCmd);
0139 }
0140 
0141 void KisKeyframeChannel::copyKeyframe(const KisKeyframeChannel *sourceChannel, int sourceTime, KisKeyframeChannel *targetChannel, int targetTime, KUndo2Command* parentUndoCmd)
0142 {
0143     KIS_ASSERT(sourceChannel && targetChannel);
0144 
0145     KisKeyframeSP sourceKeyframe = sourceChannel->keyframeAt(sourceTime);
0146     KisKeyframeSP copiedKeyframe = sourceKeyframe->duplicate(targetChannel);
0147 
0148     targetChannel->insertKeyframe(targetTime, copiedKeyframe, parentUndoCmd);
0149 }
0150 
0151 void KisKeyframeChannel::swapKeyframes(KisKeyframeChannel *channelA, int timeA, KisKeyframeChannel *channelB, int timeB, KUndo2Command *parentUndoCmd)
0152 {
0153     KIS_ASSERT(channelA && channelB);
0154 
0155     // Store B.
0156     KisKeyframeSP keyframeB = channelB->keyframeAt(timeB);
0157 
0158     // Move A -> B
0159     moveKeyframe(channelA, timeA, channelB, timeB, parentUndoCmd);
0160 
0161     // Insert B -> A
0162     if (channelA != channelB) {
0163         keyframeB = keyframeB->duplicate(channelA);
0164     }
0165     channelA->insertKeyframe(timeA, keyframeB, parentUndoCmd);
0166 }
0167 
0168 KisKeyframeSP KisKeyframeChannel::keyframeAt(int time) const
0169 {
0170     QMap<int, KisKeyframeSP>::const_iterator iter = m_d->keys.constFind(time);
0171     if (iter != m_d->keys.constEnd()) {
0172         return iter.value();
0173     } else {
0174         return KisKeyframeSP();
0175     }
0176 }
0177 
0178 int KisKeyframeChannel::keyframeCount() const
0179 {
0180     return m_d->keys.count();
0181 }
0182 
0183 int KisKeyframeChannel::activeKeyframeTime(int time) const
0184 {
0185     QMap<int, KisKeyframeSP>::const_iterator iter = const_cast<const QMap<int, KisKeyframeSP>*>(&m_d->keys)->upperBound(time);
0186 
0187     // If the next keyframe is the first keyframe, that means there's no active frame.
0188     if (iter == m_d->keys.constBegin()) {
0189         return -1;
0190     }
0191 
0192     iter--;
0193 
0194     if (iter == m_d->keys.constEnd()) {
0195         return -1;
0196     }
0197 
0198     return iter.key();
0199 }
0200 
0201 int KisKeyframeChannel::firstKeyframeTime() const
0202 {
0203     if (m_d->keys.isEmpty()) {
0204         return -1;
0205     } else {
0206         return m_d->keys.firstKey();
0207     }
0208 }
0209 
0210 int KisKeyframeChannel::previousKeyframeTime(const int time) const
0211 {
0212     if (!keyframeAt(time)) {
0213         return activeKeyframeTime(time);
0214     }
0215 
0216     QMap<int, KisKeyframeSP>::const_iterator iter = m_d->keys.constFind(time);
0217 
0218     if (iter == m_d->keys.constBegin() || iter == m_d->keys.constEnd()) {
0219         return -1;
0220     }
0221 
0222     iter--;
0223     return iter.key();
0224 }
0225 
0226 int KisKeyframeChannel::nextKeyframeTime(const int time) const
0227 {
0228     QMap<int, KisKeyframeSP>::const_iterator iter = const_cast<const QMap<int, KisKeyframeSP>*>(&m_d->keys)->upperBound(time);
0229 
0230     if (iter == m_d->keys.constEnd()) {
0231         return -1;
0232     }
0233 
0234     return iter.key();
0235 }
0236 
0237 int KisKeyframeChannel::lastKeyframeTime() const
0238 {
0239     if (m_d->keys.isEmpty()) {
0240         return -1;
0241     }
0242 
0243     return m_d->keys.lastKey();
0244 }
0245 
0246 QSet<int> KisKeyframeChannel::allKeyframeTimes() const
0247 {
0248     QSet<int> frames;
0249 
0250     TimeKeyframeMap::const_iterator it = m_d->keys.constBegin();
0251     TimeKeyframeMap::const_iterator end = m_d->keys.constEnd();
0252 
0253     while (it != end) {
0254         frames.insert(it.key());
0255         ++it;
0256     }
0257 
0258     return frames;
0259 }
0260 
0261 QString KisKeyframeChannel::id() const
0262 {
0263     return m_d->id.id();
0264 }
0265 
0266 QString KisKeyframeChannel::name() const
0267 {
0268     return m_d->id.name();
0269 }
0270 
0271 void KisKeyframeChannel::setNode(KisNodeWSP node)
0272 {
0273     if (m_d->parentNode.isValid()) { // Disconnect old..
0274         disconnect(this, &KisKeyframeChannel::sigChannelUpdated, m_d->parentNode, &KisNode::handleKeyframeChannelUpdate);
0275     }
0276 
0277     m_d->parentNode = node;
0278     m_d->bounds = KisDefaultBoundsNodeWrapperSP( new KisDefaultBoundsNodeWrapper( node ));
0279 
0280     if (m_d->parentNode) { // Connect new..
0281         connect(this, &KisKeyframeChannel::sigChannelUpdated, m_d->parentNode, &KisNode::handleKeyframeChannelUpdate);
0282     }
0283 }
0284 
0285 KisNodeWSP KisKeyframeChannel::node() const
0286 {
0287     return m_d->parentNode;
0288 }
0289 
0290 void KisKeyframeChannel::setDefaultBounds(KisDefaultBoundsBaseSP bounds) {
0291     m_d->bounds = bounds;
0292 }
0293 
0294 int KisKeyframeChannel::channelHash() const
0295 {
0296     TimeKeyframeMap::const_iterator it = m_d->keys.constBegin();
0297     TimeKeyframeMap::const_iterator end = m_d->keys.constEnd();
0298 
0299     int hash = 0;
0300 
0301     while (it != end) {
0302         hash += it.key();
0303         ++it;
0304     }
0305 
0306     return hash;
0307 }
0308 
0309 KisTimeSpan KisKeyframeChannel::affectedFrames(int time) const
0310 {
0311     if (m_d->keys.isEmpty()) return KisTimeSpan::infinite(0);
0312 
0313     const int activeKeyTime = activeKeyframeTime(time);
0314     const int nextKeyTime = nextKeyframeTime(time);
0315 
0316     // Check for keyframe behind..
0317     if (!keyframeAt(activeKeyTime)) {
0318         return KisTimeSpan::fromTimeToTime(0, nextKeyTime - 1);
0319     }
0320 
0321     // Check for keyframe ahead..
0322     if (!keyframeAt(nextKeyTime)) {
0323         return KisTimeSpan::infinite(activeKeyTime);
0324     }
0325 
0326     return KisTimeSpan::fromTimeToTime(activeKeyTime, nextKeyTime - 1);
0327 }
0328 
0329 KisTimeSpan KisKeyframeChannel::identicalFrames(int time) const
0330 {
0331     return affectedFrames(time);
0332 }
0333 
0334 QDomElement KisKeyframeChannel::toXML(QDomDocument doc, const QString &layerFilename)
0335 {
0336     QDomElement channelElement = doc.createElement("channel");
0337 
0338     channelElement.setAttribute("name", id());
0339 
0340     Q_FOREACH (int time, m_d->keys.keys()) {
0341         QDomElement keyframeElement = doc.createElement("keyframe");
0342         KisKeyframeSP keyframe = keyframeAt(time);
0343 
0344         keyframeElement.setAttribute("time", time);
0345         keyframeElement.setAttribute("color-label", keyframe->colorLabel());
0346 
0347         saveKeyframe(keyframe, keyframeElement, layerFilename);
0348 
0349         channelElement.appendChild(keyframeElement);
0350     }
0351 
0352     return channelElement;
0353 }
0354 
0355 void KisKeyframeChannel::loadXML(const QDomElement &channelNode)
0356 {
0357     for (QDomElement keyframeNode = channelNode.firstChildElement(); !keyframeNode.isNull(); keyframeNode = keyframeNode.nextSiblingElement()) {
0358         if (keyframeNode.nodeName().toUpper() != "KEYFRAME") continue;
0359 
0360         QPair<int, KisKeyframeSP> timeKeyPair = loadKeyframe(keyframeNode);
0361         KIS_SAFE_ASSERT_RECOVER(timeKeyPair.second) { continue; }
0362 
0363         if (keyframeNode.hasAttribute("color-label")) {
0364             timeKeyPair.second->setColorLabel(keyframeNode.attribute("color-label").toUInt());
0365         }
0366 
0367         insertKeyframe(timeKeyPair.first, timeKeyPair.second);
0368     }
0369 }
0370 
0371 KisKeyframeChannel::TimeKeyframeMap& KisKeyframeChannel::keys()
0372 {
0373     return m_d->keys;
0374 }
0375 
0376 const KisKeyframeChannel::TimeKeyframeMap& KisKeyframeChannel::constKeys() const
0377 {
0378     return m_d->keys;
0379 }
0380 
0381 int KisKeyframeChannel::currentTime() const
0382 {
0383     return m_d->bounds->currentTime();
0384 }
0385 
0386 void KisKeyframeChannel::workaroundBrokenFrameTimeBug(int *time)
0387 {
0388     if (*time < 0) {
0389         qWarning() << "WARNING: Loading a file with negative animation frames!";
0390         qWarning() << "         The file has been saved with a buggy version of Krita.";
0391         qWarning() << "         All the frames with negative ids will be dropped!";
0392         qWarning() << "         " << ppVar(this->id()) << ppVar(*time);
0393 
0394         m_d->haveBrokenFrameTimeBug = true;
0395         *time = 0;
0396     }
0397 
0398     if (m_d->haveBrokenFrameTimeBug) {
0399         while (keyframeAt(*time)) {
0400             (*time)++;
0401         }
0402     }
0403 }