💿🐜 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.

202 lines
5.0 KiB

  1. /*
  2. * Copyright (C) 2021 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_CHANNEL_HPP
  20. #define ANTKEEPER_ANIMATION_CHANNEL_HPP
  21. #include <list>
  22. #include <set>
  23. #include <tuple>
  24. /**
  25. * Single channel in a keyframe animation.
  26. *
  27. * @see animation
  28. */
  29. template <typename T>
  30. class animation_channel
  31. {
  32. public:
  33. /// Keyframe consisting of a time and a value.
  34. typedef std::tuple<double, T> keyframe;
  35. /**
  36. * Creates an animation channel.
  37. *
  38. * @param id ID of the channel.
  39. */
  40. animation_channel(int id);
  41. /// Creates an animation channel.
  42. animation_channel();
  43. /// Creates an animation channel.
  44. animation_channel(const animation_channel& other);
  45. /// Assigns the contents of another channel to this channel.
  46. animation_channel& operator=(const animation_channel& other);
  47. /**
  48. * Adds a keyframe to the animation.
  49. *
  50. * @param k Keyframe to add.
  51. */
  52. void insert_keyframe(const keyframe& k);
  53. /**
  54. * Removes all keyframes on `[start, end)`.
  55. *
  56. * @param start Starting position in time (inclusive).
  57. * @param end Ending position in time (non-inclusive).
  58. */
  59. void remove_keyframes(double start, double end);
  60. /// Removes all keyframes from the animation.
  61. void remove_keyframes();
  62. /**
  63. * Finds the keyframes to the left and right of @p position.
  64. *
  65. * @param position Position in time.
  66. * @return Array containing the the keyframes on the left and right of @p position.
  67. */
  68. std::array<const keyframe*, 2> find_keyframes(double position) const;
  69. /**
  70. * Finds all the keyframes on `[start, end)`.
  71. *
  72. * @param start Starting position in time (inclusive).
  73. * @param end Ending position in time (non-inclusive).
  74. * @return All keyframes on `[start, end)`.
  75. */
  76. std::list<keyframe> find_keyframes(double start, double end) const;
  77. /// Returns the ID of the animation channel.
  78. int get_id() const;
  79. /// Returns the duration of the animation channel.
  80. double get_duration() const;
  81. private:
  82. struct keyframe_compare
  83. {
  84. inline bool operator()(const keyframe& lhs, const keyframe& rhs) const
  85. {
  86. return std::get<0>(lhs) < std::get<0>(rhs);
  87. }
  88. };
  89. int id;
  90. std::set<keyframe, keyframe_compare> keyframes;
  91. };
  92. template <typename T>
  93. animation_channel<T>::animation_channel(int id):
  94. id(id),
  95. keyframes(keyframe_compare())
  96. {}
  97. template <typename T>
  98. animation_channel<T>::animation_channel():
  99. animation_channel(-1)
  100. {}
  101. template <typename T>
  102. animation_channel<T>::animation_channel(const animation_channel& other):
  103. id(other.id),
  104. keyframes(other.keyframes)
  105. {}
  106. template <typename T>
  107. animation_channel<T>& animation_channel<T>::operator=(const animation_channel& other)
  108. {
  109. id = other.id;
  110. keyframes = other.keyframes;
  111. }
  112. template <typename T>
  113. void animation_channel<T>::insert_keyframe(const keyframe& k)
  114. {
  115. keyframes.emplace(k);
  116. }
  117. template <typename T>
  118. void animation_channel<T>::remove_keyframes(double start, double end)
  119. {
  120. auto lower_bound = keyframes.lower_bound({start, T()});
  121. auto upper_bound = keyframes.upper_bound({end, T()});
  122. keyframes.erase(lower_bound, upper_bound);
  123. }
  124. template <typename T>
  125. void animation_channel<T>::remove_keyframes()
  126. {
  127. keyframes.clear();
  128. }
  129. template <typename T>
  130. std::array<const typename animation_channel<T>::keyframe*, 2> animation_channel<T>::find_keyframes(double position) const
  131. {
  132. // Find the following keyframe
  133. auto upper_bound = keyframes.upper_bound({position, T()});
  134. // Find the preceding keyframe
  135. auto lower_bound = upper_bound;
  136. --lower_bound;
  137. std::array<const keyframe*, 2> frames;
  138. frames[0] = (lower_bound != keyframes.end()) ? &(*lower_bound) : nullptr;
  139. frames[1] = (upper_bound != keyframes.end()) ? &(*upper_bound) : nullptr;
  140. return frames;
  141. }
  142. template <typename T>
  143. std::list<typename animation_channel<T>::keyframe> animation_channel<T>::find_keyframes(double start, double end) const
  144. {
  145. std::list<keyframe> keyframe_list;
  146. auto lower_bound = keyframes.lower_bound({start, T()});
  147. auto upper_bound = keyframes.upper_bound({end, T()});
  148. for (auto iterator = lower_bound; iterator != upper_bound; ++iterator)
  149. {
  150. keyframe_list.push_back(*iterator);
  151. }
  152. return keyframe_list;
  153. }
  154. template <typename T>
  155. inline int animation_channel<T>::get_id() const
  156. {
  157. return id;
  158. }
  159. template <typename T>
  160. double animation_channel<T>::get_duration() const
  161. {
  162. if (keyframes.empty())
  163. {
  164. return 0.0;
  165. }
  166. return std::get<0>(*keyframes.rbegin());
  167. }
  168. #endif // ANTKEEPER_ANIMATION_CHANNEL_HPP