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 }