Focus on 3D game programming

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

DXUT-计时器(Timer)

仅供个人学习使用,请勿转载,勿用于任何商业用途。

由于本人水平所限,如有不当之处,希望指点一二。

作者: Darren Chen

  

这些日子把DXUT的核心代码都看了一遍,以下是DXUT库的计时器.

  

 这里有两个需要特别注意的函数QueryPerformanceFrequency 和 QueryPerformanceCounter,

前者是用来获取内部计时器的时钟频率(也就是每秒有多少个"滴答"),后者是用来获取计算机的"滴答"数,

两次QueryPerformanceCounter的调用,结果之差/每秒多少个滴答 = 经过了多少秒

(详细请查阅msdn)

以下是Timer代码:

 

1 //--------------------------------------------------------------------------------------
2 // Performs timer operations
3 // Use DXUTGetGlobalTimer() to get the global instance
4 //--------------------------------------------------------------------------------------
5 class CDXUTTimer
6 {
7  public:
8 CDXUTTimer();
9 void Reset(); // resets the timer
10   void Start(); // starts the timer
11   void Stop(); // stop (or pause) the timer
12   void Advance(); // advance the timer by 0.1 seconds
13   double GetAbsoluteTime(); // get the absolute system time
14   double GetTime(); // get the current time
15   float GetElapsedTime(); // get the time that elapsed between Get*ElapsedTime() calls
16   void GetTimeValues( double* pfTime, double* pfAbsoluteTime, float* pfElapsedTime ); // get all time values at once
17   bool IsStopped(); // returns true if timer stopped
18  
19  protected:
20 LARGE_INTEGER GetAdjustedCurrentTime();
21
22 bool m_bUsingQPF;
23 bool m_bTimerStopped;
24 LONGLONG m_llQPFTicksPerSec;
25
26 LONGLONG m_llStopTime;
27 LONGLONG m_llLastElapsedTime;
28 LONGLONG m_llBaseTime;
29 };
30
31 CDXUTTimer* WINAPI DXUTGetGlobalTimer();

以上是DXUTmisc.h对CDXUTTimer的定义,先看CDXUTTimer()


构造函数CDXUTTimer()将计时器初始化:

 

1 CDXUTTimer::CDXUTTimer()
2 {
3 m_bTimerStopped = true; // 当前计时器为停止状态
4 m_llQPFTicksPerSec = 0; // Query Performance Frequency ticks per second
5
6 m_llStopTime = 0; // 记录暂停计时器时的时间基数
7 m_llLastElapsedTime = 0;
8 m_llBaseTime = 0;    // 时间基数
9
10 // Use QueryPerformanceFrequency to get the frequency of the counter
11   LARGE_INTEGER qwTicksPerSec = { 0 };
12 QueryPerformanceFrequency( &qwTicksPerSec );
13 m_llQPFTicksPerSec = qwTicksPerSec.QuadPart; // 查询出每秒多少个ticks
14 }

 

1 //-----------------------------------------------------------------------------
2  // If stopped, returns time when stopped otherwise returns current time
3  //-----------------------------------------------------------------------------
4  LARGE_INTEGER CDXUTTimer::GetAdjustedCurrentTime()
5 {
6 LARGE_INTEGER qwTime;
7 if( m_llStopTime != 0 )
8 qwTime.QuadPart = m_llStopTime; // 如果当前计时器是暂停了的,那么只需要返回暂停时记录的时间
9 else
10 QueryPerformanceCounter( &qwTime ); // 查询当前的ticks数
11 return qwTime;
12 }

 

1 void CDXUTTimer::Reset()
2 {
3 LARGE_INTEGER qwTime = GetAdjustedCurrentTime(); // 获取当前的ticks数
4
5 m_llBaseTime = qwTime.QuadPart; // 把当前的ticks数记录在BaseTime中
6 m_llLastElapsedTime = qwTime.QuadPart;
7 m_llStopTime = 0;
8 m_bTimerStopped = FALSE;
9 }

 

1 void CDXUTTimer::Start()
2 {
3 // Get the current time
4   LARGE_INTEGER qwTime = { 0 };
5 QueryPerformanceCounter( &qwTime );
6
7 if( m_bTimerStopped ) // 如果之前时钟是处于暂停状态,那么要将流逝了的ticks"补"回去
8 m_llBaseTime += qwTime.QuadPart - m_llStopTime;
9 m_llStopTime = 0;
10 m_llLastElapsedTime = qwTime.QuadPart;
11 m_bTimerStopped = FALSE;
12 }

 

1 void CDXUTTimer::Stop()
2 {
3 if( !m_bTimerStopped )
4 {
5 LARGE_INTEGER qwTime = { 0 };
6 QueryPerformanceCounter( &qwTime );
7 m_llStopTime = qwTime.QuadPart; // 记录暂停时的ticks数
8 m_llLastElapsedTime = qwTime.QuadPart; // 最新的时间也记录为当前的ticks数
9 m_bTimerStopped = TRUE; // 设置时钟为暂停
10 }
11 }

 

公式: 时间(多少秒) = 当前滴答数 / 每秒多少滴答

1 double CDXUTTimer::GetAbsoluteTime()
2 {
3 LARGE_INTEGER qwTime = { 0 };
4 QueryPerformanceCounter( &qwTime );
5
6 double fTime = qwTime.QuadPart / ( double )m_llQPFTicksPerSec;
7
8 return fTime;
9 }

 

1 double CDXUTTimer::GetTime()
2 {
3 LARGE_INTEGER qwTime = GetAdjustedCurrentTime();
4
5 double fAppTime = ( double )( qwTime.QuadPart - m_llBaseTime ) / ( double )m_llQPFTicksPerSec;
6
7 return fAppTime;
8 }

 

1 void CDXUTTimer::GetTimeValues( double* pfTime, double* pfAbsoluteTime, float* pfElapsedTime )
2 {
3 assert( pfTime && pfAbsoluteTime && pfElapsedTime ); // 输出
4
5 LARGE_INTEGER qwTime = GetAdjustedCurrentTime(); // 获得当前ticks数
6 // 经过的时间(多少秒) = ( 当前ticks数 - 上帧记录的ticks数 ) / 每秒的ticks数
7 float fElapsedTime = ( float )( ( double )( qwTime.QuadPart - m_llLastElapsedTime ) / ( double )
8 m_llQPFTicksPerSec );
9 m_llLastElapsedTime = qwTime.QuadPart; // 记录当前帧的ticks数,下一帧调用的时候用
10
11 // Clamp the timer to non-negative values to ensure the timer is accurate.
12 // fElapsedTime can be outside this range if processor goes into a
13 // power save mode or we somehow get shuffled to another processor.
14 // However, the main thread should call SetThreadAffinityMask to ensure that
15 // we don't get shuffled to another processor. Other worker threads should NOT call
16 // SetThreadAffinityMask, but use a shared copy of the timer data gathered from
17 // the main thread.
18   if( fElapsedTime < 0.0f )
19 fElapsedTime = 0.0f;
20
21 *pfAbsoluteTime = qwTime.QuadPart / ( double )m_llQPFTicksPerSec; // 绝对时间
22 *pfTime = ( qwTime.QuadPart - m_llBaseTime ) / ( double )m_llQPFTicksPerSec;
23 *pfElapsedTime = fElapsedTime;
24 }

 

贴了那么多代码,很乱的感觉,但是不贴代码,感觉又说不清楚, 耐心看看代码其实还是很简单的。

总结一下:DXUT库的这个计时器最主要的函数就是GetTimeValues,每帧都会调用这个函数,

传入三个参数分别用来获取pfAbsoluteTime "绝对时间",pfTime "程序运行时间", pfElapsedTime "前一帧到这一帧经过的时间"

 

通常游戏都需要显示每秒能运行多少帧(FPS), 公式: FPS = 1 / ElapsedTime.

 

posted on 2011-01-17 15:21  Darren Chen  阅读(269)  评论(0)    收藏  举报