File indexing completed on 2025-02-02 04:11:07

0001 /*
0002  * SPDX-FileCopyrightText: 2019-2023 Mattia Basaglia <dev@dragon.best>
0003  *
0004  * SPDX-License-Identifier: GPL-3.0-or-later
0005  */
0006 
0007 #include "repeater.hpp"
0008 
0009 #include <QPainter>
0010 
0011 #include "model/shapes/group.hpp"
0012 #include "model/animation/join_animatables.hpp"
0013 
0014 using namespace glaxnimate;
0015 
0016 GLAXNIMATE_OBJECT_IMPL(glaxnimate::model::Repeater)
0017 
0018 QIcon glaxnimate::model::Repeater::static_tree_icon()
0019 {
0020     return QIcon::fromTheme("table");
0021 }
0022 
0023 QString glaxnimate::model::Repeater::static_type_name_human()
0024 {
0025     return i18n("Repeater");
0026 }
0027 
0028 
0029 math::bezier::MultiBezier glaxnimate::model::Repeater::process(FrameTime t, const math::bezier::MultiBezier& mbez) const
0030 {
0031     QTransform matrix = transform->transform_matrix(t);
0032     math::bezier::MultiBezier out;
0033     math::bezier::MultiBezier copy = mbez;
0034     for ( int i = 0; i < copies.get_at(t); i++ )
0035     {
0036         out.append(copy);
0037         copy.transform(matrix);
0038     }
0039     return out;
0040 
0041 }
0042 
0043 bool glaxnimate::model::Repeater::process_collected() const
0044 {
0045     return true;
0046 }
0047 
0048 void glaxnimate::model::Repeater::on_paint(QPainter* painter, glaxnimate::model::FrameTime t, glaxnimate::model::VisualNode::PaintMode mode, glaxnimate::model::Modifier*) const
0049 {
0050     QTransform matrix = transform->transform_matrix(t);
0051     auto alpha_s = start_opacity.get_at(t);
0052     auto alpha_e = end_opacity.get_at(t);
0053     int n_copies = copies.get_at(t);
0054 
0055     for ( int i = 0; i < n_copies; i++ )
0056     {
0057         float alpha_lerp = float(i) / (n_copies == 1 ? 1 : n_copies - 1);
0058         auto alpha = math::lerp(alpha_s, alpha_e, alpha_lerp);
0059         painter->setOpacity(alpha * painter->opacity());
0060 
0061         for ( auto sib : affected() )
0062         {
0063             if ( sib->visible.get() )
0064                 sib->paint(painter, t, mode);
0065         }
0066 
0067         painter->setTransform(matrix, true);
0068     }
0069 }
0070 
0071 
0072 template<class T, class Func = std::plus<T>>
0073 static void increase_transform(glaxnimate::model::AnimatedProperty<T>& into, const glaxnimate::model::AnimatedProperty<T>& from, Func func = {})
0074 {
0075     using Keyframe = glaxnimate::model::Keyframe<T>;
0076 
0077     for ( int i = 0, e = from.keyframe_count(); i < e; i++ )
0078     {
0079         auto into_kf = static_cast<Keyframe*>(into.keyframe(i));
0080 
0081         into_kf->set(func(into_kf->get(), static_cast<const Keyframe*>(from.keyframe(i))->get()));
0082     }
0083 
0084     into.set(func(into.get(), from.get()));
0085 }
0086 
0087 static void increase_transform(glaxnimate::model::Transform* into, const glaxnimate::model::Transform* from)
0088 {
0089     increase_transform(into->position, from->position);
0090     increase_transform(into->anchor_point, from->anchor_point);
0091     increase_transform(into->rotation, from->rotation);
0092     increase_transform(into->scale, from->scale, [](const QVector2D& a, const QVector2D& b){
0093         return QVector2D(a.x() * b.x(), a.y() * b.y());
0094     });
0095 }
0096 
0097 std::unique_ptr<glaxnimate::model::ShapeElement> glaxnimate::model::Repeater::to_path() const
0098 {
0099     auto group = std::make_unique<glaxnimate::model::Group>(document());
0100     group->name.set(name.get());
0101     group->visible.set(visible.get());
0102     group->locked.set(locked.get());
0103 
0104     auto child = std::make_unique<glaxnimate::model::Group>(document());
0105     for ( auto sib : affected() )
0106         child->shapes.insert(sib->to_path());
0107 
0108     JoinAnimatables anim({&start_opacity, &end_opacity}, JoinAnimatables::NoValues);
0109 
0110     int n_copies = copies.get();
0111     float alpha_lerp = 1;
0112     auto func = [&alpha_lerp](float a, float b){
0113         return math::lerp(a, b, alpha_lerp);
0114     };
0115     for ( int i = 0; i < n_copies; i++ )
0116     {
0117         alpha_lerp = float(i) / (n_copies == 1 ? 1 : n_copies - 1);
0118         auto cloned = static_cast<glaxnimate::model::Group*>(group->shapes.insert_clone(child.get()));
0119         anim.apply_to(&cloned->opacity, func, &start_opacity, &end_opacity);
0120 
0121 
0122         if ( i == 0 )
0123             child->transform->assign_from(transform.get());
0124         else
0125             increase_transform(child->transform.get(), transform.get());
0126 
0127     }
0128 
0129     group->set_time(time());
0130 
0131     return group;
0132 }
0133 
0134 int glaxnimate::model::Repeater::max_copies() const
0135 {
0136     int max = copies.get();
0137     for ( int i = 0, e = copies.keyframe_count(); i < e; ++i )
0138     {
0139         int val = copies.keyframe(i)->get();
0140         if ( val > max )
0141             max = val;
0142     }
0143     return max;
0144 }