//////////////////////////////////////////////////////////////////////////////
/// \file CooneyAnimatedMesh.h
///
/// Contains AnimatedMesh:
/// Simple animation scheme that allows mesh animation by doing mesh-to-mesh
/// interpolation. This is faster than using a full skeleton, but requires
/// more memory and is less dynamic.
///
/// Stephen Timothy Cooney, 2009
//////////////////////////////////////////////////////////////////////////////
#ifndef COONEYANIMATEDMESH_H
#define COONEYANIMATEDMESH_H

#include "CooneyMesh.h"
#include <map>

namespace Cooney
{	
	/// Simple animation scheme that allows mesh animation by doing mesh-to-mesh
	/// interpolation. This is faster than using a full skeleton, but requires
	/// more memory and is less dynamic.
	class AnimatedMesh
	{
	protected:
		std::map<float, Cooney::Mesh*> keys; /// key meshes tied to time(the float)
		std::vector<Cooney::Mesh*> keymeshes; /// container of all unique owned meshes, for memory management. NOT for direct use.
		
		float timeRate; /// rate at which time passes ( default 1.0f )
		bool bLoop; /// if true, starts at the beginning once at the end...
		bool bPlaying; /// if true, the mesh is currently animating.
		
		float currentTime; /// the local mesh-time of where the animation is.
		Cooney::Mesh interpolatedMesh; // the up-to-date animated mesh.
	public:
		AnimatedMesh();
		~AnimatedMesh();
		
		/// Return a reference to teh deformed/animating mesh.
		Cooney::Mesh& Mesh(){return interpolatedMesh;}
		
		/// Add a keyframe by loading a mesh file. Attaches
		/// this loaded mesh to a time. The animated mesh will
		/// manage the memory created when loading from the file.
		bool AddKey(float time, const char* filename);
		/// Connects a mesh to a time. If connected with this
		/// function, the AnimatedMesh is NOT responsible for
		/// the memory of the mesh. Memory management is not
		/// necessary since this only contains references for
		/// animation.
		bool AddKey(float time, Cooney::Mesh* mesh);
		/// Removes a keyframe at a point in the timeline.
		bool DeleteKey(float time);
		/// Remove keyframes between a start and an endtime.
		bool DeleteKeys(float lowTime, float highTime);
		
		/// Set the current local animation time to a point in
		/// the local timeline.
		bool SetTime(float time);
		/// Begins playing the mesh if it is not already playing.
		bool Play(bool bShouldLoop = true, float timePlayRate = 1.0f);
		/// Stop playing the mesh animation.
		void Stop(bool bReset = false);
		/// Reset the animation to the start of the timeline.
		void Reset();
		
		/// Increment the timeline, stop or loop if at the end.
		void Update(float timeStep);
		/// Update the local version of the deformed mesh. This should
		/// be called before rendering the deformed/animating mesh.
		void UpdateMesh();
		
		/// Render the deformed/animating mesh.
		void PushGL(bool bPositions=true, bool bNormals=false, bool bTangents=false, bool bColors=false, bool bTexCoords=false);
		
		/// Load an animation from file.
		bool Load(const char* filePath);
		/// Save the current animation to file.
		bool Save(const char* filePath);
		
		/// Load an animation from a data-stream.
		void StreamInAnimatedMesh(std::istream& inStream);
		/// Save the current animation to a datastream.
		void StreamOutAnimatedMesh(std::ostream& outStream);
	};
	
	/// Utility function used for mesh deformation/animation.
	/// Interpolates from meshA to meshB by interp value into
	/// meshOut. It is assumed that meshA and B are of the same
	/// data-topology.
	void Interp(Cooney::Mesh &meshA, Cooney::Mesh &meshB, float interp, Cooney::Mesh &meshOut);
};

#endif