Antkeeper  0.0.1
animation.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2023 Christopher J. Howard
3  *
4  * This file is part of Antkeeper source code.
5  *
6  * Antkeeper source code is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Antkeeper source code is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef ANTKEEPER_ANIMATION_HPP
21 #define ANTKEEPER_ANIMATION_HPP
22 
24 #include <algorithm>
25 #include <functional>
26 #include <type_traits>
27 #include <unordered_map>
28 
33 {
34 public:
36 
42  virtual void advance(float dt) = 0;
43 
49  void seek(float t);
50 
52  void rewind();
53 
55  void loop(bool enabled);
56 
58  void pause();
59 
61  void play();
62 
64  void stop();
65 
71  void set_speed(float speed);
72 
74  bool is_looped() const;
75 
77  bool is_paused() const;
78 
80  bool is_stopped() const;
81 
83  float get_position() const;
84 
86  int get_loop_count() const;
87 
89  virtual float get_duration() const = 0;
90 
92  void set_start_callback(std::function<void()> callback);
93 
95  void set_end_callback(std::function<void()> callback);
96 
102  void set_loop_callback(std::function<void(int)> callback);
103 
104 protected:
105  bool looped;
107  bool paused;
108  bool stopped;
109  float position;
110  float speed;
111 
112  std::function<void()> start_callback;
113  std::function<void()> end_callback;
114  std::function<void(int)> loop_callback;
115 };
116 
117 inline bool animation_base::is_looped() const
118 {
119  return looped;
120 }
121 
122 inline bool animation_base::is_paused() const
123 {
124  return paused;
125 }
126 
127 inline bool animation_base::is_stopped() const
128 {
129  return stopped;
130 }
131 
132 inline float animation_base::get_position() const
133 {
134  return position;
135 }
136 
138 {
139  return loop_count;
140 }
141 
147 template <typename T>
149 {
150 public:
153 
154  // Keyframe type for this animation.
155  typedef typename channel::keyframe keyframe;
156 
158  typedef typename std::decay<std::function<T(const T&, const T&, float)>>::type interpolator_type;
159 
162 
164  virtual void advance(float dt);
165 
173 
179  void remove_channel(int id);
180 
183 
190 
196  void set_frame_callback(std::function<void(int, const T&)> callback);
197 
203  const channel* get_channel(int id) const;
204 
207 
209  virtual float get_duration() const;
210 
211 private:
212  std::unordered_map<int, channel> channels;
213  interpolator_type interpolator;
214  std::function<void(int, const T&)> frame_callback;
215 };
216 
217 template <typename T>
219  interpolator(nullptr),
220  frame_callback(nullptr)
221 {}
222 
223 template <typename T>
224 void animation<T>::advance(float dt)
225 {
226  if (paused || stopped)
227  {
228  return;
229  }
230 
231  // Advance position by dt
232  position += dt * speed;
233 
234  // Determine duration of the animation
235  float duration = get_duration();
236 
237  if (position < duration)
238  {
239  if (frame_callback != nullptr && interpolator != nullptr)
240  {
241  for (const auto& channel: channels)
242  {
243  auto frames = channel.second.find_keyframes(position);
244 
245  if (frames[0] != nullptr && frames[1] != nullptr)
246  {
247  // Calculate interpolated frame
248  float t0 = std::get<0>(*frames[0]);
249  float t1 = std::get<0>(*frames[1]);
250  float alpha = (position - t0) / (t1 - t0);
251  T frame = interpolator(std::get<1>(*frames[0]), std::get<1>(*frames[1]), alpha);
252 
253  // Pass frame to frame callback
254  frame_callback(channel.first, frame);
255  }
256  else if (frames[0] != nullptr)
257  {
258  // Pass frame to frame callback
259  frame_callback(channel.first, std::get<1>(*frames[0]));
260  }
261  else if (frames[1] != nullptr)
262  {
263  // Pass frame to frame callback
264  frame_callback(channel.first, std::get<1>(*frames[1]));
265  }
266  }
267  }
268  }
269  else
270  {
271  if (looped)
272  {
273  ++loop_count;
274 
275  // Subtract duration of animation from position
276  position -= duration;
277 
278  // Execute loop callback
279  if (loop_callback)
280  {
281  loop_callback(loop_count);
282  }
283 
284  // Call frame callback on looped frame
285  if (frame_callback)
286  {
287  advance(0.0);
288  }
289  }
290  else
291  {
292  // Call frame callback for end frame
293  if (frame_callback != nullptr)
294  {
295  for (auto& channel: channels)
296  {
297  auto frames = channel.second.find_keyframes(channel.second.get_duration());
298  if (frames[0] != nullptr)
299  {
300  frame_callback(channel.first, std::get<1>(*frames[0]));
301  }
302  }
303  }
304 
305  stopped = true;
306 
307  // Call end callback
308  if (end_callback)
309  {
310  end_callback();
311  }
312  }
313  }
314 }
315 
316 template <typename T>
318 {
319  return &(*channels.emplace(id, id).first).second;
320 }
321 
322 template <typename T>
324 {
325  auto it = channels.find(id);
326  if (it != channels.end())
327  {
328  channels.erase(it);
329  }
330 }
331 
332 template <typename T>
334 {
335  channels.clear();
336 }
337 
338 template <typename T>
340 {
341  this->interpolator = interpolator;
342 }
343 
344 template <typename T>
345 void animation<T>::set_frame_callback(std::function<void(int, const T&)> callback)
346 {
347  this->frame_callback = callback;
348 }
349 
350 template <typename T>
352 {
353  auto it = channels.find(id);
354  if (it != channels.end())
355  {
356  return &it->second;
357  }
358 
359  return nullptr;
360 }
361 
362 template <typename T>
364 {
365  auto it = channels.find(id);
366  if (it != channels.end())
367  {
368  return &it->second;
369  }
370 
371  return nullptr;
372 }
373 
374 template <typename T>
376 {
377  float duration = 0.0;
378 
379  for (auto it = channels.begin(); it != channels.end(); ++it)
380  {
381  duration = std::max<float>(duration, it->second.get_duration());
382  }
383 
384  return duration;
385 }
386 
387 #endif // ANTKEEPER_ANIMATION_HPP
Abstract base class for keyframe animations.
Definition: animation.hpp:33
void seek(float t)
Sets the animation position to t.
Definition: animation.cpp:34
void pause()
Pauses the animation.
Definition: animation.cpp:49
bool is_paused() const
Returns true if the animation is paused, false otherwise.
Definition: animation.hpp:122
bool is_stopped() const
Returns true if the animation is stopped, false otherwise.
Definition: animation.hpp:127
void set_loop_callback(std::function< void(int)> callback)
Sets the callback that's executed when the animation loops.
Definition: animation.cpp:92
std::function< void()> start_callback
Definition: animation.hpp:112
void set_end_callback(std::function< void()> callback)
Sets the callback that's executed when a non-looped animation has finished.
Definition: animation.cpp:87
void loop(bool enabled)
Enables or disables looping of the animation.
Definition: animation.cpp:44
void set_speed(float speed)
Sets the speed of the animation.
Definition: animation.cpp:77
void rewind()
Sets the animation position to 0.0.
Definition: animation.cpp:39
int get_loop_count() const
Returns the current loop count of the animation.
Definition: animation.hpp:137
virtual float get_duration() const =0
Returns the duration of the animation.
void play()
Plays the animation.
Definition: animation.cpp:54
virtual void advance(float dt)=0
Advances the animation position (t) by dt.
void set_start_callback(std::function< void()> callback)
Sets the callback that's executed when the animation is started from a stopped state.
Definition: animation.cpp:82
std::function< void(int)> loop_callback
Definition: animation.hpp:114
float get_position() const
Returns the current position in time of the animation.
Definition: animation.hpp:132
bool is_looped() const
Returns true if looping of the animation is enabled, false otherwise.
Definition: animation.hpp:117
void stop()
Stops the animation, rewinds it, and resets the loop count.
Definition: animation.cpp:69
std::function< void()> end_callback
Definition: animation.hpp:113
Single channel in a keyframe animation.
float get_duration() const
Returns the duration of the animation channel.
std::tuple< float, T > keyframe
Keyframe consisting of a time and a value.
std::array< const keyframe *, 2 > find_keyframes(float position) const
Finds the keyframes to the left and right of position.
Keyframe animation.
Definition: animation.hpp:149
virtual float get_duration() const
Returns the duration of the animation.
Definition: animation.hpp:375
const channel * get_channel(int id) const
Returns the channel with the specified ID.
Definition: animation.hpp:351
animation_channel< T > channel
Channel for this animation type.
Definition: animation.hpp:152
void remove_channels()
Removes all channels from the animation.
Definition: animation.hpp:333
void set_interpolator(interpolator_type interpolator)
Sets the frame interpolator function object.
Definition: animation.hpp:339
channel * add_channel(int id)
Adds a channel to the animation.
Definition: animation.hpp:317
void set_frame_callback(std::function< void(int, const T &)> callback)
Sets the callback that's executed on each frame of animation.
Definition: animation.hpp:345
channel * get_channel(int id)
Returns the channel with the specified ID.
Definition: animation.hpp:363
virtual void advance(float dt)
Advances the animation position (t) by dt.
Definition: animation.hpp:224
channel::keyframe keyframe
Definition: animation.hpp:155
animation()
Creates an animation.
Definition: animation.hpp:218
std::decay< std::function< T(const T &, const T &, float)> >::type interpolator_type
Interpolator function type.
Definition: animation.hpp:158
void remove_channel(int id)
Removes a channel from the animation.
Definition: animation.hpp:323