Вычисление FPS и подготовка поверхности осуществляются функцией UpdateFPSSurface(), вызываемой функцией DrawScene()при каждом обновлении экрана. Функция UpdateFPSSurface()выглядит так:
BOOL SwitchWin::UpdateFPSSurface() {
static const long interval=100;
framecount++;
if (framecount==interval) {
static DWORD timenow;
static DWORD timethen;
timethen=timenow;
timenow=timeGetTime();
double seconds=double(timenow-timethen)/(double)1000;
int fps=(int)((double)framecount/seconds);
static char buf[10];
int len=sprintf(buf, "%d FPS", fps);
ClearSurface(fpssurf, 0);
HDC hdc;
fpssurf->GetDC(&hdc);
SelectObject(hdc, smallfont);
SetBkMode(hdc, TRANSPARENT);
SetBkColor(hdc, RGB(0,0,0));
SetTextColor(hdc, textshadow);
TextOut(hdc, 1, 1, buf, len);
SetTextColor(hdc, brighttextcolor);
TextOut(hdc, 0, 0, buf, len);
fpssurf->ReleaseDC(hdc);
displayfps=TRUE;
framecount=0;
}
return TRUE;
}
Функция UpdateFPSSurface()использует переменную framecountдля подсчета выведенных кадров. Переменная framecountобнуляется в двух случаях: при изменении видеорежима и при обновлении поверхности fpssurfзаново вычисленным значением FPS.
Каждый раз, когда заданное количество кадров будет подготовлено и выведено на экран, функция timeGetTime()подсчитывает количество прошедших миллисекунд. По этой величине определяется текущий FPS приложения.
Значение FPS преобразуется в строку и выводится на поверхность FPS (после предварительной очистки поверхности функцией ClearSurface()). После вывода текста переменная framecountобнуляется, и начинается новый интервал хронометража. Наконец, переменной displayfpsприсваивается значение TRUE; оно говорит о том, что на поверхности FPS находится допустимое значение, которое следует вывести на экран.
Возвращаясь к функции DrawScene()(см. листинг 4.4), мы видим, что код отображения fpssurfи переключения страниц выглядит так:
if (displayfps) {
int x=displayrect.right-fpsrect.right-1;
int y=displayrect.bottom-fpsrect.bottom-1;
backsurf->BltFast(x, y, fpssurf, 0, DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT);
}
primsurf->Flip(0, DDFLIP_WAIT);
Если флаг displayfpsравен TRUE, поверхность FPS следует вывести на экран. Однако сначала мы рассчитываем ее положение по известным размерам видеорежима и поверхности. Затем мы копируем поверхность fpssurfфункцией BltFast(), после чего выводим на экран вторичный буфер функцией Flip()интерфейса DirectDrawSurface.
Задача функции DrawScene()выполнена — все три поверхности программы Switch выведены на экран. Тем не менее изучение приложения еще не закончено. Мы должны рассмотреть обработку пользовательского ввода.
Но перед тем как продолжить, я должен сделать одно замечание относительно программы Switch. Как мы видели во время рассмотрения ее кода, две из трех поверхностей программы имеют цветовые ключи для отображения прозрачных пикселей. Однако при запуске программы кажется, что анимационная поверхность (не имеющая цветового ключа) тоже является прозрачной. Почему? Потому что цвет фона растра (черный) совпадает с цветом вторичного буфера. Если изменить значение для заливки вторичного буфера, станет ясно, что анимационная поверхность на самом деле непрозрачна.
Обработка пользовательского ввода
При запуске программы Switch текст в нижней части меню подсказывает, какие клавиши управляют работой приложения. Клавиши со стрелками изменяют текущий выделенный видеорежим, клавиша Enterактивизирует его (если он не является текущим), а клавиша Escapeзавершает работу программы. Все эти клавиши обрабатываются функцией OnKeyDown(), создаваемой ClassWizard. Ее код приведен в листинге 4.5.
Листинг 4.5. Функция SwitchWin::OnKeyDown()
void SwitchWin::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) {
int newindex;
int nmodes=GetNumDisplayModes();
if (nmodes>maxmodes) nmodes=maxmodes;
int rows=nmodes/menucols;
if (nmodes%menucols) rows++;
switch (nChar) {
case VK_ESCAPE:
PostMessage(WM_CLOSE);
break;
case VK_UP:
newindex=selectmode-1;
if (newindex>=0) {
selectmode=newindex;
UpdateMenuSurface();
}
break;
case VK_DOWN:
newindex=selectmode+1;
if (newindex
selectmode=newindex;
UpdateMenuSurface();
}
break;
case VK_LEFT:
newindex=selectmode-rows;
if (newindex>=0) {
selectmode=newindex;
UpdateMenuSurface();
}
break;
case VK_RIGHT:
newindex=selectmode+rows;
Читать дальше