//////////////////////////////////////////////////////////////////////////////
/// \file FatApp.h
///
/// Contains the high-level implementation of how fat simulation is achieved.
/// Start out here when trying to understand.
///
/// Initialization done in InitiateGraphics().
/// Simulation executed in UpdateFixed().
/// Rendering primarily in DrawGeometry().
///
/// Stephen Timothy Cooney, 2009
//////////////////////////////////////////////////////////////////////////////
#ifndef PHATAPP_H
#define PHATAPP_H

#include "BaseApp.h"
#include "CooneyMesh.h"
#include "CooneyAnimatedMesh.h"
#include "CooneyFat.h"

// Our custom fat simulation application.
class FatApp : public BaseApp
{
	/// Spring physics with complex inputs are non-linear
	/// and too difficult to simulate with arbitrary time
	/// inputs. The physics step-size dictates a constant
	/// update speed so that our physics behaves in a
	/// predictable manner. This non-dynamism is somewhat
	/// mitigated by the fact that it's running in a constant
	/// fixed timer update.
	float physicsStepSize;

	/// Also known as 'bindpose', the normalPose
	/// represents the body with no fat in a standard
	/// pose.
	Cooney::Mesh normalPose;

	/// The fat poses represent a mesh that is the
	/// same in every way as the normalPose except
	/// that the fat poses represent the version of
	/// the character with extra 'weight.' The topology
	/// of these meshes MUST be the same.
	/// There are two versions since once is a lighter
	/// and one is a heavier. There only needs to be
	/// one of these though.
	Cooney::Mesh fatPose, fatPose2;

	/// Contains an animation that we apply the fat onto.
	Cooney::AnimatedMesh runningMan;

	/// Contains an alternate animation that we apply the fat onto.
	Cooney::AnimatedMesh runningMan2;

	/// Represents the final version of the mesh
	/// before fat is applied. In this instance,
	/// it could be a combination of runningMan
	/// and runningMan2.
	Cooney::Mesh combinedAnimation;

	/// The finalmesh represents the animated mesh combined with
	/// the result of the fat simulation. Ultimately, this mesh
	/// represents what is rendered.
	Cooney::Mesh finalMesh;
	
	/// The dynamics system runs in the fatSystem object.
	Cooney::Fat fatSystem;
	
	/// Which animation are we playing? (runningMan or runningMan2)
	bool runswitch;
	/// Interpolation value between run forward and run left. (runningMan and runningMan2)
	float runinterp;

	/// Used for interpolating from the bind pose to the initial
	/// animation. This keeps the dynamics from blowing up.
	float initialInterp;
	
	/// Are we playing the animation at all?
	bool bPlay;
	
	/// Which fat simulation are we looking at?
	/// This could be the heavier(high) or lighter man.
	bool bHighFat;
	
	/// Render Modes.
	bool bOnlyFat; /// only show fat. No animating mesh.
	bool bRenderFat; /// show fat in the animation or just the animation without fat.
	bool bRenderFatLayer; /// show outlines dictating the dynamics springs.
	bool bXRayFatLayer; /// disable depth testing so you can see all of the dynamics springs.
	
	// Simple camera movement
	bool bClicked; // mouse button down?
	int lmx, lmy, mx, my; // mouse position data, next - last.
	int dx, dy; // mouse movement, delta(x)(y).
	float fRotationYaw, fRotationPitch; // current camera state.
	
public:
	FatApp(){}
	virtual ~FatApp(){};
	
	// Initialization
	virtual bool Initiate(unsigned int numArguments=0, char* arguments[]=0);
	virtual bool InitiateGraphics();
	
	// Runtime
	virtual void UpdateFixed(float timeStep);
	virtual void OnKeyboard(unsigned char key, int x, int y);
	virtual void OnMouse(int button, int state, int x, int y);
	virtual void OnMouseMotion(int x, int y);
	virtual void GetViewPoint(float &eyeX,float &eyeY,float &eyeZ,float &centerX,float &centerY,float &centerZ,float &upX,float &upY,float &upZ);
	virtual void GetShadowTarget(float &xOut, float &yOut, float &zOut){xOut=0.0f;yOut=0.0f;zOut=0.0f;} // pointed at the origin. Static for this app.
	virtual void DrawGeometry();
	virtual void PostRender();
	virtual void SetupPostProcess(){};
	virtual void CleanupPostProcess(){};
	virtual void PostGUIRender(){};
	
	// Checks/Gets
	virtual bool ShouldQuit(){return false;}
	virtual unsigned int GetNumHelpItems(){return 7;} // see GetHelpItem for actual items.
	virtual char* GetHelpItem(unsigned int itemIndex)
	{
		switch (itemIndex)
		{
			case 0:
				return (char*)"R - Reset";
				break;
			case 1:
				return (char*)"W - Change Animation";
				break;
			case 2:
				return (char*)"I - Toggle Level of Fat";
				break;
			case 3:
				return (char*)"O - Play/Freeze Animation";
				break;
			case 4:
				return (char*)"E - Toggle Fat";
				break;
			case 5:
				return (char*)"T - Toggle Debug";
				break;
			case 6:
				return (char*)"B - Toggle ONLY Fat";
				break;
			default:
				break;
		}
		return NULL;
	}
};

#endif