File indexing completed on 2024-05-19 04:26:18

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