Radium Engine  1.5.20
Loading...
Searching...
No Matches
KeyFramedValue.hpp
1#pragma once
2
3#include <map>
4#include <set>
5
6#include <Core/Containers/AlignedAllocator.hpp>
7#include <Core/Math/Math.hpp>
8#include <Core/Types.hpp>
9
10namespace Ra {
11namespace Core {
12namespace Animation {
13
20class RA_CORE_API KeyFramedValueBase
21{
22 public:
24
25 virtual ~KeyFramedValueBase() {}
26
30 virtual inline size_t size() const = 0;
31
36 virtual inline bool removeKeyFrame( size_t i ) = 0;
37
41 virtual inline void moveKeyFrame( size_t i, const Scalar& t ) = 0;
42
46 virtual inline std::vector<Scalar> getTimes() const = 0;
47};
48
61template <typename VALUE_TYPE>
63{
64 public:
67
70
72 using Interpolator = std::function<VALUE_TYPE( const KeyFramedValue<VALUE_TYPE>&, Scalar )>;
73
79 KeyFramedValue( Scalar t, VALUE_TYPE frame ) { insertKeyFrame( t, frame ); }
80
81 KeyFramedValue( const KeyFramedValue& keyframe ) = default;
82
83 inline KeyFramedValue& operator=( const KeyFramedValue& keyframe ) = default;
84
85 inline std::vector<Scalar> getTimes() const override {
87#pragma omp parallel for
88 for ( int i = 0; i < int( m_keyframes.size() ); ++i ) {
89 times[i] = m_keyframes[i].first;
90 }
91 return times;
92 }
93
96
100 inline size_t size() const override { return m_keyframes.size(); }
101
105 const KeyFrames& getKeyFrames() const { return m_keyframes; }
106
110 inline const KeyFrame& operator[]( size_t i ) const { return m_keyframes[i]; }
111
116 inline void insertKeyFrame( const Scalar& t, const VALUE_TYPE& frame ) {
117 KeyFrame kf( t, frame );
118 auto upper = std::upper_bound(
119 m_keyframes.begin(), m_keyframes.end(), kf, []( const auto& a, const auto& b ) {
120 return a.first < b.first;
121 } );
122 if ( upper == m_keyframes.begin() ) { m_keyframes.insert( upper, kf ); }
123 else {
124 auto lower = upper - 1;
125 if ( Math::areApproxEqual( lower->first, t ) ) { lower->second = frame; }
126 else { m_keyframes.insert( upper, kf ); }
127 }
128 }
129
134 inline void insertInterpolatedKeyFrame( const Scalar& t, const Interpolator& interpolator ) {
135 insertKeyFrame( t, at( t, interpolator ) );
136 }
137
142 inline bool removeKeyFrame( size_t i ) override {
143 if ( size() == 1 ) return false;
145 return true;
146 }
147
151 inline void moveKeyFrame( size_t i, const Scalar& t ) override {
152 KeyFrame kf = m_keyframes[i];
153 if ( !Ra::Core::Math::areApproxEqual( kf.first, t ) ) {
154 removeKeyFrame( i );
155 insertKeyFrame( t, kf.second );
156 }
157 }
158
163 inline VALUE_TYPE at( const Scalar& t, const Interpolator& interpolator ) const {
164 return interpolator( *this, t );
165 }
166
182 // before first
183 if ( t < m_keyframes.begin()->first ) { return { 0, 0, 0_ra }; }
184 // after last
185 if ( t > m_keyframes.rbegin()->first ) {
186 const size_t i = m_keyframes.size() - 1;
187 return { i, i, 0_ra };
188 }
189 // look for exact match
190 auto kf0 = m_keyframes[0];
191 kf0.first = t;
192 auto upper = std::upper_bound(
193 m_keyframes.begin(), m_keyframes.end(), kf0, []( const auto& a, const auto& b ) {
194 return a.first < b.first;
195 } );
196
197 // here upper > begin() since before first case is already taken into account.
198 auto lower = upper;
199 --lower;
200 if ( Math::areApproxEqual( lower->first, t ) ) {
201 const size_t i = std::distance( m_keyframes.begin(), lower );
202 return { i, i, 0_ra };
203 }
204 // in-between
205 const size_t i = std::distance( m_keyframes.begin(), lower );
206 const Scalar t0 = lower->first;
207 const Scalar t1 = upper->first;
208 return { i, i + 1, ( t - t0 ) / ( t1 - t0 ) };
209 }
211
214
219 inline bool operator==( const KeyFramedValue& keyframe ) const {
220 return ( m_keyframes == keyframe.m_keyframes );
221 }
222
227 inline bool operator!=( const KeyFramedValue& keyframe ) const {
228 return !( *this == keyframe );
229 }
231
232 protected:
235};
236
237} // namespace Animation
238} // namespace Core
239} // namespace Ra
T begin(T... args)
virtual std::vector< Scalar > getTimes() const =0
virtual size_t size() const =0
virtual void moveKeyFrame(size_t i, const Scalar &t)=0
virtual bool removeKeyFrame(size_t i)=0
void insertInterpolatedKeyFrame(const Scalar &t, const Interpolator &interpolator)
bool operator==(const KeyFramedValue &keyframe) const
const KeyFrames & getKeyFrames() const
bool operator!=(const KeyFramedValue &keyframe) const
const KeyFrame & operator[](size_t i) const
void insertKeyFrame(const Scalar &t, const VALUE_TYPE &frame)
void moveKeyFrame(size_t i, const Scalar &t) override
KeyFrames m_keyframes
The list of keyframes.
VALUE_TYPE at(const Scalar &t, const Interpolator &interpolator) const
bool removeKeyFrame(size_t i) override
KeyFramedValue(Scalar t, VALUE_TYPE frame)
std::vector< Scalar > getTimes() const override
std::tuple< size_t, size_t, Scalar > findRange(Scalar t) const
T distance(T... args)
T end(T... args)
T erase(T... args)
T insert(T... args)
std::enable_if<!std::numeric_limits< T >::is_integer, bool >::type areApproxEqual(T x, T y, T espilonBoostFactor=T(10))
Compare two numbers such that |x-y| < espilon*epsilonBoostFactor.
Definition Math.hpp:42
hepler function to manage enum as underlying types in VariableSet
Definition Cage.cpp:3
T rbegin(T... args)
T size(T... args)
T upper_bound(T... args)