💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

235 lines
5.9 KiB

  1. /*
  2. * Copyright (C) 2020 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. #ifndef ANTKEEPER_ANIMATION_HPP
  20. #define ANTKEEPER_ANIMATION_HPP
  21. #include <functional>
  22. #include <set>
  23. #include <tuple>
  24. #include <type_traits>
  25. /**
  26. * Abstract base class for animations.
  27. */
  28. class animation_base
  29. {
  30. public:
  31. animation_base();
  32. /**
  33. * Advances the animation position (t) by @p dt.
  34. *
  35. * @param dt Delta time by which the animation position will be advanced.
  36. */
  37. virtual void advance(double dt) = 0;
  38. /**
  39. * Sets the animation position to @p t.
  40. *
  41. * @param t Position in time to which the animation position will be set.
  42. */
  43. void seek(double t);
  44. void reset();
  45. /// Returns the current position in time of the animation.
  46. double get_position() const;
  47. /// Sets the callback that's executed when the animation is started.
  48. void set_start_callback(std::function<void()> callback);
  49. /// Sets the callback that's executed when the animation ends.
  50. void set_end_callback(std::function<void()> callback);
  51. /// Sets the callback that's executed when the animation loops.
  52. void set_loop_callback(std::function<void()> callback);
  53. protected:
  54. double position;
  55. std::function<void()> start_callback;
  56. std::function<void()> end_callback;
  57. std::function<void()> loop_callback;
  58. };
  59. /**
  60. * Templated keyframe animation class.
  61. */
  62. template <typename T>
  63. class animation: public animation_base
  64. {
  65. public:
  66. /// Scheduled function consisting of a time and function object.
  67. typedef std::tuple<double, T> keyframe;
  68. /// Interpolator function type.
  69. typedef typename std::decay<std::function<T(const T&, const T&, double)>>::type interpolator_type;
  70. /// Creates an animation
  71. animation();
  72. /// @copydoc animation_base::advance()
  73. virtual void advance(double dt);
  74. /**
  75. * Adds a keyframe to the animation.
  76. *
  77. * @param k Keyframe to add.
  78. */
  79. void insert_keyframe(const keyframe& k);
  80. /**
  81. * Removes all keyframes on `[start, end)`.
  82. *
  83. * @param start Starting position in time (inclusive).
  84. * @param end Ending position in time (non-inclusive).
  85. */
  86. void remove_keyframes(double start, double end);
  87. /**
  88. * Returns all the keyframes on `[start, end)`.
  89. *
  90. * @param start Starting position in time (inclusive).
  91. * @param end Ending position in time (non-inclusive).
  92. * @return All keyframes on `[start, end)`.
  93. */
  94. std::list<keyframe> get_keyframes(double start, double end) const;
  95. /// Removes all keyframes from the animation.
  96. void clear();
  97. /**
  98. * Sets the frame interpolator function object.
  99. *
  100. * @param interpolator Frame interpolator function object.
  101. */
  102. void set_interpolator(interpolator_type interpolator);
  103. /**
  104. * Sets the callback that's executed on each frame of animation.
  105. *
  106. * @param callback Frame callback which receives the value of the interpolated frames.
  107. */
  108. void set_frame_callback(std::function<void(const T&)> callback);
  109. private:
  110. //static bool keyframe_compare(const keyframe& a, const keyframe & b);
  111. struct keyframe_compare
  112. {
  113. inline bool operator()(const keyframe& lhs, const keyframe& rhs) const
  114. {
  115. return std::get<0>(lhs) < std::get<0>(rhs);
  116. }
  117. };
  118. interpolator_type interpolator;
  119. std::function<void(const T&)> frame_callback;
  120. std::set<keyframe, keyframe_compare> keyframes;
  121. };
  122. /*
  123. template <typename T>
  124. bool animation<T>::keyframe_compare(const keyframe& a, const keyframe & b)
  125. {
  126. return std::get<0>(a) < std::get<0>(b);
  127. }
  128. */
  129. template <typename T>
  130. animation<T>::animation():
  131. interpolator(nullptr),
  132. frame_callback(nullptr),
  133. keyframes(keyframe_compare())
  134. {}
  135. template <typename T>
  136. void animation<T>::advance(double dt)
  137. {
  138. position += dt;
  139. if (frame_callback != nullptr && interpolator != nullptr)
  140. {
  141. auto upper_bound = keyframes.upper_bound({position, T()});
  142. auto lower_bound = upper_bound;
  143. --lower_bound;
  144. if (lower_bound != keyframes.end() && upper_bound != keyframes.end())
  145. {
  146. // Calculate interpolated frame
  147. double t0 = std::get<0>(*lower_bound);
  148. double t1 = std::get<0>(*upper_bound);
  149. double alpha = (position - t0) / (t1 - t0);
  150. T frame = interpolator(std::get<1>(*lower_bound), std::get<1>(*upper_bound), alpha);
  151. // Pass frame to frame callback
  152. frame_callback(frame);
  153. }
  154. }
  155. }
  156. template <typename T>
  157. void animation<T>::insert_keyframe(const keyframe& k)
  158. {
  159. keyframes.emplace(k);
  160. }
  161. template <typename T>
  162. void animation<T>::remove_keyframes(double start, double end)
  163. {
  164. auto lower_bound = keyframes.lower_bound({start, T()});
  165. auto upper_bound = keyframes.upper_bound({end, T()});
  166. keyframes.erase(lower_bound, upper_bound);
  167. }
  168. template <typename T>
  169. std::list<typename animation<T>::keyframe> animation<T>::get_keyframes(double start, double end) const
  170. {
  171. std::list<keyframe> keyframe_list;
  172. auto lower_bound = keyframes.lower_bound({start, T()});
  173. auto upper_bound = keyframes.upper_bound({end, T()});
  174. for (auto iterator = lower_bound; iterator != upper_bound; ++iterator)
  175. {
  176. keyframe_list.push_back(*iterator);
  177. }
  178. return keyframe_list;
  179. }
  180. template <typename T>
  181. void animation<T>::clear()
  182. {
  183. keyframes.clear();
  184. }
  185. template <typename T>
  186. void animation<T>::set_interpolator(interpolator_type interpolator)
  187. {
  188. this->interpolator = interpolator;
  189. }
  190. template <typename T>
  191. void animation<T>::set_frame_callback(std::function<void(const T&)> callback)
  192. {
  193. this->frame_callback = callback;
  194. }
  195. #endif // ANTKEEPER_ANIMATION_HPP