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

0001 /*
0002  * SPDX-FileCopyrightText: 2019-2023 Mattia Basaglia <dev@dragon.best>
0003  *
0004  * SPDX-License-Identifier: GPL-3.0-or-later
0005  */
0006 
0007 #pragma once
0008 #include <tuple>
0009 #include <set>
0010 
0011 #include "model/animation/animatable.hpp"
0012 
0013 
0014 namespace glaxnimate::model {
0015 
0016 /**
0017  * \brief Utility to join keyframes from multiple animatables
0018  */
0019 class JoinAnimatables
0020 {
0021 private:
0022     using MidTransition = model::AnimatableBase::MidTransition;
0023 
0024 public:
0025     struct Keyframe
0026     {
0027         FrameTime time;
0028         std::vector<QVariant> values;
0029         std::vector<KeyframeTransition> transitions;
0030 
0031         Keyframe(FrameTime time, std::size_t prop_count)
0032             : time(time)
0033         {
0034             values.reserve(prop_count);
0035             transitions.reserve(prop_count);
0036         }
0037 
0038         static KeyframeTransition mix_transitions(const std::vector<KeyframeTransition>& transitions)
0039         {
0040             int count = 0;
0041             QPointF in;
0042             QPointF out;
0043             for ( const auto& transition : transitions )
0044             {
0045                 if ( !transition.hold() )
0046                 {
0047                     in += transition.before();
0048                     out += transition.after();
0049                     count++;
0050                 }
0051             }
0052 
0053             if ( count == 0 )
0054                 return {{0, 0}, {1, 1}, true};
0055 
0056             return {in / count, out / count};
0057         }
0058 
0059         KeyframeTransition transition() const
0060         {
0061             return mix_transitions(transitions);
0062         }
0063     };
0064 
0065     enum Flags
0066     {
0067         Normal      = 0x00,
0068         NoKeyframes = 0x01,
0069         NoValues    = 0x02,
0070     };
0071 
0072     using iterator = typename std::vector<Keyframe>::const_iterator;
0073 
0074     JoinAnimatables(std::vector<const model::AnimatableBase*> properties, int flags = Normal)
0075     : properties_(std::move(properties))
0076     {
0077         if ( !(flags & NoKeyframes) )
0078             load_keyframes(flags);
0079     }
0080 
0081     /**
0082      * \brief Whether the result has more than one keyframe
0083      */
0084     bool animated() const
0085     {
0086         return keyframes_.size() > 1;
0087     }
0088 
0089     /**
0090      * \brief Keyframe range begin
0091      */
0092     auto begin() const
0093     {
0094         return keyframes_.begin();
0095     }
0096 
0097     /**
0098      * \brief Keyframe range end
0099      */
0100     auto end() const
0101     {
0102         return keyframes_.end();
0103     }
0104 
0105     /**
0106      * \brief Current value as a vector of variants
0107      */
0108     std::vector<QVariant> current_value() const
0109     {
0110         std::vector<QVariant> values;
0111         values.reserve(properties_.size());
0112         for ( auto prop : properties_ )
0113             values.push_back(prop->value());
0114         return values;
0115     }
0116 
0117     /**
0118      * \brief Value at time as a vector of variants
0119      */
0120     std::vector<QVariant> value_at(FrameTime time) const
0121     {
0122         std::vector<QVariant> values;
0123         values.reserve(properties_.size());
0124         for ( auto prop : properties_ )
0125             values.push_back(prop->value(time));
0126         return values;
0127     }
0128 
0129     const std::vector<const model::AnimatableBase*>& properties() const
0130     {
0131         return properties_;
0132     }
0133 
0134     const std::vector<Keyframe>& keyframes() const
0135     {
0136         return keyframes_;
0137     }
0138 
0139     /**
0140      * \brief Current value combined by a callback
0141      * \pre each property can be converted to the corresponding \p AnimatedProperty<Args>.
0142      */
0143     template<class... Args, class Func>
0144     auto combine_current_value(const Func& func)
0145     {
0146         return invoke_combine_get<Args...>(func, std::index_sequence_for<Args...>());
0147     }
0148 
0149     /**
0150      * \brief Value at a given time combined by a callback
0151      * \pre each property can be converted to the corresponding \p AnimatedProperty<Args>.
0152      */
0153     template<class... Args, class Func>
0154     auto combine_value_at(FrameTime time, const Func& func)
0155     {
0156         return invoke_combine_get_at<Args...>(time, func, std::index_sequence_for<Args...>());
0157     }
0158 
0159     /**
0160      * \brief Fills \p target with the combined values
0161      * \pre Each property can be converted to the corresponding \p AnimatedProperty<Args>.
0162      * \pre \p target values can be initialized by what \p func returns
0163      */
0164     template<class... Args, class Target, class Func>
0165     void apply_to(Target* target, const Func& func, const model::AnimatedProperty<Args>*...)
0166     {
0167         target->clear_keyframes();
0168         target->set(combine_current_value<Args...>(func));
0169         for ( const auto& keyframe : keyframes_ )
0170         {
0171             auto real_kf = target->set_keyframe(keyframe.time, combine_value_at<Args...>(keyframe.time, func));
0172             real_kf->set_transition(keyframe.transition());
0173         }
0174     }
0175 
0176 private:
0177     std::vector<const model::AnimatableBase*> properties_;
0178     std::vector<Keyframe> keyframes_;
0179 
0180     void load_keyframes(int flags)
0181     {
0182         std::set<FrameTime> time_set;
0183         for ( auto prop : properties_ )
0184             for ( int i = 0, e = prop->keyframe_count(); i < e; i++ )
0185                 time_set.insert(prop->keyframe(i)->time());
0186         std::vector<FrameTime> time_vector(time_set.begin(), time_set.end());
0187         time_set.clear();
0188 
0189         std::vector<std::vector<MidTransition>> mids;
0190         mids.reserve(time_vector.size());
0191         for ( FrameTime t : time_vector )
0192         {
0193             mids.push_back({});
0194             mids.back().reserve(properties_.size());
0195             for ( auto prop : properties_ )
0196                 mids.back().push_back(prop->mid_transition(t));
0197         }
0198 
0199         keyframes_.reserve(time_vector.size());
0200         for ( std::size_t i = 0; i < time_vector.size(); i++ )
0201         {
0202             keyframes_.emplace_back(time_vector[i], properties_.size());
0203 
0204             for ( std::size_t j = 0; j < properties_.size(); j++ )
0205             {
0206                 if ( !(flags & NoValues) )
0207                     keyframes_.back().values.push_back(mids[i][j].value);
0208                 keyframes_.back().transitions.push_back(mids[i][j].to_next);
0209                 if ( mids[i][j].type == MidTransition::Middle && i > 0 && mids[i-1][j].type != MidTransition::Middle )
0210                 {
0211                     keyframes_[i-1].transitions[j] = mids[i][j].from_previous;
0212                 }
0213             }
0214         }
0215     }
0216 
0217     template<class... Args, class Func, std::size_t... Indices>
0218     auto invoke_combine_get(const Func& func, std::integer_sequence<std::size_t, Indices...>)
0219     {
0220         return func(static_cast<const model::AnimatedProperty<Args>*>(properties_[Indices])->get()...);
0221     }
0222 
0223     template<class... Args, class Func, std::size_t... Indices>
0224     auto invoke_combine_get_at(FrameTime t, const Func& func, std::integer_sequence<std::size_t, Indices...>)
0225     {
0226         return func(static_cast<const model::AnimatedProperty<Args>*>(properties_[Indices])->get_at(t)...);
0227     }
0228 };
0229 
0230 /**
0231  * \brief JoinAnimatables implementing AnimatableBase
0232  */
0233 class JoinedAnimatable : public AnimatableBase, public JoinAnimatables
0234 {
0235 public:
0236     using ConversionFunction = std::function<QVariant (const std::vector<QVariant>& args)>;
0237 
0238     class Keyframe : public KeyframeBase
0239     {
0240     public:
0241         Keyframe(JoinedAnimatable* parent, const JoinAnimatables::Keyframe* subkf)
0242             : KeyframeBase(subkf->time),
0243               parent(parent),
0244               subkf(subkf)
0245         {
0246             set_transition(subkf->transition());
0247         }
0248 
0249         Keyframe(JoinedAnimatable* parent, model::FrameTime time)
0250             : KeyframeBase(time),
0251               parent(parent),
0252               subkf(nullptr)
0253         {}
0254 
0255         std::vector<QVariant> get() const
0256         {
0257             if ( subkf )
0258                 return subkf->values;
0259             else
0260                 return parent->value_at(time());
0261         }
0262 
0263         QVariant value() const override
0264         {
0265             if ( subkf )
0266                 return parent->converter(subkf->values);
0267             else
0268                 return parent->converter(parent->value_at(time()));
0269         }
0270 
0271         // read only
0272         bool set_value(const QVariant&) override { return false; }
0273 
0274     protected:
0275         std::unique_ptr<KeyframeBase> do_clone() const override
0276         {
0277             return std::make_unique<JoinedAnimatable::Keyframe>(parent, subkf);
0278         }
0279 
0280         class Splitter : public KeyframeSplitter
0281         {
0282         public:
0283             Splitter(const Keyframe* a, const Keyframe* b) : a(a), b(b) {}
0284 
0285             void step(const QPointF&) override {}
0286 
0287 
0288             std::unique_ptr<KeyframeBase> left(const QPointF& p) const override
0289             {
0290                 return std::make_unique<Keyframe>(
0291                     a->parent,
0292                     math::lerp(a->time(), b->time(), p.x())
0293                 );
0294             }
0295 
0296             std::unique_ptr<KeyframeBase> right(const QPointF& p) const override
0297             {
0298                 return std::make_unique<Keyframe>(
0299                     a->parent,
0300                     math::lerp(a->time(), b->time(), p.x())
0301                 );
0302             }
0303 
0304             std::unique_ptr<KeyframeBase> last() const override { return b->clone(); }
0305 
0306             const Keyframe* a;
0307             const Keyframe* b;
0308         };
0309 
0310         std::unique_ptr<KeyframeSplitter> splitter(const KeyframeBase* other) const override
0311         {
0312             return std::make_unique<Splitter>(this, static_cast<const Keyframe*>(other));
0313         }
0314 
0315     private:
0316         JoinedAnimatable* parent;
0317         const JoinAnimatables::Keyframe* subkf = nullptr;
0318     };
0319 
0320     JoinedAnimatable(std::vector<const model::AnimatableBase*> properties, ConversionFunction converter, int flags = Normal)
0321         : AnimatableBase(nullptr, {}, {}),
0322           JoinAnimatables(std::move(properties), flags),
0323           converter(std::move(converter))
0324 
0325     {
0326         wrapped_keyframes.reserve(keyframes().size());
0327         for ( auto& kf : keyframes() )
0328             wrapped_keyframes.push_back(std::make_unique<Keyframe>(this, &kf));
0329     }
0330 
0331     int keyframe_count() const override
0332     {
0333         return wrapped_keyframes.size();
0334     }
0335 
0336     using JoinAnimatables::animated;
0337 
0338     const KeyframeBase* keyframe(int i) const override
0339     {
0340         return wrapped_keyframes[i].get();
0341     }
0342 
0343     KeyframeBase* keyframe(int i) override
0344     {
0345         return wrapped_keyframes[i].get();
0346     }
0347 
0348     QVariant value(FrameTime time) const override
0349     {
0350         return converter(value_at(time));
0351     }
0352 
0353     QVariant value() const override
0354     {
0355         return converter(current_value());
0356     }
0357 
0358 
0359     // read only
0360     bool set_value(const QVariant&) override { return false; }
0361     bool valid_value(const QVariant&) const override { return false; }
0362     bool set_undoable(const QVariant&, bool) override { return false; }
0363     int move_keyframe(int, FrameTime) override { return -1; }
0364     bool value_mismatch() const override { return false; }
0365     KeyframeBase* set_keyframe(FrameTime , const QVariant& , SetKeyframeInfo*, bool ) override { return nullptr; }
0366     void remove_keyframe(int) override {};
0367     void clear_keyframes() override {};
0368     bool remove_keyframe_at_time(FrameTime) override { return false; }
0369 
0370 protected:
0371     void on_set_time(FrameTime) override {}
0372 
0373     // Shouldn't be needed
0374     QVariant do_mid_transition_value(const KeyframeBase*, const KeyframeBase*, qreal) const override
0375     {
0376         return {};
0377     }
0378 
0379 
0380 private:
0381     ConversionFunction converter;
0382     std::vector<std::unique_ptr<Keyframe>> wrapped_keyframes;
0383 };
0384 
0385 } // namespace glaxnimate::model