Gry i inne podobne aplikacje wymagają precyzyjnego pomiaru czasu, aby realizować obliczenia związane z fizyką, animacją, itp. Jak niemal wszystko, API potrzebne do tego celu jest różne w zależności od platformy, czyli (głównie) systemu operacyjnego. Dzisiaj chciałbym pokazać, jak wygląda to na dwóch najpopularniejszych systemach: Windows i POSIX (a więc między innymi na wszelkiego typu Linuksach).
Interfejs programistyczny systemu spod znaku okienek udostępnia dwie funkcje od dokładnego mierzenia czasu. Są to
QueryPerformanceFrequency
i QueryPerformanceCounter
. Tę pierwszą wywołuje się tylko raz, a jej wynikiem jest częstotliwość wewnętrznego systemowego zegara, który służy do precyzyjnego pomiaru upływającego czasu. Wyrażana jest ona w liczbie “tyknięć” na sekundę i na dzisiejszym sprzęcie może być bardzo duża, bo liczona w (kilku(nastu/dziesięciu)) milionach.
Druga funkcja jest używana nieporównywalnie częściej, gdyż to ona zwraca aktualną wartość zegara, czyli liczbę jego “tyknięć”. Stąd wynika, że obliczenie tej wartości w sekundach wymaga podzielenia rezultatu QPC
przez uzyskaną wcześniej częstotliwość:
Używana tu unia LARGE_INTERGER
to nic innego, jak zwykła liczba 64-bitowa.
W systemach POSIX-owych rzecz jest odrobinę prostsza, jako że tutaj dokładność zegara jest ściśle ustalona. Funkcja gettimeofday
(z nagłówka sys/time.h) zwraca rezultat z precyzją mikrosekundową w postaci struktury timeval
:
Część odpowiadającą niepełnym sekundom (pole tv_usec
) trzeba więc podzielić przez milion.
Chcąc mieć bardziej uniwersalne rozwiązanie, możemy napisać klasę opakowującą zegar z implementacją kontrolowaną docelową platformą, na którą kompilujemy:
Można by na koniec zapytać jeszcze, co tak naprawdę znaczy zwracana wartość zegara. Kiedy wynosi ona zero?… Otóż wbrew pozorom odpowiedź na to pytanie nie jest istotna, bo w praktyce interesuje nas tylko interwał czasowy, tj. różnica między dwoma wskazaniami timera. To na jej podstawie liczymy zmianę w prędkościach obiektów, klatkach animacji czy w końcu niezbędnie konieczną do wyświetlenia wartość FPS :)