Radium Engine  1.5.0
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 
10 namespace Ra {
11 namespace Core {
12 namespace Animation {
13 
20 class 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 
61 template <typename VALUE_TYPE>
63 {
64  public:
66  using KeyFrame = std::pair<Scalar, VALUE_TYPE>;
67 
69  using KeyFrames = std::vector<KeyFrame>;
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 {
86  std::vector<Scalar> times( m_keyframes.size() );
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;
144  m_keyframes.erase( m_keyframes.begin() + i );
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 
181  std::tuple<size_t, size_t, Scalar> findRange( Scalar t ) const {
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
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
std::pair< Scalar, VALUE_TYPE > KeyFrame
The type for a keyframe.
bool operator!=(const KeyFramedValue &keyframe) const
std::vector< Scalar > getTimes() const override
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
std::vector< KeyFrame > KeyFrames
The type for the keyframes container.
bool removeKeyFrame(size_t i) override
KeyFramedValue(Scalar t, VALUE_TYPE frame)
const KeyFrame & operator[](size_t i) const
std::tuple< size_t, size_t, Scalar > findRange(Scalar t) const
const KeyFrames & getKeyFrames() const
std::function< VALUE_TYPE(const KeyFramedValue< VALUE_TYPE > &, Scalar)> Interpolator
The type for interpolators.
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
Definition: Cage.cpp:3