/*************************************************************************/
/*	File : CKTimemanager.h												 */
/*	Author :  Romain Sididris											 */	
/*																		 */	
/*	A Manager to provide the same acces to time to behaviors			 */	
/*	The time as seen by behaviors can be the real time or clamped		 */
/*	and stretched to slow or accelerate	"real" time						 */	
/*																		 */	
/*	Virtools SDK 														 */	 
/*	Copyright (c) Virtools 2000, All Rights Reserved.					 */	
/*************************************************************************/
#ifndef CKTIMEMANAGER_H

#define CKTIMEMANAGER_H "$Id:$"

#include "CKDefines.h"
#include "CKBaseManager.h"


#if _MSC_VER > 1000
	#pragma warning(disable:4786)
#endif

/*******************************************************
{filename:CK_FRAMERATE_LIMITS}
Summary:Time limits settings

Remarks:
+ The default settings for the process loop is to 
execute one behavioral process then one rendering (with 
a synchonization to screen refresh rate). 
+ Behavioral process and Rendering can have a maximum frame rate 
in which case it is guaranteed the rendering and behavioral loop
will not be called more than the given fps time per second. The asked frame rate
may not be achieved but it will not be exceed.
See also:CKTimeManager
********************************************************/
typedef enum CK_FRAMERATE_LIMITS
{
	CK_RATE_NOP			= 0x00000000,	
	CK_BEHRATE_SYNC		= 0x00000001,	// Behavioral Rate is synchronized to frame rate
	CK_BEHRATE_LIMIT	= 0x00000004,	// Behavioral Rate is limited to a maximum value (see CKTimeManager::SetBehavioralRateLimit)
	CK_BEHRATE_MASK		= 0x0000000F,	// Mask for values concerning behavioral rate

	CK_FRAMERATE_SYNC	= 0x00000010,	// Frame Rate is synchronized to screen refresh rate (Render function will wait for vertical blank signal)
	CK_FRAMERATE_FREE	= 0x00000020,	// Frame Rate is free. Rendering occurs at the maximum possible rate.
	CK_FRAMERATE_LIMIT	= 0x00000040,	// Frame Rate is limited to a maximum value (see CKTimeManager::SetFrameRateLimit)
	CK_FRAMERATE_MASK	= 0x000000F0,	// Mask for values concerning frame rate
} CK_FRAMERATE_LIMITS;



/**************************************************************************
Name: CKTimeManager

Summary: Story and execution time management


Remarks:

+ The Time manager stores and updates time for the story but also real time.

+ Each frame the time manager computes the time elapsed since last process loop. This time
is then multiplied by the scale factor and clamped to a minimum 
and maximum value to avoid extreme values which could produces jump in the playback if its time dependant. 
This delta value is added to the current time to compute the absolute time elapsed since
the playback started. 

+ The time as it appears to behaviors can be multiplied by a scale 
factor and also be clamped to minimum and maximum values. 

+ The CKContext::Pause,Reset,Play automatically call
the appropriate functions in CKTimeManager to pause and restart the timers.

+ Since the time taken to render a scene and execute the scripts can greatly vary
from one frame to another, it is recommended to perform time dependant actions rather
the frame dependant. 

+ The unique instance of the time manager can be retrieved through the  CKContext::GetTimeManager method

See also: Time Management,Creating a Standalone Application,CKContext::GetTimeManager
*****************************************************************************/
class CKTimeManager:public CKBaseManager {
public :
//*********** Processing **********************

/**************************************************
Summary: Returns the number of process loop (call to CKContext::Process()) since startup.

See also: GetTime,GetAbsoluteTime,GetLastDeltaTime,SetLastDeltaTime
***************************************************/
CKDWORD GetMainTickCount() { return m_MainTickCount; }

/**************************************************
Summary: Returns time elapsed since startup in milliseconds.

Remarks:
+ Use a high-precision timer to return the time elapsed since creation of this context.
+ The returned time does NOT take scale factors,minimum and maximum values into account.
+ The behaviors should not use this function but rather GetAbsoluteTime which takes scale factor into account.
Use only this function to be relative to the "real" time.
See also: GetAbsoluteTime,GetLastDeltaTime,SetLastDeltaTime
*****************************************************/
float GetTime() { return m_StartupChrono.Current(); }

/*******************************************************
Summary: Returns time elapsed since last frame in milliseconds.

Remarks:
	+ The returned time takes scale factors,minimum and maximum values into account.
See also: GetTime,GetLastDeltaTime,SetMinimumDeltaTime,SetMaximumDeltaTime,SetTimeScaleFactor
*********************************************************/
float GetLastDeltaTime() { return m_DeltaTime; }

/*******************************************************
Summary: Returns real time elapsed since last frame in milliseconds.

Remarks:
+ The returned time does NOT takes scale factors,minimum and maximum values into account.
+ The behaviors should not use this function but rather GetLastDeltaTime which takes scale factor into account.
Use only this function to be relative to the "real" time. For example if between two frames an action takes
a very long time, the GetLastDeltaTime() method will return the maximum allowed delta time (GetMaximumDeltaTime)
while this method will return the exact time elapsed.
See also: GetTime,GetLastDeltaTime,SetLastDeltaTime,SetMinimumDeltaTime,SetMaximumDeltaTime,SetTimeScaleFactor
*********************************************************/
float GetLastDeltaTimeFree() { return m_DeltaTimeFree; }
	
/*********************************************************
Summary: Returns time elapsed since last call to CKContext::Reset() in milliseconds.

Remarks:
	+ The returned time takes scale factors,minimum and maximum values into account.
See also: GetTime,GetLastDeltaTime,SetLastDeltaTime,SetMinimumDeltaTime,SetMaximumDeltaTime,SetTimeScaleFactor
**********************************************************/
float GetAbsoluteTime() { return m_PlayTime; }

//*********** Time scale factors **********************

/*********************************************************
Summary: Sets the time scaling factor.

Arguments:
	mulfactor: A scale factor by which real time value will be multiplied.
Remarks:
	+ All time dependant operations in behaviors use the time manager methods, 
	with a scale factor you can simulate a slower of faster time flow. 
See also: GetTime,GetLastDeltaTime,SetLastDeltaTime,SetMinimumDeltaTime,SetMaximumDeltaTime,GetTimeScaleFactor
*********************************************************/
void SetTimeScaleFactor(float mulfactor) { m_TimeScaleFactor=mulfactor; }
/*********************************************************
Summary: Gets the time scaling factor.

Return Value:	Current scale factor by which real time value is multiplied.
Remarks:
	+ All time dependant operations in behaviors use the time manager methods, 
	with a scale factor you can simulate a slower of faster time flow. 
See also: GetTime,GetLastDeltaTime,SetLastDeltaTime,SetMinimumDeltaTime,SetMaximumDeltaTime,SetTimeScaleFactor
*********************************************************/
	float GetTimeScaleFactor() { return m_TimeScaleFactor; }

//------------ Limits --------------------

/****************************************************
Summary: Gets the rendering and behavioral frame rate limits.

Remarks:
	+ Returns a combination of CK_FRAMERATE_LIMITS flags 
	specifying the behavioral and frame rate limits.
See Also:CK_FRAMERATE_LIMITS,ChangeLimitOptions
*****************************************************/
	CKDWORD GetLimitOptions() { return m_LimitOptions; }
/****************************************************
Summary: Gets the frame rate limit

Return Value:
	Maximum render loops per second.
Remarks:
	+ This value is only used when the frame rate is limited (GetLimitOptions() & CK_FRAMERATE_LIMIT)
See Also:SetFrameRateLimit,GetLimitOptions,ChangeLimitOptions
*****************************************************/
	float GetFrameRateLimit()		{ return m_LimitFrameRate; }
/****************************************************
Summary: Gets the behavioral rate limit

Return Value:
	Maximum process loops per second.
Remarks:
	+ This value is only used when the behavioral rate is limited (GetLimitOptions() & CK_BEHRATE_LIMIT)
See Also:SetBehavioralRateLimit,GetLimitOptions,ChangeLimitOptions
*****************************************************/
	float GetBehavioralRateLimit()	{ return m_LimitBehRate; }
/****************************************************
Summary: Gets the minimum delta time.

Remarks:
+ Each frame the time manager computes the time elapsed since last process loop. This time
is then multiplied by the scale factor. This time are also be clamped to a minimum 
and maximum value to avoid extreme values. 
+ Default minimum delta time = 1 millisecond.
See Also:SetMinimumDeltaTime,GetMaximumDeltaTime
*****************************************************/
	float GetMinimumDeltaTime()		{ return m_MinimumDeltaTime; }
/****************************************************
Summary: Gets the maximum delta time.

Remarks:
+ Each frame the time manager computes the time elapsed since last process loop. This time
is then multiplied by the scale factor. This time are also be clamped to a minimum 
and maximum value to avoid extreme values. 
+ Default maximum delta time = 200 millisecond.
See Also:GetMinimumDeltaTime,SetMaximumDeltaTime
*****************************************************/
	float GetMaximumDeltaTime()		{ return m_MaximumDeltaTime; }
/****************************************************
Summary: Changes the rendering and behavioral frame rate limits.

Arguments:
	FpsOptions:  CK_FRAMERATE_SYNC to synchronize to screen refresh rate (Render 
	function will wait for vertical blank signal),CK_FRAMERATE_FREE to render
	at the maximum possible rate or CK_FRAMERATE_LIMIT to set a maximum frame rate.
	BehOptions: CK_BEHRATE_SYNC to synchronise the process loop with rendering (a behavioral processing is done
	before each rendering) or CK_BEHRATE_LIMIT to set a maximum behavioral rate.
Remarks:
	+ If the frame or behavioral rate is limited, the limits can be set by the 
	SetFrameRateLimit or SetBehavioralRateLimit methods.
See Also:CK_FRAMERATE_LIMITS,SetBehavioralRateLimit,SetFrameRateLimit,GetLimitOptions
*****************************************************/
	void	ChangeLimitOptions(CK_FRAMERATE_LIMITS FpsOptions,CK_FRAMERATE_LIMITS BehOptions=CK_RATE_NOP);
/****************************************************
Summary: Sets the frame rate limit

Arguments:
	FRLimit: Maximum render loops per second.
Remarks:
	+ This value is only used when the frame rate is limited (GetLimitOptions() & CK_FRAMERATE_LIMIT)
See Also:GetFrameRateLimit,GetLimitOptions,ChangeLimitOptions
*****************************************************/
	void SetFrameRateLimit(float FRLimit);
/****************************************************
Summary: Sets the behavioral rate limit

Arguments:
	BRLimit: Maximum process loops per second.
Remarks:
	+ This value is only used when the behavioral rate is limited (GetLimitOptions() & CK_BEHRATE_LIMIT)
See Also:GetBehavioralRateLimit,GetLimitOptions,ChangeLimitOptions
*****************************************************/
	void SetBehavioralRateLimit(float BRLimit);
/****************************************************
Summary: Sets the minimum delta time.

Arguments:
	DtMax: Minimum value for the delta time in milliseconds.
Remarks:
+ Each frame the time manager computes the time elapsed since last process loop. This time
is then multiplied by the scale factor. This time are also be clamped to a minimum 
and maximum value to avoid extreme values. 
+ Default minimum delta time = 1 millisecond.
See Also:SetMaximumDeltaTime,GetMinimumDeltaTime
*****************************************************/
	void SetMinimumDeltaTime(float DtMin);
/****************************************************
Summary: Sets the maximum delta time.

Arguments:
	DtMax: Maximum value for the delta time in milliseconds.
Remarks:
+ Each frame the time manager computes the time elapsed since last process loop. This time
is then multiplied by the scale factor. This time are also be clamped to a minimum 
and maximum value to avoid extreme values. 
+ Default maximum delta time = 200 millisecond.
See Also:SetMinimumDeltaTime,GetMaximumDeltaTime
*****************************************************/
	void SetMaximumDeltaTime(float DtMax);


/*******************************************************
Summary: Set the DeltaTime for custom use.

Remarks:
	+This is usefull for special purposes.
See also: GetTime,GetLastDeltaTime,SetLastDeltaTime,SetMinimumDeltaTime,SetMaximumDeltaTime,SetTimeScaleFactor
*********************************************************/
	void SetLastDeltaTime(float DtSet) { m_DeltaTime = DtSet; }

//----------------------------------------------------
//--  Runtime 

/***************************************************************
Summary: Returns the time to wait to respect the time manager limits. 

Arguments:
	TimeBeforeRender: Time in milliseconds to wait before performing 
	a rendering.
	TimeBeforeBeh: Time in milliseconds to wait before performing 
	a process loop.
Remarks:
+ This method returns the time to wait in milliseconds 
to perfom a rendering or a process loop so that the 
time manager limits are respected.
+ If the rendering or the behavioral process are not limited to given frame rate the 
method returns 0 values.
Example
	// This is a standard loop that takes potential frame rate limitats
	// into account

	CKTimeManager* TheTimeManager = TheContext->GetTimeManager();
	while(1) {
			float TimeBeforeRender=0,TimeBeforeBeh=0;

			// Ask the time manager the time to wait before 
			// doing a render and a process
			// if the time is positive we keep on looping
			// without doing anything
			TheTimeManager->GetTimeToWaitForLimits(TimeBeforeRender,TimeBeforeBeh);

			BOOL DoBehaviors	= (TimeBeforeBeh <=0);
			BOOL DoRender		= (TimeBeforeRender  <=0);

			// If a rendering or a behavioral process is done
			// we restart the chronos for the next iteration
			TheTimeManager->ResetChronos(DoRender,DoBehaviors);

			if (DoBehaviors)	TheCKContext->Process();
			if (DoRender) 		TheRenderContext->Render();
	}
See Also:Creating a Standalone Application
*****************************************************/
	void	GetTimeToWaitForLimits(float& TimeBeforeRender,float& TimeBeforeBeh);

	void	ResetChronos(CKBOOL RenderChrono,CKBOOL BehavioralChrono);

//-------------------------------------------------------------------------
// Internal functions 
#ifdef DOCJETDUMMY // DOCJET secret macro
#else

	virtual CKERROR PreProcess();	
	virtual CKERROR OnCKPlay();		
	virtual CKERROR OnCKPause();	
	virtual CKERROR OnCKReset();	
	virtual CKERROR PostClearAll();	
	virtual CKBOOL IsPaused();		
	virtual CKERROR LoadData(CKStateChunk *chunk,CKFile* LoadedFile);	
	virtual CKStateChunk* SaveData(CKFile *SavedFile);					
	
	virtual CKDWORD	GetValidFunctionsMask()	{ return CKMANAGER_FUNC_OnCKPause|
																 CKMANAGER_FUNC_OnCKPlay|
																 CKMANAGER_FUNC_OnCKReset|
																 CKMANAGER_FUNC_PostClearAll|
																 CKMANAGER_FUNC_PreProcess; }
	
	virtual int	GetFunctionPriority(CKMANAGER_FUNCTIONS Function)	{ if (Function!=CKMANAGER_FUNC_PreProcess) 
																			return DEFAULT_MANAGERFUNC_PRIORITY;
																	  else	return MAX_MANAGERFUNC_PRIORITY; }	
	
	CKTimeManager(CKContext *Context);

protected :
	CKDWORD m_MainTickCount;
	float m_LastTime,m_CurrentTime;
	float m_PlayTime,m_DeltaTime;

//----------- Limits 
	float m_LimitFrameRate;
	float m_LimitBehRate;
	float m_MaximumDeltaTime;
	float m_MinimumDeltaTime;
	CKDWORD m_LimitOptions;

//--- Calculated from FPS Limitations	
	float m_LimitFPSDeltaTime;
	float m_LimitBehDeltaTime;

	CKBOOL 	m_Paused;
	float	m_TimeScaleFactor;

#ifdef PSP 
	VxTimeProfilerPSP	m_BehChrono;
	VxTimeProfilerPSP	m_FpsChrono;
	VxTimeProfilerPSP	m_StartupChrono;
#else
	VxTimeProfiler	m_BehChrono;
	VxTimeProfiler	m_FpsChrono;
	VxTimeProfiler	m_StartupChrono;
#endif
	float m_DeltaTimeFree;
#endif // Docjet secret macro
};

#endif

