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 }