/*=========================================================================
* Clock.c : This module contain all engine clock's functions
* This is a part of the Game project.
*
* Version              1.0
* Creation date        31/10/96
* Revision date
*
* That file needs to be compatible for all platforms.
*
* (c) Ubi Studios 1996
*=======================================================================*/
//#define DEMO
 
#include "ToolsCPA.h"
 
#include "Options/Options.h"
#include "Macros.h"
 
#include "Structur/EngMode.h"
 
#include "Clock.h"
 
/*HP 051098*/
#ifdef U64
#include "INO.h"
#define	FORCE_FRAME_RATE
#define	FORCED_FRAME_DURATION	50L
#else
#include "PRF.h"
extern u_long fn_ulTimerTickPerSecond(short wTimerType);
extern unsigned long GLI_g_ulFrameLength;
extern unsigned long fn_ulTimerCpuClock (void);
#endif /* U64 */


/*************** FabPerez Cheat Code  *******/
#if defined (WIN32) && defined (_DEBUG)
#ifndef CHEAT_CODE_DELTA_TIME
	 #define	CHEAT_CODE_DELTA_TIME	1
#endif
#ifndef PRF_C_lMaxNbCheatCodeVariable
	 #define	PRF_C_lMaxNbCheatCodeVariable 3
#endif

	extern	BOOL	g_CheatCodeActivate;
	extern	unsigned long g_ulCurrentCheatCode;
	extern	BOOL a_lCheatCodeVariable[PRF_C_lMaxNbCheatCodeVariable];
	extern	void (*a_p_fnCheatCodeFonction[PRF_C_lMaxNbCheatCodeVariable])(BOOL);

	void	(*p_fn)(BOOL);
#endif //(WIN32) & (DEBUG)
/************ Fin FabPerez Cheat Code **********/


/*-----------------------------------------------------------------------------
 *  Description :   First Initialize the clock structure 
 *-----------------------------------------------------------------------------
 *  Input :         void
 *  Output :        void
 *-----------------------------------------------------------------------------
 *  Creation date : 31/10/96            Author : Francois
 *-----------------------------------------------------------------------------
 *  Modification date :                 Modification Author :
 *  Modifications :
 *---------------------------------------------------------------------------*/
void fn_vFirstInitEngineClock()
{
 /**** Initialize the timer library ****/
 fn_wTimerInitLibrary();
 /**** Initialize the game timer ****/
 
#ifdef U64
 g_stEngineStructure.stEngineTimer.sTimerHandle = fn_wTimerCreate(C_wTimerFrequencyLow);
#else 
 g_stEngineStructure.stEngineTimer.sTimerHandle = fn_wTimerCreate(C_wTimerFrequencyMedium);
 g_stEngineStructure.stEngineTimer.ulTickPerMS  = fn_ulTimerTickPerSecond(C_wTimerFrequencyMedium) / 1000; 
#endif
 }

/*-----------------------------------------------------------------------------
 *  Description :   Initialize frame length 
 *-----------------------------------------------------------------------------
 *  Input :         void
 *  Output :        void
 *-----------------------------------------------------------------------------
 *  Creation date : 02/03/99            Author : Jacques Thénoz
 *-----------------------------------------------------------------------------
 *  Modification date :                 Modification Author :
 *  Modifications :
 *---------------------------------------------------------------------------*/
void fn_vInitFrameLenght (void)
{
#ifdef U64

 if (osTvType == 0) /* PAL */
	g_stEngineStructure.stEngineTimer.xFrameLength = MTH_M_xDoubleToReal(1./50.);
 else /* NTSC OR MPAL */
	g_stEngineStructure.stEngineTimer.xFrameLength = MTH_M_xDoubleToReal(1./60.);

#else
/* g_stEngineStructure.stEngineTimer.xFrameLength = MTH_M_xDiv ( MTH_M_xDoubleToReal(GLI_g_ulFrameLength) , MTH_M_xDoubleToReal(fn_ulTimerCpuClock()) ); */
 g_stEngineStructure.stEngineTimer.xFrameLength = MTH_M_xDiv( MTH_M_xLongToReal( GLI_g_ulFrameLength ), MTH_M_xLongToReal( fn_ulTimerTickPerSecond( C_wTimerFrequencyMedium ) ) );
#endif
}



/*-----------------------------------------------------------------------------
 *  Description :   Last Desinitialize the clock structure 
 *-----------------------------------------------------------------------------
 *  Input :         void
 *  Output :        void
 *-----------------------------------------------------------------------------
 *  Creation date : 31/10/96            Author : Francois
 *-----------------------------------------------------------------------------
 *  Modification date :                 Modification Author :
 *  Modifications :
 *---------------------------------------------------------------------------*/
#ifndef _FIRE_DEADCODE_U64_
void fn_vLastDesinitEngineClock()
{
 /**** Initialize the game timer ****/
 fn_wTimerDestroy(g_stEngineStructure.stEngineTimer.sTimerHandle);
 /**** desinitialize the timer library ****/
 fn_wTimerExitLibrary();
}
#endif /* _FIRE_DEADCODE_U64_ */
 
/*-----------------------------------------------------------------------------
 *  Description :   Initialize the clock structure (When game start)
 *-----------------------------------------------------------------------------
 *  Input :         void
 *  Output :        void
 *-----------------------------------------------------------------------------
 *  Creation date : 31/10/96            Author : Francois
 *-----------------------------------------------------------------------------
 *  Modification date :                 Modification Author :
 *  Modifications :
 *---------------------------------------------------------------------------*/
void fn_vReinitEngineClock()
{
 /**** Initialize the game timer ****/
/* g_stEngineStructure.stEngineTimer.sTimerHandle = fn_wTimerCreate(C_wTimerFrequencyLow);*/
}
 
/*-----------------------------------------------------------------------------
 *  Description :   Desinitialize the clock structure (When game stop)
 *-----------------------------------------------------------------------------
 *  Input :         void
 *  Output :        void
 *-----------------------------------------------------------------------------
 *  Creation date : 31/10/96            Author : Francois
 *-----------------------------------------------------------------------------
 *  Modification date :                 Modification Author :
 *  Modifications :
 *---------------------------------------------------------------------------*/

#ifndef _FIRE_DEADCODE_U64_ /* Added by RUC 07/06/99 */
void fn_vRedesinitEngineClock()
{
 /**** Initialize the game timer ****/
/* fn_wTimerDestroy(g_stEngineStructure.stEngineTimer.sTimerHandle);*/
}
#endif /* _FIRE_DEADCODE_U64_ */ /* Added by RUC 07/06/99 */

 
/*-----------------------------------------------------------------------------
 *  Description :   determines the time 
 *                  of the current frame
 *-----------------------------------------------------------------------------
 *  Input :         void
 *  Output :        Time (in milliseconds)
 *-----------------------------------------------------------------------------
 *  Creation date : 21/04/97            Author : Frederic 
 *-----------------------------------------------------------------------------
 *  Modification date : 13/11/98        Modification Author : YLT
 *  Modifications : Change MaxMilliSecondsPerFrame to 133 (8 frames)  
  *---------------------------------------------------------------------------*/
#define C_MinMilliSecondsPerFrame (unsigned long)16
#define C_MaxMilliSecondsPerFrame (unsigned long)133
 
unsigned long fn_ulDetermineUsefulDT()
{
	unsigned long ulResult;
 
 
	ulResult = g_stEngineStructure.stEngineTimer.ulDeltaTimerCount;
 
	if(ulResult < C_MinMilliSecondsPerFrame)
		ulResult = C_MinMilliSecondsPerFrame;
	else if(ulResult > C_MaxMilliSecondsPerFrame)
		ulResult = C_MaxMilliSecondsPerFrame;
 
	return ulResult;
}
 
 
 
 
/*-----------------------------------------------------------------------------
 *  Description :   Start the clock structure (When level start)
 *-----------------------------------------------------------------------------
 *  Input :         void
 *  Output :        void
 *-----------------------------------------------------------------------------
 *  Creation date : 31/10/96            Author : Francois
 *-----------------------------------------------------------------------------
 *  Modification date :                 Modification Author :
 *  Modifications :
 *---------------------------------------------------------------------------*/
void fn_vStartEngineClock()
{
 unsigned long i;
 struct _stTimerCount stCurrentTimerCount;  /**** Current trame timer ****/
 
	
#ifdef U64
	int iDemoMode;
#endif	

 /**** Start the timer ****/
 fn_wTimerReset(g_stEngineStructure.stEngineTimer.sTimerHandle);
 fn_wTimerStart(g_stEngineStructure.stEngineTimer.sTimerHandle);
 fn_wTimerRead(g_stEngineStructure.stEngineTimer.sTimerHandle,&stCurrentTimerCount);
 
#ifdef U64
 fn_vSaveEngineClock();
 g_stEngineStructure.stEngineTimer.ulCurrentTimerCount = stCurrentTimerCount.m_ulLowPart;

 iDemoMode=INO_fn_iU64UseDemoClock();
 if(iDemoMode==INO_U64_BeginDemoPlayMode || iDemoMode==INO_U64_BeginDemoRecordMode)
 {
	g_stEngineStructure.stEngineTimer.ulUsefulDeltaTime=FORCED_FRAME_DURATION;
	g_stEngineStructure.stEngineTimer.ulCurrentTimerCount=0;
 }
 else
	g_stEngineStructure.stEngineTimer.ulUsefulDeltaTime = fn_ulDetermineUsefulDT();

#else 
 g_stEngineStructure.stEngineTimer.stRealTimeCount     = stCurrentTimerCount;
 g_stEngineStructure.stEngineTimer.ulCurrentTimerCount = stCurrentTimerCount.m_ulLowPart / g_stEngineStructure.stEngineTimer.ulTickPerMS;

 g_stEngineStructure.stEngineTimer.ulUsefulDeltaTime = fn_ulDetermineUsefulDT();
#endif
 
 /**** Trame counter ****/
 g_stEngineStructure.stEngineTimer.ulTrameNumber = 1;
 
 /**** Clear all clock ****/
 g_stEngineStructure.stEngineTimer.a_ulCounter[0] = 1;
 for (i=1;i<C_NumberOfCounter;i++)
  g_stEngineStructure.stEngineTimer.a_ulCounter[i] = 0;
}
 
/*-----------------------------------------------------------------------------
 *  Description :   Stop the clock structure (When level start)
 *-----------------------------------------------------------------------------
 *  Input :         void
 *  Output :        void
 *-----------------------------------------------------------------------------
 *  Creation date : 31/10/96            Author : Francois
 *-----------------------------------------------------------------------------
 *  Modification date :                 Modification Author :
 *  Modifications :
 *---------------------------------------------------------------------------*/
 
void fn_vStopEngineClock()
{
 /**** Stop the timer ****/
 fn_wTimerStop(g_stEngineStructure.stEngineTimer.sTimerHandle);
}
 
 
/*-----------------------------------------------------------------------------
 *  Description :   Actualize the clock structure (In game loop)
 *-----------------------------------------------------------------------------
 *  Input :         void
 *  Output :        void
 *-----------------------------------------------------------------------------
 *  Creation date : 31/10/96            Author : Francois
 *-----------------------------------------------------------------------------
 *  Modification date :                 Modification Author :
 *  Modifications :
 *---------------------------------------------------------------------------*/
void fn_vActualizeEngineClock()
{
	unsigned long i;
	struct _stTimerCount stCurrentTimerCount;  /**** Current trame timer ****/
	
#ifdef U64
	int iDemoMode;
#else
	unsigned long ulDeltaTime;	
#endif
	
	/**** Trame counter ****/
	g_stEngineStructure.stEngineTimer.ulTrameNumber++;
	
	
	/**** Time counter (in ms) ****/
#ifdef U64
#ifndef	FORCE_FRAME_RATE
	fn_wTimerRead(g_stEngineStructure.stEngineTimer.sTimerHandle,&stCurrentTimerCount);
#else	/* FORCE_FRAME_RATE*/
	
	iDemoMode=INO_fn_iU64UseDemoClock();
	
	if(iDemoMode==INO_U64_BeginDemoPlayMode || iDemoMode==INO_U64_BeginDemoRecordMode)
	{
		stCurrentTimerCount.m_ulLowPart=g_stEngineStructure.stEngineTimer.ulCurrentTimerCount + FORCED_FRAME_DURATION;
		g_stEngineStructure.stEngineTimer.ulDeltaTimerCount=FORCED_FRAME_DURATION;
	}
	else if(iDemoMode==INO_U64_DemoPlayMode) {
		g_stEngineStructure.stEngineTimer.ulDeltaTimerCount=
			INO_fn_ulGetDemoTimeDelta();
		stCurrentTimerCount.m_ulLowPart=g_stEngineStructure.stEngineTimer.ulCurrentTimerCount + g_stEngineStructure.stEngineTimer.ulDeltaTimerCount;
	}
	else
	{
		fn_wTimerRead(g_stEngineStructure.stEngineTimer.sTimerHandle,&stCurrentTimerCount);
		
		if (stCurrentTimerCount.m_ulLowPart<g_stEngineStructure.stEngineTimer.ulCurrentTimerCount)
			g_stEngineStructure.stEngineTimer.ulDeltaTimerCount = (unsigned long)(-(long)(stCurrentTimerCount.m_ulLowPart-g_stEngineStructure.stEngineTimer.ulCurrentTimerCount));
		else
			g_stEngineStructure.stEngineTimer.ulDeltaTimerCount = (stCurrentTimerCount.m_ulLowPart-g_stEngineStructure.stEngineTimer.ulCurrentTimerCount);
		
#ifdef DEMO
		if(iDemoMode==INO_U64_DemoRecordMode)
		{
			if(g_stEngineStructure.stEngineTimer.ulDeltaTimerCount>0xFFL)
			{
				ASM_BREAK;
				osSyncPrintf("frame duration doesn't fit on one char \n"); 
			}

			INO_fn_vSetDemoTimeDelta((long)g_stEngineStructure.stEngineTimer.ulDeltaTimerCount);
		}
#endif
		
	}
#endif	/* FORCE_FRAME_RATE*/
	
	g_stEngineStructure.stEngineTimer.ulCurrentTimerCount = stCurrentTimerCount.m_ulLowPart;
	
#else	/* U64*/
	


/*************** FabPerez Cheat Code *******/
#if defined (WIN32) && defined (_DEBUG)
	if(g_CheatCodeActivate)
	{
		p_fn = a_p_fnCheatCodeFonction[CHEAT_CODE_DELTA_TIME];
		(*p_fn)(a_lCheatCodeVariable[CHEAT_CODE_DELTA_TIME]);

		if(g_ulCurrentCheatCode == 0) g_CheatCodeActivate = FALSE;
	}
#endif //(WIN32) & (DEBUG)
/************ Fin FabPerez Cheat Code **********/
 

	
	fn_wTimerRead(g_stEngineStructure.stEngineTimer.sTimerHandle,&stCurrentTimerCount);
	
    if ( stCurrentTimerCount.m_ulHighPart == g_stEngineStructure.stEngineTimer.stRealTimeCount.m_ulHighPart )
	{
		ulDeltaTime = stCurrentTimerCount.m_ulLowPart - g_stEngineStructure.stEngineTimer.stRealTimeCount.m_ulLowPart;
	}
	else
	{
		if ( stCurrentTimerCount.m_ulLowPart >= g_stEngineStructure.stEngineTimer.stRealTimeCount.m_ulLowPart )
			ulDeltaTime = stCurrentTimerCount.m_ulLowPart - g_stEngineStructure.stEngineTimer.stRealTimeCount.m_ulLowPart;
		else
		{
			ulDeltaTime = stCurrentTimerCount.m_ulLowPart + (0xffffffff - g_stEngineStructure.stEngineTimer.stRealTimeCount.m_ulLowPart + 1);
		}
	}
	
	

	g_stEngineStructure.stEngineTimer.ulDeltaTimerCount = ulDeltaTime / g_stEngineStructure.stEngineTimer.ulTickPerMS;
	
	g_stEngineStructure.stEngineTimer.stRealTimeCount = stCurrentTimerCount;
	g_stEngineStructure.stEngineTimer.ulCurrentTimerCount += g_stEngineStructure.stEngineTimer.ulDeltaTimerCount;
	
#endif
	
/*	PRF_fn_vSetIndependantVariable (PRF_C_ulIdpDeltaTime , g_stEngineStructure.stEngineTimer.ulDeltaTimerCount);*/
	
	
	g_stEngineStructure.stEngineTimer.ulUsefulDeltaTime = fn_ulDetermineUsefulDT();

	/* FON_fn_vSetElapsedTime(g_stEngineStructure.stEngineTimer.ulUsefulDeltaTime);*/
	
	
	/**** All clock ****/
	for (i=2;i<C_NumberOfCounter;i++)
	{
		if (g_stEngineStructure.stEngineTimer.a_ulCounter[i]==i-1)
			g_stEngineStructure.stEngineTimer.a_ulCounter[i]=0;
		else
			g_stEngineStructure.stEngineTimer.a_ulCounter[i]++;
	}
}
 
/*-----------------------------------------------------------------------------*/
/* Description : Save the state of the Engine Clock*/
/*-----------------------------------------------------------------------------*/
/* Creation date : 03/09/98            Author : Carlos Torres*/
/*-----------------------------------------------------------------------------*/
void fn_vSaveEngineClock()
{
	struct _stTimerCount stCurrentTimerCount;
	
/* ANNECY MT - 27/01/99 {*/
#ifdef U64
	/* read timer and keep it*/
	fn_wTimerRead(g_stEngineStructure.stEngineTimer.sTimerHandle,&stCurrentTimerCount);
	//g_stEngineStructure.stEngineTimer.ulPauseTime = stCurrentTimerCount.m_ulLowPart;
	g_stEngineStructure.stEngineTimer.ulPauseTime = g_stEngineStructure.stEngineTimer.ulCurrentTimerCount;
	
#else
	
	unsigned long ulDeltaTime;	
	
	/* read timer and keep it*/
	fn_wTimerRead(g_stEngineStructure.stEngineTimer.sTimerHandle,&stCurrentTimerCount);
	
    if ( stCurrentTimerCount.m_ulHighPart == g_stEngineStructure.stEngineTimer.stRealTimeCount.m_ulHighPart )
	{
		ulDeltaTime = stCurrentTimerCount.m_ulLowPart - g_stEngineStructure.stEngineTimer.stRealTimeCount.m_ulLowPart;
	}
	else
	{
		if ( stCurrentTimerCount.m_ulLowPart >= g_stEngineStructure.stEngineTimer.stRealTimeCount.m_ulLowPart )
			ulDeltaTime = stCurrentTimerCount.m_ulLowPart - g_stEngineStructure.stEngineTimer.stRealTimeCount.m_ulLowPart;
		else
		{
			ulDeltaTime = stCurrentTimerCount.m_ulLowPart + (0xffffffff - g_stEngineStructure.stEngineTimer.stRealTimeCount.m_ulLowPart + 1);
		}
	}
	g_stEngineStructure.stEngineTimer.stPauseTime = stCurrentTimerCount;
	g_stEngineStructure.stEngineTimer.ulPauseTime = g_stEngineStructure.stEngineTimer.ulCurrentTimerCount + (ulDeltaTime / g_stEngineStructure.stEngineTimer.ulTickPerMS);
	
#endif
/* END ANNECY MT }*/
}
 
/*-----------------------------------------------------------------------------*/
/* Description : reset the state of the Engine Clock previously saved*/
/*-----------------------------------------------------------------------------*/
/* Creation date : 03/09/98            Author : Carlos Torres*/
/*-----------------------------------------------------------------------------*/
void fn_vLoadEngineClock()
{
/* ANNECY MT - 27/01/99 {*/
#ifdef U64
	
	struct _stTimerCount stCurrentTimerCount;
	
	stCurrentTimerCount.m_ulHighPart = 0;
	
	/* Reset timer with saved value, Engine ca ncontinue running so init ulCurrentTimerCount too*/
	g_stEngineStructure.stEngineTimer.ulCurrentTimerCount = 
		stCurrentTimerCount.m_ulLowPart = 
		g_stEngineStructure.stEngineTimer.ulPauseTime;
 
	TMR_fn_wSetTimerValue(g_stEngineStructure.stEngineTimer.sTimerHandle, &stCurrentTimerCount);
 
#else
	
	g_stEngineStructure.stEngineTimer.stRealTimeCount 	  = g_stEngineStructure.stEngineTimer.stPauseTime;
    g_stEngineStructure.stEngineTimer.ulCurrentTimerCount = g_stEngineStructure.stEngineTimer.ulPauseTime;
	TMR_fn_wSetTimerValue(g_stEngineStructure.stEngineTimer.sTimerHandle, &g_stEngineStructure.stEngineTimer.stRealTimeCount);
    
#endif
/* END ANNECY MT }*/
 
	fn_wTimerStart(g_stEngineStructure.stEngineTimer.sTimerHandle);
}
