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 }