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