瀏覽代碼

Added C# Animation component

BearishSun 9 年之前
父節點
當前提交
5703dd7eab

+ 101 - 0
Source/MBansheeEditor/Inspectors/AnimationInspector.cs

@@ -0,0 +1,101 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /** @addtogroup Inspectors
+     *  @{
+     */
+
+    /// <summary>
+    /// Renders an inspector for the <see cref="Animation"/> component.
+    /// </summary>
+    [CustomInspector(typeof(Animation))]
+    internal class AnimationInspector : Inspector
+    {
+        private GUIResourceField animationClipField = new GUIResourceField(typeof(AudioClip), new LocEdString("Clip"));
+        private GUIEnumField wrapModeField = new GUIEnumField(typeof(AnimWrapMode), new LocEdString("Wrap mode"));
+        private GUIFloatField speedField = new GUIFloatField(new LocEdString("Speed"));
+        private InspectableState modifyState;
+
+        /// <inheritdoc/>
+        protected internal override void Initialize()
+        {
+            BuildGUI();
+        }
+
+        /// <inheritdoc/>
+        protected internal override InspectableState Refresh()
+        {
+            Animation animation = InspectedObject as Animation;
+            if (animation == null)
+                return InspectableState.NotModified;
+
+            animationClipField.Value = animation.DefaultClip;
+            wrapModeField.Value = (ulong)animation.WrapMode;
+            speedField.Value = animation.Speed;
+
+            InspectableState oldState = modifyState;
+            if (modifyState.HasFlag(InspectableState.Modified))
+                modifyState = InspectableState.NotModified;
+
+            return oldState;
+        }
+
+        /// <summary>
+        /// Recreates all the GUI elements used by this inspector.
+        /// </summary>
+        private void BuildGUI()
+        {
+            Layout.Clear();
+
+            Animation animation = InspectedObject as Animation;
+            if (animation == null)
+                return;
+
+            animationClipField.OnChanged += x =>
+            {
+                AnimationClip clip = Resources.Load<AnimationClip>(x);
+
+                animation.DefaultClip = clip;
+                MarkAsModified();
+                ConfirmModify();
+            };
+
+            wrapModeField.OnSelectionChanged += x =>
+            {
+                animation.WrapMode = (AnimWrapMode)x;
+                MarkAsModified();
+                ConfirmModify();
+            };
+
+            speedField.OnChanged += x => { animation.Speed = x; MarkAsModified(); };
+            speedField.OnConfirmed += ConfirmModify;
+            speedField.OnFocusLost += ConfirmModify;
+            
+            Layout.AddElement(animationClipField);
+            Layout.AddElement(wrapModeField);
+            Layout.AddElement(speedField);
+        }
+
+        /// <summary>
+        /// Marks the contents of the inspector as modified.
+        /// </summary>
+        protected void MarkAsModified()
+        {
+            modifyState |= InspectableState.ModifyInProgress;
+        }
+
+        /// <summary>
+        /// Confirms any queued modifications.
+        /// </summary>
+        protected void ConfirmModify()
+        {
+            if (modifyState.HasFlag(InspectableState.ModifyInProgress))
+                modifyState |= InspectableState.Modified;
+        }
+    }
+
+    /** @} */
+}

+ 1 - 0
Source/MBansheeEditor/MBansheeEditor.csproj

@@ -41,6 +41,7 @@
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <Compile Include="Inspectors\AnimationClipInspector.cs" />
     <Compile Include="Inspectors\AnimationClipInspector.cs" />
+    <Compile Include="Inspectors\AnimationInspector.cs" />
     <Compile Include="Inspectors\AudioClipInspector.cs" />
     <Compile Include="Inspectors\AudioClipInspector.cs" />
     <Compile Include="Inspectors\AudioListenerInspector.cs" />
     <Compile Include="Inspectors\AudioListenerInspector.cs" />
     <Compile Include="Inspectors\AudioSourceInspector.cs" />
     <Compile Include="Inspectors\AudioSourceInspector.cs" />

+ 15 - 0
Source/MBansheeEditor/Window/MenuItems.cs

@@ -410,6 +410,21 @@ namespace BansheeEditor
             EditorApplication.SetSceneDirty();
             EditorApplication.SetSceneDirty();
         }
         }
 
 
+        /// <summary>
+        /// Adds an ANimation component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Animation", 7029)]
+        private static void AddAnimation()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                return;
+
+            UndoRedo.RecordSO(so, false, "Added an Animation component");
+            so.AddComponent<Animation>();
+            EditorApplication.SetSceneDirty();
+        }
+
         /// <summary>
         /// <summary>
         /// Creates a new empty scene object.
         /// Creates a new empty scene object.
         /// </summary>
         /// </summary>

+ 332 - 0
Source/MBansheeEngine/Animation/Animation.cs

@@ -0,0 +1,332 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using System;
+using System.Runtime.InteropServices;
+
+namespace BansheeEngine
+{
+    /** @addtogroup Animation
+     *  @{
+     */
+
+    /// <summary>
+    /// Determines how an animation clip behaves when it reaches the end.
+    /// </summary>
+    public enum AnimWrapMode // Note: Must match C++ enum AnimWrapMode
+    {
+        /// <summary>
+        /// Loop around to the beginning/end when the last/first frame is reached.
+        /// </summary>
+        Loop,
+        /// <summary>
+        /// Clamp to end/beginning, keeping the last/first frame active.
+        /// </summary>
+	    Clamp
+    }
+
+    /// <summary>
+    /// Determines what happens to other animation clips when a new clip starts playing.
+    /// </summary>
+    public enum AnimPlayMode // Note: Must match C++ enum AnimPlayMode
+    {
+        /// <summary>
+        /// All other animation clips are stopped.
+        /// </summary>
+        StopAll,
+        /// <summary>
+        /// Only the clips within the current layer are stopped.
+        /// </summary>
+		StopLayer
+    }
+
+    /// <summary>
+    /// Contains information about a currently playing animation clip.
+    /// </summary>
+    public struct AnimationClipState
+    {
+        /// <summary>
+        /// Layer the clip is playing on. Multiple clips can be played simulatenously on different layers.
+        /// </summary>
+        public int layer;
+
+        /// <summary>
+        /// Current time the animation is playing from.
+        /// </summary>
+        public float time;
+
+        /// <summary>
+        /// Speed at which the animation is playing.
+        /// </summary>
+        public float speed;
+
+        /// <summary>
+        /// Determines how much of an influence does the clip have on the final pose.
+        /// </summary>
+        public float weight;
+
+        /// <summary>
+        /// Determines what happens to other animation clips when a new clip starts playing.
+        /// </summary>
+        public AnimWrapMode wrapMode;
+
+        /// <summary>
+        /// Initializes the state with default values.
+        /// </summary>
+        public void InitDefault()
+        {
+            speed = 1.0f;
+            weight = 1.0f;
+            wrapMode = AnimWrapMode.Loop;
+        }
+    }
+
+    /// <summary>
+    /// Handles animation playback. Takes one or multiple animation clips as input and evaluates them every animation update
+    /// tick depending on set properties.The evaluated data is used by the core thread for skeletal animation, by the sim
+    /// thread for updating attached scene objects and bones (if skeleton is attached), or the data is made available for
+    /// manual queries in the case of generic animation.
+    /// </summary>
+    public class Animation : Component
+    {
+        private NativeAnimation _native;
+
+        [SerializeField]
+        private SerializableData serializableData = new SerializableData();
+
+        /// <summary>
+        /// Returns the non-component version of Animation that is wrapped by this component. 
+        /// </summary>
+        internal NativeAnimation Native
+        {
+            get { return _native; }
+        }
+
+        /// <summary>
+        /// Determines the default clip to play as soon as the component is enabled. If more control over playing clips is
+        /// needed use the <see cref="Play"/>, <see cref="Blend"/> and <see cref="CrossFade"/> methods to queue clips for
+        /// playback manually, and <see cref="SetState"/> method for modify their states individually.
+        /// </summary>
+        public AnimationClip DefaultClip
+        {
+            get { return serializableData.defaultClip; }
+            set
+            {
+                serializableData.defaultClip = value;
+
+                if (value != null && _native != null)
+                    _native.Play(value, 0, AnimPlayMode.StopLayer);
+            }
+        }
+
+        /// <summary>
+        /// Determines the wrap mode for all active animations. Wrap mode determines what happens when animation reaches the 
+        /// first or last frame.
+        /// <see cref="AnimWrapMode"/>
+        /// </summary>
+        public AnimWrapMode WrapMode
+        {
+            get { return serializableData.wrapMode; }
+            set
+            {
+                serializableData.wrapMode = value;
+
+                if (_native != null)
+                    _native.WrapMode = value;
+            }
+        }
+
+        /// <summary>
+        /// Determines the speed for all animations. The default value is 1.0f. Use negative values to play-back in reverse.
+        /// </summary>
+        public float Speed
+        {
+            get { return serializableData.speed; }
+            set
+            {
+                serializableData.speed = value;
+
+                if (_native != null)
+                    _native.Speed = value;
+            }
+        }
+
+        /// <summary>
+        /// Checks if any animation clips are currently playing.
+        /// </summary>
+        public bool IsPlaying
+        {
+            get
+            {
+                if (_native != null)
+                    return _native.IsPlaying();
+
+                return false;
+            }
+        }
+
+        /// <summary>
+        /// Plays the specified animation clip at the specified layer.
+        /// </summary>
+        /// <param name="clip">Clip to play.</param>
+        /// <param name="layer">Layer to play the clip in. Multiple clips can be playing at once in separate layers.</param>
+        /// <param name="playMode">Determines how are other playing animations handled when this animation starts.</param>
+        public void Play(AnimationClip clip, int layer = 0, AnimPlayMode playMode = AnimPlayMode.StopLayer)
+        {
+            if(_native != null)
+                _native.Play(clip, layer, playMode);
+        }
+
+        /// <summary>
+        /// Blends the specified animation clip with other animation clips playing in the specified layer.
+        /// </summary>
+        /// <param name="clip">Clip to blend.</param>
+        /// <param name="weight">Determines how much of an effect will the blended animation have on the final output.
+        ///                      In range [0, 1]. All animation weights on the same layer will be normalized.</param>
+        /// <param name="fadeLength">Applies the blend over a specified time period, increasing the weight as the time
+        ///                          passes. Set to zero to blend immediately. In seconds.</param>
+        /// <param name="layer">Layer to play the clip in. Multiple clips can be playing at once in separate layers.</param>
+        public void Blend(AnimationClip clip, float weight = 1.0f, float fadeLength = 0.0f, int layer = 0)
+        {
+            if (_native != null)
+                _native.Blend(clip, weight, fadeLength, layer);
+        }
+
+        /// <summary>
+        /// Fades the specified animation clip in, while fading other playing animations out, over the specified time 
+        /// period.
+        /// </summary>
+        /// <param name="clip">Clip to fade in.</param>
+        /// <param name="fadeLength">Determines the time period over which the fade occurs. In seconds.</param>
+        /// <param name="layer">Layer to play the clip in. Multiple clips can be playing at once in separate layers.</param>
+        /// <param name="playMode">Determines should all other animations be faded out, or just the ones on the same layer.
+        ///                        </param>
+        public void CrossFade(AnimationClip clip, float fadeLength = 0.0f, int layer = 0, 
+            AnimPlayMode playMode = AnimPlayMode.StopLayer)
+        {
+            if (_native != null)
+                _native.CrossFade(clip, fadeLength, layer, playMode);
+        }
+
+        /// <summary>
+        /// Stops playing all animations on the provided layer.
+        /// </summary>
+        /// <param name="layer">Layer on which to stop animations on.</param>
+        public void Stop(int layer)
+        {
+            if (_native != null)
+                _native.Stop(layer);
+        }
+
+        /// <summary>
+        /// Stops playing all animations.
+        /// </summary>
+        public void StopAll()
+        {
+            if (_native != null)
+                _native.StopAll();
+        }
+
+        /// <summary>
+        /// Retrieves detailed information about a currently playing animation clip.
+        /// </summary>
+        /// <param name="clip">Clip to retrieve the information for.</param>
+        /// <param name="state">Animation clip state containing the requested information. Only valid if the method returns
+        ///                     true.</param>
+        /// <returns>True if the state was found (animation clip is playing), false otherwise.</returns>
+        public bool GetState(AnimationClip clip, out AnimationClipState state)
+        {
+            if (_native != null)
+                return _native.GetState(clip, out state);
+
+            state = new AnimationClipState();
+            return false;
+        }
+
+        /// <summary>
+        /// Changes the state of a playing animation clip. If animation clip is not currently playing the state change is
+        /// ignored.
+        /// </summary>
+        /// <param name="clip">Clip to change the state for.</param>
+        /// <param name="state">New state of the animation (e.g. changing the time for seeking).</param>
+        public void SetState(AnimationClip clip, AnimationClipState state)
+        {
+            if (_native != null)
+                _native.SetState(clip, state);
+        }
+
+        private void OnEnabled()
+        {
+            RestoreNative();
+        }
+
+        private void OnDisabled()
+        {
+            DestroyNative();
+        }
+
+        private void OnDestroy()
+        {
+            DestroyNative();
+        }
+
+        /// <summary>
+        /// Creates the internal representation of the animation and restores the values saved by the component.
+        /// </summary>
+        private void RestoreNative()
+        {
+            if (_native != null)
+                _native.Destroy();
+
+            _native = new NativeAnimation();
+
+            // Restore saved values after reset
+            _native.WrapMode = serializableData.wrapMode;
+            _native.Speed = serializableData.speed;
+
+            if (serializableData.defaultClip != null)
+                _native.Play(serializableData.defaultClip, 0, AnimPlayMode.StopLayer);
+
+            Renderable renderable = SceneObject.GetComponent<Renderable>();
+            if (renderable == null)
+                return;
+
+            NativeRenderable nativeRenderable = renderable.Native;
+            if (nativeRenderable != null)
+                nativeRenderable.Animation = _native;
+        }
+
+        /// <summary>
+        /// Destroys the internal animation representation.
+        /// </summary>
+        private void DestroyNative()
+        {
+            Renderable renderableComponent = SceneObject.GetComponent<Renderable>();
+            if (renderableComponent != null)
+            {
+                NativeRenderable renderable = renderableComponent.Native;
+
+                if (renderable != null)
+                    renderable.Animation = null;
+            }
+
+            if (_native != null)
+            {
+                _native.Destroy();
+                _native = null;
+            }
+        }
+
+        /// <summary>
+        /// Holds all data the animation component needs to persist through serialization.
+        /// </summary>
+        [SerializeObject]
+        private class SerializableData
+        {
+            public AnimationClip defaultClip;
+            public AnimWrapMode wrapMode = AnimWrapMode.Loop;
+            public float speed = 1.0f;
+        }
+    }
+
+    /** @} */
+}

+ 134 - 0
Source/MBansheeEngine/Animation/Interop/NativeAnimation.cs

@@ -0,0 +1,134 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using System;
+using System.Runtime.CompilerServices;
+
+namespace BansheeEngine
+{
+    /** @cond INTEROP */
+
+    /// <summary>
+    /// Wrapper around the native Animation class.
+    /// <see cref="Animation"/>
+    /// </summary>
+    internal class NativeAnimation : ScriptObject
+    {
+        public AnimWrapMode WrapMode
+        {
+            set { Internal_SetWrapMode(mCachedPtr, value); }
+        }
+
+        public float Speed
+        {
+            set { Internal_SetSpeed(mCachedPtr, value); }
+        }
+
+        public void Play(AnimationClip clip, int layer, AnimPlayMode playMode)
+        {
+            IntPtr clipPtr = IntPtr.Zero;
+            if (clip != null)
+                clipPtr = clip.GetCachedPtr();
+
+            Internal_Play(mCachedPtr, clipPtr, layer, playMode);
+        }
+
+        public void Blend(AnimationClip clip, float weight, float fadeLength, int layer)
+        {
+            IntPtr clipPtr = IntPtr.Zero;
+            if (clip != null)
+                clipPtr = clip.GetCachedPtr();
+
+            Internal_Blend(mCachedPtr, clipPtr, weight, fadeLength, layer);
+        }
+
+        public void CrossFade(AnimationClip clip, float fadeLength, int layer, AnimPlayMode playMode)
+        {
+            IntPtr clipPtr = IntPtr.Zero;
+            if (clip != null)
+                clipPtr = clip.GetCachedPtr();
+
+            Internal_CrossFade(mCachedPtr, clipPtr, fadeLength, layer, playMode);
+        }
+
+        public void Stop(int layer)
+        {
+            Internal_Stop(mCachedPtr, layer);
+        }
+
+        public void StopAll()
+        {
+            Internal_StopAll(mCachedPtr);
+        }
+
+        public bool IsPlaying()
+        {
+            return Internal_IsPlaying(mCachedPtr);
+        }
+
+        public bool GetState(AnimationClip clip, out AnimationClipState state)
+        {
+            IntPtr clipPtr = IntPtr.Zero;
+            if (clip != null)
+                clipPtr = clip.GetCachedPtr();
+
+            return Internal_GetState(mCachedPtr, clipPtr, out state);
+        }
+
+        public void SetState(AnimationClip clip, AnimationClipState state)
+        {
+            IntPtr clipPtr = IntPtr.Zero;
+            if (clip != null)
+                clipPtr = clip.GetCachedPtr();
+
+            Internal_SetState(mCachedPtr, clipPtr, ref state);
+        }
+
+        internal NativeAnimation()
+        {
+            Internal_Create(this);
+        }
+        
+        internal void Destroy()
+        {
+            Internal_Destroy(mCachedPtr);
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Create(NativeAnimation instance);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Destroy(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetWrapMode(IntPtr thisPtr, AnimWrapMode wrapMode);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetSpeed(IntPtr thisPtr, float speed);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Play(IntPtr thisPtr, IntPtr clipPtr, int layer, AnimPlayMode playMode);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Blend(IntPtr thisPtr, IntPtr clipPtr, float weight, float fadeLength, int layer);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_CrossFade(IntPtr thisPtr, IntPtr clipPtr, float fadeLength, int layer, AnimPlayMode playMode);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Stop(IntPtr thisPtr, int layer);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_StopAll(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_IsPlaying(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_GetState(IntPtr thisPtr, IntPtr clipPtr, out AnimationClipState state);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetState(IntPtr thisPtr, IntPtr clipPtr, ref AnimationClipState state);
+    }
+
+    /** @endcond */
+}

+ 15 - 0
Source/MBansheeEngine/Interop/NativeRenderable.cs

@@ -48,6 +48,18 @@ namespace BansheeEngine
             set { Internal_SetLayers(mCachedPtr, value); }
             set { Internal_SetLayers(mCachedPtr, value); }
         }
         }
 
 
+        internal NativeAnimation Animation
+        {
+            set
+            {
+                IntPtr animationPtr = IntPtr.Zero;
+                if (value != null)
+                    animationPtr = value.GetCachedPtr();
+
+                Internal_SetAnimation(mCachedPtr, animationPtr);
+            }
+        }
+
         private Material[] materials = new Material[1];
         private Material[] materials = new Material[1];
         private Mesh mesh;
         private Mesh mesh;
         
         
@@ -110,6 +122,9 @@ namespace BansheeEngine
         [MethodImpl(MethodImplOptions.InternalCall)]
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_Create(NativeRenderable instance, IntPtr parentSO);
         private static extern void Internal_Create(NativeRenderable instance, IntPtr parentSO);
 
 
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetAnimation(IntPtr thisPtr, IntPtr animation);
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_UpdateTransform(IntPtr thisPtr, IntPtr parentSO);
         private static extern void Internal_UpdateTransform(IntPtr thisPtr, IntPtr parentSO);
 
 

+ 2 - 0
Source/MBansheeEngine/MBansheeEngine.csproj

@@ -43,7 +43,9 @@
     <Reference Include="System.Xml" />
     <Reference Include="System.Xml" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
+    <Compile Include="Animation\Animation.cs" />
     <Compile Include="Animation\AnimationClip.cs" />
     <Compile Include="Animation\AnimationClip.cs" />
+    <Compile Include="Animation\Interop\NativeAnimation.cs" />
     <Compile Include="Audio\Audio.cs" />
     <Compile Include="Audio\Audio.cs" />
     <Compile Include="Audio\AudioClip.cs" />
     <Compile Include="Audio\AudioClip.cs" />
     <Compile Include="Audio\AudioListener.cs" />
     <Compile Include="Audio\AudioListener.cs" />

+ 4 - 0
Source/MBansheeEngine/Rendering/Renderable.cs

@@ -129,6 +129,10 @@ namespace BansheeEngine
                 _native.Materials = serializableData.materials;
                 _native.Materials = serializableData.materials;
 
 
             _native.Layers = serializableData.layers;
             _native.Layers = serializableData.layers;
+
+            Animation animation = SceneObject.GetComponent<Animation>();
+            if (animation != null)
+                _native.Animation = animation.Native;
         }
         }
 
 
         private void OnUpdate()
         private void OnUpdate()

+ 1 - 1
Source/RenderBeast/Include/BsObjectRendering.h

@@ -87,7 +87,7 @@ namespace BansheeEngine
 		/**
 		/**
 		 * Updates object specific parameter buffers with new values. To be called whenever object specific values change.
 		 * Updates object specific parameter buffers with new values. To be called whenever object specific values change.
 		 */
 		 */
-		void updatePerObjectBuffers(RenderableElement& element, const RenderableShaderData& data, const Matrix4& wvpMatrix);
+		void updatePerObjectBuffers(const RenderableElement& element, const RenderableShaderData& data, const Matrix4& wvpMatrix);
 
 
 		/** Returns a buffer that stores per-camera parameters. */
 		/** Returns a buffer that stores per-camera parameters. */
 		const PerCameraParamBuffer& getPerCameraParams() const { return mPerCameraParams; }
 		const PerCameraParamBuffer& getPerCameraParams() const { return mPerCameraParams; }

+ 11 - 0
Source/RenderBeast/Include/BsRenderBeast.h

@@ -143,6 +143,17 @@ namespace BansheeEngine
 		 */
 		 */
 		void renderOverlay(RenderTargetData& rtData, UINT32 camIdx, float delta);
 		void renderOverlay(RenderTargetData& rtData, UINT32 camIdx, float delta);
 
 
+		/** 
+		 * Renders a single element of a renderable object. 
+		 *
+		 * @param[in]	element		Element to render.
+		 * @param[in]	passIdx		Index of the material pass to render the element with.
+		 * @param[in]	bindPass	If true the material pass will be bound for rendering, if false it is assumed it is
+		 *							already bound.
+		 * @param[in]	viewProj	View projection matrix of the camera the element is being rendered with.
+		 */
+		void renderElement(const BeastRenderableElement& element, UINT32 passIdx, bool bindPass, const Matrix4& viewProj);
+
 		/**	Creates data used by the renderer on the core thread. */
 		/**	Creates data used by the renderer on the core thread. */
 		void initializeCore();
 		void initializeCore();
 
 

+ 1 - 1
Source/RenderBeast/Source/BsObjectRendering.cpp

@@ -120,7 +120,7 @@ namespace BansheeEngine
 		mPerCameraParams.flushToGPU();
 		mPerCameraParams.flushToGPU();
 	}
 	}
 
 
-	void ObjectRenderer::updatePerObjectBuffers(RenderableElement& element, const RenderableShaderData& data, 
+	void ObjectRenderer::updatePerObjectBuffers(const RenderableElement& element, const RenderableShaderData& data, 
 		const Matrix4& wvpMatrix)
 		const Matrix4& wvpMatrix)
 	{
 	{
 		// Note: If I kept all the values in the same structure maybe a simple memcpy directly into the constant buffer
 		// Note: If I kept all the values in the same structure maybe a simple memcpy directly into the constant buffer

+ 25 - 36
Source/RenderBeast/Source/BsRenderBeast.cpp

@@ -539,24 +539,7 @@ namespace BansheeEngine
 		for (auto iter = opaqueElements.begin(); iter != opaqueElements.end(); ++iter)
 		for (auto iter = opaqueElements.begin(); iter != opaqueElements.end(); ++iter)
 		{
 		{
 			BeastRenderableElement* renderElem = static_cast<BeastRenderableElement*>(iter->renderElem);
 			BeastRenderableElement* renderElem = static_cast<BeastRenderableElement*>(iter->renderElem);
-			SPtr<MaterialCore> material = renderElem->material;
-
-			UINT32 rendererId = renderElem->renderableId;
-			Matrix4 worldViewProjMatrix = cameraShaderData.viewProj * mRenderableShaderData[rendererId].worldTransform;
-
-			mObjectRenderer->updatePerObjectBuffers(*renderElem, mRenderableShaderData[rendererId], worldViewProjMatrix);
-
-			if (iter->applyPass)
-				RendererUtility::instance().setPass(material, iter->passIdx, false);
-
-			SPtr<PassParametersCore> passParams = material->getPassParameters(iter->passIdx);
-
-			if (renderElem->samplerOverrides != nullptr)
-				setPassParams(passParams, &renderElem->samplerOverrides->passes[iter->passIdx]);
-			else
-				setPassParams(passParams, nullptr);
-
-			gRendererUtility().draw(iter->renderElem->mesh, iter->renderElem->subMesh);
+			renderElement(*renderElem, iter->passIdx, iter->applyPass, cameraShaderData.viewProj);
 		}
 		}
 
 
 		renderTargets->bindSceneColor(true);
 		renderTargets->bindSceneColor(true);
@@ -627,24 +610,7 @@ namespace BansheeEngine
 		for (auto iter = transparentElements.begin(); iter != transparentElements.end(); ++iter)
 		for (auto iter = transparentElements.begin(); iter != transparentElements.end(); ++iter)
 		{
 		{
 			BeastRenderableElement* renderElem = static_cast<BeastRenderableElement*>(iter->renderElem);
 			BeastRenderableElement* renderElem = static_cast<BeastRenderableElement*>(iter->renderElem);
-			SPtr<MaterialCore> material = renderElem->material;
-
-			UINT32 rendererId = renderElem->renderableId;
-			Matrix4 worldViewProjMatrix = cameraShaderData.viewProj * mRenderableShaderData[rendererId].worldTransform;
-
-			mObjectRenderer->updatePerObjectBuffers(*renderElem, mRenderableShaderData[rendererId], worldViewProjMatrix);
-
-			if (iter->applyPass)
-				RendererUtility::instance().setPass(material, iter->passIdx, false);
-
-			SPtr<PassParametersCore> passParams = material->getPassParameters(iter->passIdx);
-
-			if (renderElem->samplerOverrides != nullptr)
-				setPassParams(passParams, &renderElem->samplerOverrides->passes[iter->passIdx]);
-			else
-				setPassParams(passParams, nullptr);
-
-			gRendererUtility().draw(iter->renderElem->mesh, iter->renderElem->subMesh);
+			renderElement(*renderElem, iter->passIdx, iter->applyPass, cameraShaderData.viewProj);
 		}
 		}
 
 
 		// Render non-overlay post-scene callbacks
 		// Render non-overlay post-scene callbacks
@@ -684,6 +650,29 @@ namespace BansheeEngine
 		gProfilerCPU().endSample("Render");
 		gProfilerCPU().endSample("Render");
 	}
 	}
 
 
+	void RenderBeast::renderElement(const BeastRenderableElement& element, UINT32 passIdx, bool bindPass, 
+		const Matrix4& viewProj)
+	{
+		SPtr<MaterialCore> material = element.material;
+
+		UINT32 rendererId = element.renderableId;
+		Matrix4 worldViewProjMatrix = viewProj * mRenderableShaderData[rendererId].worldTransform;
+
+		mObjectRenderer->updatePerObjectBuffers(element, mRenderableShaderData[rendererId], worldViewProjMatrix);
+
+		if (bindPass)
+			RendererUtility::instance().setPass(material, passIdx, false);
+
+		SPtr<PassParametersCore> passParams = material->getPassParameters(passIdx);
+
+		if (element.samplerOverrides != nullptr)
+			setPassParams(passParams, &element.samplerOverrides->passes[passIdx]);
+		else
+			setPassParams(passParams, nullptr);
+
+		gRendererUtility().draw(element.mesh, element.subMesh);
+	}
+
 	void RenderBeast::renderOverlay(RenderTargetData& rtData, UINT32 camIdx, float delta)
 	void RenderBeast::renderOverlay(RenderTargetData& rtData, UINT32 camIdx, float delta)
 	{
 	{
 		gProfilerCPU().beginSample("RenderOverlay");
 		gProfilerCPU().beginSample("RenderOverlay");

+ 2 - 0
Source/SBansheeEngine/CMakeSources.cmake

@@ -139,6 +139,7 @@ set(BS_SBANSHEEENGINE_INC_WRAPPERS
 	"Include/BsScriptAudioSource.h"
 	"Include/BsScriptAudioSource.h"
 	"Include/BsScriptAudioListener.h"
 	"Include/BsScriptAudioListener.h"
 	"Include/BsScriptAnimationClip.h"
 	"Include/BsScriptAnimationClip.h"
+	"Include/BsScriptAnimation.h"
 )
 )
 
 
 set(BS_SBANSHEEENGINE_INC_WRAPPERS_GUI
 set(BS_SBANSHEEENGINE_INC_WRAPPERS_GUI
@@ -268,6 +269,7 @@ set(BS_SBANSHEEENGINE_SRC_WRAPPERS
 	"Source/BsScriptAudioSource.cpp"
 	"Source/BsScriptAudioSource.cpp"
 	"Source/BsScriptAudioListener.cpp"
 	"Source/BsScriptAudioListener.cpp"
 	"Source/BsScriptAnimationClip.cpp"
 	"Source/BsScriptAnimationClip.cpp"
+	"Source/BsScriptAnimation.cpp"
 )
 )
 
 
 set(BS_SBANSHEEENGINE_INC_SERIALIZATION
 set(BS_SBANSHEEENGINE_INC_SERIALIZATION

+ 54 - 0
Source/SBansheeEngine/Include/BsScriptAnimation.h

@@ -0,0 +1,54 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "BsScriptObject.h"
+#include "BsAnimation.h"
+
+namespace BansheeEngine
+{
+	class ScriptAnimationClip;
+
+	/** @addtogroup ScriptInteropEngine
+	 *  @{
+	 */
+
+	/**	Interop class between C++ & CLR for Animation. */
+	class BS_SCR_BE_EXPORT ScriptAnimation : public ScriptObject <ScriptAnimation>
+	{
+	public:
+		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "NativeAnimation")
+
+		/**	Returns the native wrapped animation. */
+		SPtr<Animation> getInternal() const { return mAnimation; }
+
+	private:
+		ScriptAnimation(MonoObject* managedInstance);
+		~ScriptAnimation();
+
+		SPtr<Animation> mAnimation;
+
+		/************************************************************************/
+		/* 								CLR HOOKS						   		*/
+		/************************************************************************/
+		static void internal_Create(MonoObject* instance);
+		static void internal_Destroy(ScriptAnimation* thisPtr);
+
+		static void internal_SetWrapMode(ScriptAnimation* thisPtr, AnimWrapMode wrapMode);
+		static void internal_SetSpeed(ScriptAnimation* thisPtr, float speed);
+
+		static void internal_Play(ScriptAnimation* thisPtr, ScriptAnimationClip* clip, UINT32 layer, AnimPlayMode playMode);
+		static void internal_Blend(ScriptAnimation* thisPtr, ScriptAnimationClip* clip, float weight, float fadeLength, UINT32 layer);
+		static void internal_CrossFade(ScriptAnimation* thisPtr, ScriptAnimationClip* clip, float fadeLength, UINT32 layer, AnimPlayMode playMode);
+
+		static void internal_Stop(ScriptAnimation* thisPtr, UINT32 layer);
+		static void internal_StopAll(ScriptAnimation* thisPtr);
+		static bool internal_IsPlaying(ScriptAnimation* thisPtr);
+
+		static bool internal_GetState(ScriptAnimation* thisPtr, ScriptAnimationClip* clip, AnimationClipState* state);
+		static void internal_SetState(ScriptAnimation* thisPtr, ScriptAnimationClip* clip, AnimationClipState* state);
+	};
+
+	/** @} */
+}

+ 5 - 2
Source/SBansheeEngine/Include/BsScriptRenderable.h

@@ -7,6 +7,8 @@
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
+	class ScriptAnimation;
+
 	/** @addtogroup ScriptInteropEngine
 	/** @addtogroup ScriptInteropEngine
 	 *  @{
 	 *  @{
 	 */
 	 */
@@ -17,7 +19,7 @@ namespace BansheeEngine
 	public:
 	public:
 		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "NativeRenderable")
 		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "NativeRenderable")
 
 
-		/**	Returns the native wrapped renderable handler. */
+		/**	Returns the native wrapped renderable. */
 		SPtr<Renderable> getInternal() const { return mRenderable; }
 		SPtr<Renderable> getInternal() const { return mRenderable; }
 
 
 	private:
 	private:
@@ -27,7 +29,7 @@ namespace BansheeEngine
 		/** Updates the internal transform of the renderable handled according to the scene object it is attached to. */
 		/** Updates the internal transform of the renderable handled according to the scene object it is attached to. */
 		void updateTransform(const HSceneObject& parent);
 		void updateTransform(const HSceneObject& parent);
 
 
-		/**	Destroys the internal renderable handler object. */
+		/**	Destroys the internal renderable object. */
 		void destroy();
 		void destroy();
 
 
 		/** @copydoc ScriptObject::_onManagedInstanceDeleted */
 		/** @copydoc ScriptObject::_onManagedInstanceDeleted */
@@ -40,6 +42,7 @@ namespace BansheeEngine
 		/* 								CLR HOOKS						   		*/
 		/* 								CLR HOOKS						   		*/
 		/************************************************************************/
 		/************************************************************************/
 		static void internal_Create(MonoObject* instance, ScriptSceneObject* parentSO);
 		static void internal_Create(MonoObject* instance, ScriptSceneObject* parentSO);
+		static void internal_SetAnimation(ScriptRenderable* thisPtr, ScriptAnimation* animation);
 		static void internal_UpdateTransform(ScriptRenderable* thisPtr, ScriptSceneObject* parentSO);
 		static void internal_UpdateTransform(ScriptRenderable* thisPtr, ScriptSceneObject* parentSO);
 		static void internal_SetMesh(ScriptRenderable* thisPtr, ScriptMesh* mesh);
 		static void internal_SetMesh(ScriptRenderable* thisPtr, ScriptMesh* mesh);
 		static void internal_GetBounds(ScriptRenderable* thisPtr, ScriptSceneObject* parentSO, AABox* box, Sphere* sphere);
 		static void internal_GetBounds(ScriptRenderable* thisPtr, ScriptSceneObject* parentSO, AABox* box, Sphere* sphere);

+ 121 - 0
Source/SBansheeEngine/Source/BsScriptAnimation.cpp

@@ -0,0 +1,121 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsScriptAnimation.h"
+#include "BsScriptMeta.h"
+#include "BsMonoField.h"
+#include "BsMonoClass.h"
+#include "BsMonoManager.h"
+#include "BsMonoUtil.h"
+#include "BsScriptAnimationClip.h"
+
+namespace BansheeEngine
+{
+	ScriptAnimation::ScriptAnimation(MonoObject* managedInstance)
+		:ScriptObject(managedInstance), mAnimation(nullptr)
+	{
+		mAnimation = Animation::create();
+	}
+
+	ScriptAnimation::~ScriptAnimation()
+	{ }
+
+	void ScriptAnimation::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_Create", &ScriptAnimation::internal_Create);
+		metaData.scriptClass->addInternalCall("Internal_Destroy", &ScriptAnimation::internal_Destroy);
+
+		metaData.scriptClass->addInternalCall("Internal_SetWrapMode", &ScriptAnimation::internal_SetWrapMode);
+		metaData.scriptClass->addInternalCall("Internal_SetSpeed", &ScriptAnimation::internal_SetSpeed);
+
+		metaData.scriptClass->addInternalCall("Internal_Play", &ScriptAnimation::internal_Play);
+		metaData.scriptClass->addInternalCall("Internal_Blend", &ScriptAnimation::internal_Blend);
+		metaData.scriptClass->addInternalCall("Internal_CrossFade", &ScriptAnimation::internal_CrossFade);
+
+		metaData.scriptClass->addInternalCall("Internal_Stop", &ScriptAnimation::internal_Stop);
+		metaData.scriptClass->addInternalCall("Internal_StopAll", &ScriptAnimation::internal_StopAll);
+		metaData.scriptClass->addInternalCall("Internal_IsPlaying", &ScriptAnimation::internal_IsPlaying);
+
+		metaData.scriptClass->addInternalCall("Internal_GetState", &ScriptAnimation::internal_GetState);
+		metaData.scriptClass->addInternalCall("Internal_SetState", &ScriptAnimation::internal_SetState);
+	}
+
+	void ScriptAnimation::internal_Create(MonoObject* instance)
+	{
+		new (bs_alloc<ScriptAnimation>()) ScriptAnimation(instance);
+	}
+
+	void ScriptAnimation::internal_Destroy(ScriptAnimation* thisPtr)
+	{
+		thisPtr->mAnimation = nullptr;
+	}
+
+	void ScriptAnimation::internal_SetWrapMode(ScriptAnimation* thisPtr, AnimWrapMode wrapMode)
+	{
+		thisPtr->getInternal()->setWrapMode(wrapMode);
+	}
+
+	void ScriptAnimation::internal_SetSpeed(ScriptAnimation* thisPtr, float speed)
+	{
+		thisPtr->getInternal()->setSpeed(speed);
+	}
+
+	void ScriptAnimation::internal_Play(ScriptAnimation* thisPtr, ScriptAnimationClip* clip, UINT32 layer, AnimPlayMode playMode)
+	{
+		HAnimationClip nativeClip;
+		if (clip != nullptr)
+			nativeClip = clip->getHandle();
+
+		thisPtr->getInternal()->play(nativeClip, layer, playMode);
+	}
+
+	void ScriptAnimation::internal_Blend(ScriptAnimation* thisPtr, ScriptAnimationClip* clip, float weight, float fadeLength, UINT32 layer)
+	{
+		HAnimationClip nativeClip;
+		if (clip != nullptr)
+			nativeClip = clip->getHandle();
+
+		thisPtr->getInternal()->blend(nativeClip, weight, fadeLength, layer);
+	}
+
+	void ScriptAnimation::internal_CrossFade(ScriptAnimation* thisPtr, ScriptAnimationClip* clip, float fadeLength, UINT32 layer, AnimPlayMode playMode)
+	{
+		HAnimationClip nativeClip;
+		if (clip != nullptr)
+			nativeClip = clip->getHandle();
+
+		thisPtr->getInternal()->crossFade(nativeClip, fadeLength, layer, playMode);
+	}
+
+	void ScriptAnimation::internal_Stop(ScriptAnimation* thisPtr, UINT32 layer)
+	{
+		thisPtr->getInternal()->stop(layer);
+	}
+
+	void ScriptAnimation::internal_StopAll(ScriptAnimation* thisPtr)
+	{
+		thisPtr->getInternal()->stopAll();
+	}
+
+	bool ScriptAnimation::internal_IsPlaying(ScriptAnimation* thisPtr)
+	{
+		return thisPtr->getInternal()->isPlaying();
+	}
+
+	bool ScriptAnimation::internal_GetState(ScriptAnimation* thisPtr, ScriptAnimationClip* clip, AnimationClipState* state)
+	{
+		HAnimationClip nativeClip;
+		if (clip != nullptr)
+			nativeClip = clip->getHandle();
+
+		return thisPtr->getInternal()->getState(nativeClip, *state);
+	}
+
+	void ScriptAnimation::internal_SetState(ScriptAnimation* thisPtr, ScriptAnimationClip* clip, AnimationClipState* state)
+	{
+		HAnimationClip nativeClip;
+		if (clip != nullptr)
+			nativeClip = clip->getHandle();
+
+		thisPtr->getInternal()->setState(nativeClip, *state);
+	}
+}

+ 7 - 0
Source/SBansheeEngine/Source/BsScriptRenderable.cpp

@@ -12,6 +12,7 @@
 #include "BsSceneObject.h"
 #include "BsSceneObject.h"
 #include "BsSceneManager.h"
 #include "BsSceneManager.h"
 #include "BsScriptMesh.h"
 #include "BsScriptMesh.h"
+#include "BsScriptAnimation.h"
 #include "BsScriptMaterial.h"
 #include "BsScriptMaterial.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
@@ -29,6 +30,7 @@ namespace BansheeEngine
 	void ScriptRenderable::initRuntimeData()
 	void ScriptRenderable::initRuntimeData()
 	{
 	{
 		metaData.scriptClass->addInternalCall("Internal_Create", &ScriptRenderable::internal_Create);
 		metaData.scriptClass->addInternalCall("Internal_Create", &ScriptRenderable::internal_Create);
+		metaData.scriptClass->addInternalCall("Internal_SetAnimation", &ScriptRenderable::internal_SetAnimation);
 		metaData.scriptClass->addInternalCall("Internal_UpdateTransform", &ScriptRenderable::internal_UpdateTransform);
 		metaData.scriptClass->addInternalCall("Internal_UpdateTransform", &ScriptRenderable::internal_UpdateTransform);
 		metaData.scriptClass->addInternalCall("Internal_SetMesh", &ScriptRenderable::internal_SetMesh);
 		metaData.scriptClass->addInternalCall("Internal_SetMesh", &ScriptRenderable::internal_SetMesh);
 		metaData.scriptClass->addInternalCall("Internal_GetBounds", &ScriptRenderable::internal_GetBounds);
 		metaData.scriptClass->addInternalCall("Internal_GetBounds", &ScriptRenderable::internal_GetBounds);
@@ -65,6 +67,11 @@ namespace BansheeEngine
 		new (bs_alloc<ScriptRenderable>()) ScriptRenderable(instance, so);
 		new (bs_alloc<ScriptRenderable>()) ScriptRenderable(instance, so);
 	}
 	}
 
 
+	void ScriptRenderable::internal_SetAnimation(ScriptRenderable* thisPtr, ScriptAnimation* animation)
+	{
+		thisPtr->getInternal()->setAnimation(animation->getInternal());
+	}
+
 	void ScriptRenderable::internal_UpdateTransform(ScriptRenderable* thisPtr, ScriptSceneObject* parent)
 	void ScriptRenderable::internal_UpdateTransform(ScriptRenderable* thisPtr, ScriptSceneObject* parent)
 	{
 	{
 		HSceneObject parentSO = parent->getNativeSceneObject();
 		HSceneObject parentSO = parent->getNativeSceneObject();