Animation.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. using System;
  4. using System.Runtime.InteropServices;
  5. namespace BansheeEngine
  6. {
  7. /** @addtogroup Animation
  8. * @{
  9. */
  10. /// <summary>
  11. /// Determines how an animation clip behaves when it reaches the end.
  12. /// </summary>
  13. public enum AnimWrapMode // Note: Must match C++ enum AnimWrapMode
  14. {
  15. /// <summary>
  16. /// Loop around to the beginning/end when the last/first frame is reached.
  17. /// </summary>
  18. Loop,
  19. /// <summary>
  20. /// Clamp to end/beginning, keeping the last/first frame active.
  21. /// </summary>
  22. Clamp
  23. }
  24. /// <summary>
  25. /// Determines what happens to other animation clips when a new clip starts playing.
  26. /// </summary>
  27. public enum AnimPlayMode // Note: Must match C++ enum AnimPlayMode
  28. {
  29. /// <summary>
  30. /// All other animation clips are stopped.
  31. /// </summary>
  32. StopAll,
  33. /// <summary>
  34. /// Only the clips within the current layer are stopped.
  35. /// </summary>
  36. StopLayer
  37. }
  38. /// <summary>
  39. /// Contains information about a currently playing animation clip.
  40. /// </summary>
  41. public struct AnimationClipState
  42. {
  43. /// <summary>
  44. /// Layer the clip is playing on. Multiple clips can be played simulatenously on different layers.
  45. /// </summary>
  46. public int layer;
  47. /// <summary>
  48. /// Current time the animation is playing from.
  49. /// </summary>
  50. public float time;
  51. /// <summary>
  52. /// Speed at which the animation is playing.
  53. /// </summary>
  54. public float speed;
  55. /// <summary>
  56. /// Determines how much of an influence does the clip have on the final pose.
  57. /// </summary>
  58. public float weight;
  59. /// <summary>
  60. /// Determines what happens to other animation clips when a new clip starts playing.
  61. /// </summary>
  62. public AnimWrapMode wrapMode;
  63. /// <summary>
  64. /// Initializes the state with default values.
  65. /// </summary>
  66. public void InitDefault()
  67. {
  68. speed = 1.0f;
  69. weight = 1.0f;
  70. wrapMode = AnimWrapMode.Loop;
  71. }
  72. }
  73. /// <summary>
  74. /// Handles animation playback. Takes one or multiple animation clips as input and evaluates them every animation update
  75. /// tick depending on set properties.The evaluated data is used by the core thread for skeletal animation, by the sim
  76. /// thread for updating attached scene objects and bones (if skeleton is attached), or the data is made available for
  77. /// manual queries in the case of generic animation.
  78. /// </summary>
  79. public class Animation : Component
  80. {
  81. private NativeAnimation _native;
  82. [SerializeField]
  83. private SerializableData serializableData = new SerializableData();
  84. /// <summary>
  85. /// Returns the non-component version of Animation that is wrapped by this component.
  86. /// </summary>
  87. internal NativeAnimation Native
  88. {
  89. get { return _native; }
  90. }
  91. /// <summary>
  92. /// Determines the default clip to play as soon as the component is enabled. If more control over playing clips is
  93. /// needed use the <see cref="Play"/>, <see cref="Blend"/> and <see cref="CrossFade"/> methods to queue clips for
  94. /// playback manually, and <see cref="SetState"/> method for modify their states individually.
  95. /// </summary>
  96. public AnimationClip DefaultClip
  97. {
  98. get { return serializableData.defaultClip; }
  99. set
  100. {
  101. serializableData.defaultClip = value;
  102. if (value != null && _native != null)
  103. _native.Play(value, 0, AnimPlayMode.StopLayer);
  104. }
  105. }
  106. /// <summary>
  107. /// Determines the wrap mode for all active animations. Wrap mode determines what happens when animation reaches the
  108. /// first or last frame.
  109. /// <see cref="AnimWrapMode"/>
  110. /// </summary>
  111. public AnimWrapMode WrapMode
  112. {
  113. get { return serializableData.wrapMode; }
  114. set
  115. {
  116. serializableData.wrapMode = value;
  117. if (_native != null)
  118. _native.WrapMode = value;
  119. }
  120. }
  121. /// <summary>
  122. /// Determines the speed for all animations. The default value is 1.0f. Use negative values to play-back in reverse.
  123. /// </summary>
  124. public float Speed
  125. {
  126. get { return serializableData.speed; }
  127. set
  128. {
  129. serializableData.speed = value;
  130. if (_native != null)
  131. _native.Speed = value;
  132. }
  133. }
  134. /// <summary>
  135. /// Checks if any animation clips are currently playing.
  136. /// </summary>
  137. public bool IsPlaying
  138. {
  139. get
  140. {
  141. if (_native != null)
  142. return _native.IsPlaying();
  143. return false;
  144. }
  145. }
  146. /// <summary>
  147. /// Plays the specified animation clip at the specified layer.
  148. /// </summary>
  149. /// <param name="clip">Clip to play.</param>
  150. /// <param name="layer">Layer to play the clip in. Multiple clips can be playing at once in separate layers.</param>
  151. /// <param name="playMode">Determines how are other playing animations handled when this animation starts.</param>
  152. public void Play(AnimationClip clip, int layer = 0, AnimPlayMode playMode = AnimPlayMode.StopLayer)
  153. {
  154. if(_native != null)
  155. _native.Play(clip, layer, playMode);
  156. }
  157. /// <summary>
  158. /// Blends the specified animation clip with other animation clips playing in the specified layer.
  159. /// </summary>
  160. /// <param name="clip">Clip to blend.</param>
  161. /// <param name="weight">Determines how much of an effect will the blended animation have on the final output.
  162. /// In range [0, 1]. All animation weights on the same layer will be normalized.</param>
  163. /// <param name="fadeLength">Applies the blend over a specified time period, increasing the weight as the time
  164. /// passes. Set to zero to blend immediately. In seconds.</param>
  165. /// <param name="layer">Layer to play the clip in. Multiple clips can be playing at once in separate layers.</param>
  166. public void Blend(AnimationClip clip, float weight = 1.0f, float fadeLength = 0.0f, int layer = 0)
  167. {
  168. if (_native != null)
  169. _native.Blend(clip, weight, fadeLength, layer);
  170. }
  171. /// <summary>
  172. /// Fades the specified animation clip in, while fading other playing animations out, over the specified time
  173. /// period.
  174. /// </summary>
  175. /// <param name="clip">Clip to fade in.</param>
  176. /// <param name="fadeLength">Determines the time period over which the fade occurs. In seconds.</param>
  177. /// <param name="layer">Layer to play the clip in. Multiple clips can be playing at once in separate layers.</param>
  178. /// <param name="playMode">Determines should all other animations be faded out, or just the ones on the same layer.
  179. /// </param>
  180. public void CrossFade(AnimationClip clip, float fadeLength = 0.0f, int layer = 0,
  181. AnimPlayMode playMode = AnimPlayMode.StopLayer)
  182. {
  183. if (_native != null)
  184. _native.CrossFade(clip, fadeLength, layer, playMode);
  185. }
  186. /// <summary>
  187. /// Stops playing all animations on the provided layer.
  188. /// </summary>
  189. /// <param name="layer">Layer on which to stop animations on.</param>
  190. public void Stop(int layer)
  191. {
  192. if (_native != null)
  193. _native.Stop(layer);
  194. }
  195. /// <summary>
  196. /// Stops playing all animations.
  197. /// </summary>
  198. public void StopAll()
  199. {
  200. if (_native != null)
  201. _native.StopAll();
  202. }
  203. /// <summary>
  204. /// Retrieves detailed information about a currently playing animation clip.
  205. /// </summary>
  206. /// <param name="clip">Clip to retrieve the information for.</param>
  207. /// <param name="state">Animation clip state containing the requested information. Only valid if the method returns
  208. /// true.</param>
  209. /// <returns>True if the state was found (animation clip is playing), false otherwise.</returns>
  210. public bool GetState(AnimationClip clip, out AnimationClipState state)
  211. {
  212. if (_native != null)
  213. return _native.GetState(clip, out state);
  214. state = new AnimationClipState();
  215. return false;
  216. }
  217. /// <summary>
  218. /// Changes the state of a playing animation clip. If animation clip is not currently playing the state change is
  219. /// ignored.
  220. /// </summary>
  221. /// <param name="clip">Clip to change the state for.</param>
  222. /// <param name="state">New state of the animation (e.g. changing the time for seeking).</param>
  223. public void SetState(AnimationClip clip, AnimationClipState state)
  224. {
  225. if (_native != null)
  226. _native.SetState(clip, state);
  227. }
  228. private void OnEnabled()
  229. {
  230. RestoreNative();
  231. }
  232. private void OnDisabled()
  233. {
  234. DestroyNative();
  235. }
  236. private void OnDestroy()
  237. {
  238. DestroyNative();
  239. }
  240. /// <summary>
  241. /// Creates the internal representation of the animation and restores the values saved by the component.
  242. /// </summary>
  243. private void RestoreNative()
  244. {
  245. if (_native != null)
  246. _native.Destroy();
  247. _native = new NativeAnimation();
  248. // Restore saved values after reset
  249. _native.WrapMode = serializableData.wrapMode;
  250. _native.Speed = serializableData.speed;
  251. if (serializableData.defaultClip != null)
  252. _native.Play(serializableData.defaultClip, 0, AnimPlayMode.StopLayer);
  253. Renderable renderable = SceneObject.GetComponent<Renderable>();
  254. if (renderable == null)
  255. return;
  256. NativeRenderable nativeRenderable = renderable.Native;
  257. if (nativeRenderable != null)
  258. nativeRenderable.Animation = _native;
  259. }
  260. /// <summary>
  261. /// Destroys the internal animation representation.
  262. /// </summary>
  263. private void DestroyNative()
  264. {
  265. Renderable renderableComponent = SceneObject.GetComponent<Renderable>();
  266. if (renderableComponent != null)
  267. {
  268. NativeRenderable renderable = renderableComponent.Native;
  269. if (renderable != null)
  270. renderable.Animation = null;
  271. }
  272. if (_native != null)
  273. {
  274. _native.Destroy();
  275. _native = null;
  276. }
  277. }
  278. /// <summary>
  279. /// Holds all data the animation component needs to persist through serialization.
  280. /// </summary>
  281. [SerializeObject]
  282. private class SerializableData
  283. {
  284. public AnimationClip defaultClip;
  285. public AnimWrapMode wrapMode = AnimWrapMode.Loop;
  286. public float speed = 1.0f;
  287. }
  288. }
  289. /** @} */
  290. }