Рейтинговые книги
Читем онлайн Графика для Windows средствами DirectDraw - Стэн Трухильо

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 21 22 23 24 25 26 27 28 29 ... 66

Вернемся к функции DrawScene(). Наша следующая задача - обновление и отображение поверхности FPS (fpssurf). Однако, как было сказано выше, поверхность fpssurf обновляется лишь после того, как закончится очередной интервал хронометража.

Вычисление 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<nmodes)  {

   selectmode=newindex;

   UpdateMenuSurface();

  }

  break;

 case VK_LEFT:

  newindex=selectmode-rows;

  if (newindex>=0) {

   selectmode=newindex;

   UpdateMenuSurface();

  }

  break;

 case VK_RIGHT:

  newindex=selectmode+rows;

  if (newindex<nmodes) {

   selectmode=newindex;

   UpdateMenuSurface();

  }

  break;

 case VK_RETURN:

  if (selectmode != GetCurDisplayMode()) {

   ActivateDisplayMode(selectmode);

   x=y=0;

  }

  break;

 case 'S':

  SaveSurface(primsurf, "switch.bmp");

  break;

 case 'M':

  SaveSurface(menusurf, "menusurf.bmp");

  break;

 case 'F':

  SaveSurface(fpssurf, "fpssurf.bmp");

  break;

 case 'T':

  SaveSurface(bmpsurf, "trisurf.bmp");

  break;

 default:

  DirectDrawWin::OnKeyDown(nChar, nRepCnt, nFlags);

 }

}

Обработка нажатых клавиш происходит в различных секциях оператора switch. Клавиша Escape (код виртуальной клавиши VK_ESCAPE) приводит к посылке сообщения WM_CLOSE и последующему завершению приложения. При нажатии клавиш со стрелками изменяется индекс текущего видеорежима и вызывается функция UpdateMenuSurface(), которая перерисовывает menusurf в соответствии с произведенными изменениями. При нажатии клавиши Enter (VK_RETURN) вызывается функция ActivateDisplayMode(), которой в качестве аргумента передается индекс режима (при условии, что выбран видеорежим, отличный от текущего). Все остальные клавиши, нажатые пользователем, обрабатываются функцией OnKeyDown() базового класса. 

Восстановление поверхностей 

Программа Switch почти готова. Она инициализируется, переключает видеорежимы и обрабатывает пользовательский ввод. Но окончательный вид программа примет лишь после того, как мы организуем в ней восстановление потерянных поверхностей. Класс DirectDrawWin обнаруживает потерю поверхностей и автоматически восстанавливает первичную поверхность со вторичным буфером; после этого вызывается функция RestoreSurfaces(), в которой должны восстанавливаться вспомогательные поверхности приложения. В программе Switch функция RestoreSurfaces() реализована так:

void SwitchWin::RestoreSurfaces() {

 int displaydepth=GetCurDisplayDepth();

 CString filename;

 if (displaydepth==8) filename="tri08.bmp";

 else filename="tri24.bmp";

 if (bmpsurf->IsLost()) {

  bmpsurf->Restore();

  LoadSurface(bmpsurf, filename);

 }

 if (menusurf->IsLost()) {

  menusurf->Restore();

  UpdateMenuSurface();

 }

 if (fpssurf->IsLost()) {

  fpssurf->Restore();

  ClearSurface(fpssurf, 0);

 }

 displayfps=FALSE;

 framecount=0;

}

В нашем случае функция RestoreSurfaces() отвечает за восстановление всех трех вспомогательных поверхностей. Ее работа начинается с анимационной поверхности (bmpsurf). Функция получает текущую глубину пикселей и по ней определяет, какую версию BMP-файла (палитровую или беспалитровую) следует использовать при восстановлении поверхности. Затем мы проверяем, действительно ли поверхность была потеряна.

При этом учитывается, что «потеряться» могут лишь поверхности, находящиеся в видеопамяти. Поверхности в системной памяти никогда не теряются, поэтому предварительная проверка может избавить нас от хлопот с повторной загрузкой содержимого BMP-файла и, следовательно, ускорить процесс восстановления.

Если поверхность потеряна, мы вызываем функцию Restore() интерфейса DirectDrawSurface, чтобы вернуть видеопамять в объеме, достаточном для хранения поверхности. Содержимое поверхности восстанавливается функцией LoadSurface().

Восстановление двух других поверхностей происходит несколько иначе, потому что их содержимое не является BMP-файлом. Поверхность menusurf восстанавливается функцией Restore() с последующим вызовом функции UpdateMenuSurface(), в которой происходит стирание и перерисовка поверхности меню. При восстановлении fpssurf мы сначала вызываем Restore(), а потом стираем содержимое поверхности, потому что это содержимое после восстановления оказывается непредсказуемым. Не забывайте, поверхности чаще всего теряются из-за того, что занимаемая ими видеопамять понадобилась другому приложению.

1 ... 21 22 23 24 25 26 27 28 29 ... 66
На этой странице вы можете бесплатно читать книгу Графика для Windows средствами DirectDraw - Стэн Трухильо бесплатно.
Похожие на Графика для Windows средствами DirectDraw - Стэн Трухильо книги

Оставить комментарий