//////////////////////////////////////////////////////////////////////////////
/// \file CooneyFat.h
///
/// Declares:
/// FatPointInfo
/// Fat
///
/// Stephen Timothy Cooney, 2009
//////////////////////////////////////////////////////////////////////////////
#ifndef COONEYFAT_H
#define COONEYFAT_H

#include "CooneyMath.h"
#include "CooneyMesh.h"
#include "CooneySoftBody.h"

#include <vector>

// Epsilon value represents an epsilon that
// can be predictably relied upon in the fat
// system. This can be overwritten when
// constructing the Fat object.
#define COONEY_FAT_EPSILON 0.001f

namespace Cooney
{
	/// Describes the connection between the fat system and the soft-body.
	/// Each point represents a point on the source mesh and soft-body mesh.
	struct FatPointInfo
	{
		/// If locked, the point exists in the soft-body system, and uses
		/// the animated/source-mesh for locality. It does not 'spring' but
		/// participates in influencing the simulated points.
		bool bLocked;
		
		// Index link betweeen this fat point and a point in the soft-body mesh.
		unsigned int fatLink;

		// Index link between this fat point and a point on the actual mesh.
		// Two of these for every mesh-point with fat (locked and unlocked).
		unsigned int meshLink;
		
		FatPointInfo()
		{
			bLocked = false;
			meshLink = 0;
		}
	};
	
	/// Desribes a fat simulation system that works by connecting a soft-
	/// body mesh to an animated or static mesh. It first generates the
	/// fat layer by comparing differences in a topologically identical
	/// thin and fat mesh. Then, it constructs a soft-body mesh between
	/// the gaps and runs a simulation on it. The original points are
	/// locked and drive the motion of the points on the exterior fat layer.
	class Fat
	{
		/// The SoftBody that acts as the fat layer.
		/// Simulation is run on this object.
		Cooney::SoftBody fat;

		/// Connects the source-static/animating mesh to the
		/// soft-body fat system.
		std::vector<FatPointInfo> fatinfo;

		/// The shortest distance when comparing a thin and
		/// fat mesh's verts that are considered candidates
		/// for fat tissue.
		float epsilon;
		
	public:
		
		/// Generates the layer of fat by comparing a thin mesh and a high mesh
		/// both meshes are assumed to be organized in the EXACT same way.
		/// Returns true on success, false on failure.
		bool BakeFat(Cooney::Mesh& thinMesh, Cooney::Mesh& fatMesh, float epsilon = COONEY_FAT_EPSILON,
					float stiffness=15.0f, float damping=10.0f, float cornerStiffness=0.0f, float cornerDamping=0.0f);
		
		/// Takes the inMesh and replaces 'thin' muscle tissue verts with
		/// the fat muscle tissue verts. Both Meshes should be topolically
		/// the exact same.
		void OverlayFat(Cooney::Mesh& outMesh);
		
		/// Iterates the layer of fat through time in reference
		/// to the thin in-mesh.
		void UpdateFat(float timeStep, Cooney::Mesh& inMesh);

		/// Pushes the contained fat object onto OpenGL for rendering.
		void PushGL();
		
	protected:
		
		/// Add's a new fat point info while checking for duplicates.
		/// Returns true on success, false on failure.
		bool AddUniqueFatPointInfo(FatPointInfo &possibleFatPoint);
	};
};

#endif