diff --git a/libs/image/kis_animation_cycle.cpp b/libs/image/kis_animation_cycle.cpp index bfe32e0117..b375a491f5 100644 --- a/libs/image/kis_animation_cycle.cpp +++ b/libs/image/kis_animation_cycle.cpp @@ -1,201 +1,199 @@ /* * Copyright (c) 2018 Jouni Pentikäinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_animation_cycle.h" #include #include "kis_time_range.h" #include "kis_keyframe_channel.h" KisAnimationCycle::KisAnimationCycle(KisKeyframeChannel *channel, KisTimeSpan sourceRange) : KisKeyframeBase(channel, sourceRange.start()) , m_range(sourceRange) {} KisAnimationCycle::KisAnimationCycle(const KisAnimationCycle &cycle, KisTimeSpan newRange) : KisKeyframeBase(cycle.channel(), newRange.start()) , m_range(newRange) {} KisTimeSpan KisAnimationCycle::originalRange() const { return m_range; } int KisAnimationCycle::duration() const { return originalRange().duration(); } void KisAnimationCycle::addRepeat(QSharedPointer repeat) { if (m_repeats.contains(repeat)) return; m_repeats.append(repeat); } void KisAnimationCycle::removeRepeat(QSharedPointer repeat) { m_repeats.removeAll(repeat); } const QVector>& KisAnimationCycle::repeats() const { return m_repeats; } KisFrameSet KisAnimationCycle::instancesWithin(KisKeyframeSP original, KisTimeSpan range) const { KisFrameSet frames; const int originalTime = original->time(); const KisKeyframeBaseSP next = original->channel()->nextItem(*original); const int frameDuration = (next.isNull()) ? -1 : next->time() - originalTime; const int interval = duration(); int infiniteFrom = frameDuration == -1 ? originalTime : -1; QVector spans; Q_FOREACH(const QWeakPointer repeatFrame, m_repeats) { - auto repeat = repeatFrame.toStrongRef(); - if (!repeat) continue; - - const int endTime = repeat->end(); - - if (range.isEmpty()) { - if (endTime != -1) { - range = KisTimeSpan(0, endTime - 1); - } else { - infiniteFrom = repeat->firstInstanceOf(originalTime); - continue; - } - } + const QSharedPointer repeat = repeatFrame.toStrongRef(); + if (!repeat) continue; + + const int lastOfRepeat = repeat->lastFrame(); + + if (range.isEmpty() && lastOfRepeat == -1) { + infiniteFrom = repeat->firstInstanceOf(originalTime); + } else { + const int end = (lastOfRepeat != -1) ? lastOfRepeat : range.end(); + const KisTimeSpan repeatRange{repeat->time(), end}; + const KisTimeSpan relevantRange = range.isEmpty() ? repeatRange : (range & repeatRange); - KisTimeSpan repeatRange = (endTime != -1) ? range & KisTimeSpan(repeat->time(), endTime) : range.truncateRight(repeat->time()); int firstInstance = repeat->firstInstanceOf(originalTime); if (firstInstance == -1) continue; - if (firstInstance < repeatRange.start()) { + if (firstInstance < relevantRange.start()) { firstInstance += interval * ((range.start() - firstInstance) / interval); } - for (int repeatTime = firstInstance; repeatTime <= repeatRange.end(); repeatTime += interval) { - bool endsWithinRange = frameDuration != -1 && repeatTime + frameDuration - 1 <= repeatRange.end(); - const int repeatEndTime = endsWithinRange ? (repeatTime + frameDuration - 1) : repeatRange.end(); + for (int repeatTime = firstInstance; repeatTime <= relevantRange.end(); repeatTime += interval) { + const bool endsWithinRange = frameDuration != -1 && repeatTime + frameDuration - 1 <= relevantRange.end(); + const int repeatEndTime = endsWithinRange ? (repeatTime + frameDuration - 1) : relevantRange.end(); spans.append(KisTimeSpan(repeatTime, repeatEndTime)); } } + } frames |= KisFrameSet(spans); if (infiniteFrom != -1) { frames |= KisFrameSet::infiniteFrom(infiniteFrom); } else { frames |= KisFrameSet::between(originalTime, originalTime + frameDuration - 1); } return frames; } QRect KisAnimationCycle::affectedRect() const { QRect rect; for (auto keyframe : channel()->itemsWithin(m_range)) { rect |= keyframe->affectedRect(); } return rect; } KisKeyframeSP KisAnimationCycle::getOriginalKeyframeFor(int time) const { return channel()->activeKeyframeAt(time); } KisRepeatFrame::KisRepeatFrame(KisKeyframeChannel *channel, int time, QSharedPointer cycle) : KisKeyframeBase(channel, time) , m_cycle(cycle) {} QSharedPointer KisRepeatFrame::cycle() const { return m_cycle; } QRect KisRepeatFrame::affectedRect() const { return m_cycle->affectedRect(); } int KisRepeatFrame::getOriginalTimeFor(int time) const { KisTimeSpan originalRange = m_cycle->originalRange(); int timeWithinCycle = (time - this->time()) % originalRange.duration(); return originalRange.start() + timeWithinCycle; } KisKeyframeSP KisRepeatFrame::getOriginalKeyframeFor(int time) const { return channel()->activeKeyframeAt(getOriginalTimeFor(time)); } int KisRepeatFrame::firstInstanceOf(int originalTime) const { KisTimeSpan originalRange = m_cycle->originalRange(); const int timeWithinCycle = originalTime - originalRange.start(); const int first = this->time() + timeWithinCycle; const KisKeyframeSP next = channel()->nextKeyframe(time()); if (next && next->time() < first) return -1; return first; } int KisRepeatFrame::previousVisibleFrame(int time) const { if (time <= this->time()) return -1; const int earlierOriginalTime = getOriginalTimeFor(time - 1); int originalStart, originalEnd; channel()->activeKeyframeRange(earlierOriginalTime, &originalStart, &originalEnd); if (originalEnd == -1) return -1; const int durationOfOriginalKeyframe = originalEnd + 1 - originalStart; return time - durationOfOriginalKeyframe; } int KisRepeatFrame::nextVisibleFrame(int time) const { const int originalTime = getOriginalTimeFor(time); int originalStart, originalEnd; channel()->activeKeyframeRange(originalTime, &originalStart, &originalEnd); if (originalEnd == -1) return -1; const int durationOfOriginalKeyframe = originalEnd + 1 - originalStart; const int nextFrameTime = time + durationOfOriginalKeyframe; - const int endTime = end(); + const int endTime = lastFrame(); return (endTime == -1 || nextFrameTime < endTime) ? nextFrameTime : -1; } -int KisRepeatFrame::end() const +int KisRepeatFrame::lastFrame() const { const KisKeyframeBaseSP next = channel()->nextItem(*this); return next ? next->time() - 1 : -1; } diff --git a/libs/image/kis_animation_cycle.h b/libs/image/kis_animation_cycle.h index fff2f308f2..b875f40ee9 100644 --- a/libs/image/kis_animation_cycle.h +++ b/libs/image/kis_animation_cycle.h @@ -1,94 +1,94 @@ /* * Copyright (c) 2018 Jouni Pentikäinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_ANIMATION_CYCLE_H #define KIS_ANIMATION_CYCLE_H #include "kis_keyframe.h" #include "kis_time_range.h" class KisTimeSpan; class KisFrameSet; class KisRepeatFrame; class KRITAIMAGE_EXPORT KisAnimationCycle : public KisKeyframeBase { public: KisAnimationCycle(KisKeyframeChannel *channel, KisTimeSpan sourceRange); KisAnimationCycle(const KisAnimationCycle &cycle, KisTimeSpan newRange); /** * The full source range repeated by the cycle. */ KisTimeSpan originalRange() const; int duration() const; void addRepeat(QSharedPointer repeat); void removeRepeat(QSharedPointer repeat); const QVector>& repeats() const; QRect affectedRect() const override; KisKeyframeSP getOriginalKeyframeFor(int time) const override; KisFrameSet instancesWithin(KisKeyframeSP original, KisTimeSpan range) const; private: friend class KisKeyframeChannel; KisTimeSpan m_range; QVector> m_repeats; }; class KRITAIMAGE_EXPORT KisRepeatFrame : public KisKeyframeBase { public: KisRepeatFrame(KisKeyframeChannel *channel, int time, QSharedPointer cycle); QSharedPointer cycle() const; QRect affectedRect() const override; int getOriginalTimeFor(int time) const; KisKeyframeSP getOriginalKeyframeFor(int time) const override; /// Returns the earliest time the original frame appears in this repeat, or -1 if it never does. int firstInstanceOf(int originalTime) const; /** Returns the time at which the previous frame within the repeat appears, * or -1 if time is at the first repeated frame. * NB: time should be at the start of a repeated frame */ int previousVisibleFrame(int time) const; /** Returns the time at which the next frame within the repeat appears, * or -1 if time is at the last repeated frame. * NB: time should be at the start of a repeated frame */ int nextVisibleFrame(int time) const; /** * Finds the time of the next keyframe if any. * Returns -1 if the cycle continues indefinitely. */ - int end() const; + int lastFrame() const; private: QSharedPointer m_cycle; }; #endif