CCore 클래스의 싱글톤 객체의 멤버 함수 progress에는
프로그램이 동작하는 동안 계속 실행될 코드가 있습니다.
이때 CTimeMgr 클래스의 싱글톤 객체가 생성되며
update 함수를 호출하죠.
CTimeMgr 클래스에는 각종 멤버 변수와
멤버 함수가 존재합니다.
CTimeMgr 클래스의 멤버 함수 update는
progress 함수가 호출될 때마다, 즉 매 프레임마다
호출이 되는 것이죠.
CTimeMgr 클래스의 update 함수는 30번째 줄에서
QueryPerformanceCounter 함수를 호출합니다.
이를 통해 update 함수가 호출되는 순간의
시점을 m_liCurCount에 저장하죠.
그리고 현재 시점이 저장된 m_liCurCount와
이전 시점이 저장된 m_liPrevCount의 값을 뺀 값을
m_liFrequency로 나누어 줍니다.
예를 들어 현재 시점이 1000이고 이전 시점이 800일 때,
이 둘을 빼면 1000 - 800 = 200이 되고 이것을 10,000,000으로
나누는 것이죠. 그럼 0.00002입니다.
이 값이 의미하는 것은 1 프레임이
실행되는 시간이 0.00002초임을 의미합니다.
풀어서 설명해 보면 update 함수가 호출되었다는 것은
1 프레임이 흘렀다는 의미입니다.
만약 update 함수가 호출된 순간이 2 프레임인 시점이라고 하였을 때
과거 시점은 1 프레임 시점이겠죠?
2 프레임 시점과 1 프레임 시점을 빼면 2 프레임과 1 프레임 사이의 시간 값,
즉 1 프레임이 지나는 동안의 시점을 얻을 수 있는 것이죠.
QueryPerformance 함수는 1초에 10,000,000을 셀 수 있기 때문에
10,000,000이라는 값은 곧 1초를 의미합니다.
1 프레임이 지나는 동안의 시점을 10,000,000으로 나눔으로써
"해당 시점을 초로 환산하였을 때 몇 초인가?" 를 알 수 있죠.
그리고 이렇게 얻은 값을
double형 멤버 변수 m_dDT에 대입합니다.
35번째 줄에서 m_iCallCount 값을 하나 올려 줍니다.
멤버 m_iCallCount는 초당 프레임 횟수를 저장합니다.
예를 들어 1초가 지난 시점에
m_iCallCount의 값을 확인해 보니 300입니다.
update 함수는 매 프레임마다 호출되는데 이때마다 m_iCallCount 의
값이 증가했던 것이므로 1초가 지나는 동안 update 함수가 300번 호출되었다는 의미이죠?
1초당 300 프레임이 지났음을 알 수 있는 것입니다.
37번째 줄에서 m_dAccDT와 m_dDT의 값을 더해
m_dAccDT에 대입하고 있습니다.
멤버 m_dAccDT는 누적 시간을 나타내는 멤버입니다.
1 프레임이 흐른 시간을 계속해서 누적하는 것이죠.
39번째 줄에서는 이전 시점을
현재 시점으로 교체해 주고 있는 모습입니다.
그래야지 다음 프레임에 update 함수가 호출될 때
제대로된 Delta Time을 계산하여 m_dDT에 대입할 수 있겠죠.
41번째 줄에서 m_dAccDT의 값이 1보다 크거나 같을 때,
즉 첫 update 함수가 호출되고 1초 이상이 지났을 때
FPS( frames per second )를 저장하는 멤버
m_iFPS에 m_iCallCount의 값을 저장하고
누적 시간을 나타내는 m_dAccDT와
update 함수의 호출 횟수를 나타내는 m_iCallCount에
0을 대입합니다.
48번째 줄에서 swprintf_s 함수를 통해
wchar_t형 변수 szBuffer에 문자열 "FPS : %d DT : %f"를
저장합니다. 이때 %d는 m_iFPS의 값이,
%f는 m_dDT의 값으로 대체됩니다.
49번째 줄에서 SetWindowText 함수를 통해
윈도우 타이틀에 szBuffer에 저장된 문자열을 출력할 것인데
SetWindowText 함수는 윈도우 핸들을 첫 번째 인자로 받습니다.
그래서 CCore 클래스의 헤더 파일에서 볼 수 있듯이
15번째 줄에 코어 객체가 갖고 있는 메인 윈도우 핸들을
반환하는 GetMainHwnd 함수를 추가하였습니다.
GetMainHwnd 함수를 SetWindowText 함수의 첫 번째 인자로
하여 윈도우 핸들을 넘기고 두 번째 인자로 문자열을 넘깁니다.
그럼 프로그램이 실행되면서 progress 함수가 호출되고
44번째 줄에 있는 CTimeMgr 클래스로 생성된 타임 매니저 객체의
멤버 함수 update가 호출되면서 Delta Time이 저장될 겁니다.
이후 46번째 줄에 있는 CCore 클래스로 생성된 코어 객체의
멤버 함수 update가 호출되면서 키 입력을 받겠죠.
왼쪽 키 입력을 받으면 55번째 if 문에 걸리면서
사각형의 x 좌푯값이 수정되고 48번째 줄에 있는
render 함수를 통해 수정된 x 좌푯값이 반영된
위치에 사각형이 그려질 것입니다.
이때 57, 62번째 줄에서 100에 fDT를 곱한 것이 보입니다.
fDT는 매크로로 define.h 파일에 구현되어 있습니다.
내용을 보니 CTimeMgr 클래스의 멤버 함수
GetfDT 함수를 호출하는 구문으로 치환이 되겠네요.
GetfDT 함수는 Delta Time 값이 저장된
멤버 m_dDT를 반환하는 함수입니다.
100 * Delta Time한 값을 대입하는 것의 의미는
1초에 100 픽셀을 이동할 만큼의 값을 대입하라는 것이죠.
기존처럼 키 입력이 들어왔을 때 일정거리만큼 이동하게 하는 것이 아니라,
현재 컴퓨터가 초당 어느 정도 함수 호출을 반복하는지, 즉 Delta Time을
구하고 Delta Time과 작성자가 원하는 1초 동안의 이동 거릿값(여기서는 100)을
곱하면 "현재 컴퓨터 성능으로는 1초에 100 픽셀을 이동하려면
한 번 키 입력이 들어왔을 때 이만큼 이동해야 해"라는 의미가 되는 거죠.
이제 프로그램을 실행해 보면
키 입력 시, 적절하게 사각형이 움직이는 것을 확인할 수 있습니다.
또한 윈도우 타이틀 부분에 FPS와 DT의 값이 표시됩니다.
위 사진 기준, 해당 프로그램은 초당 35658 프레임을 보여주며
한 프레임이 실행될 때 걸리는 시간은 0.000022초임을 알 수 있습니다.
강의 출처 : https://www.youtube.com/watch?v=vI_W8mMniWU
'Win32 API > 기초' 카테고리의 다른 글
Win32 API 기초 : Key Manager (1) (0) | 2024.07.01 |
---|---|
Win32 API 기초 : Double Buffering (0) | 2024.06.30 |
Win32 API 기초 : Timer (1) (0) | 2024.06.27 |
Win32 API 기초 : Core 클래스 (2) (0) | 2024.06.26 |
Win32 API 기초 : Singleton (2) (0) | 2024.06.24 |