if (CreateCustomSurfaces()==FALSE) {
FatalError('CreateCustomSurfaces() failed');
return FALSE;
}
return TRUE;
}
Функция ActivateDisplayMode() получает один аргумент — индекс в отсортированном списке обнаруженных видеорежимов. Сначала индекс проверяется на правильность. Если он соответствует допустимому элементу массива displaymode, высота, ширина и глубина заданного режима извлекаются из массива и используются для инициализации переменных displayrect и displaydepth. Затем атрибуты видеорежима используются при вызове функции SetDisplayMode(), активизирующей новый видеорежим.
Далее функция CreateFlipingSurfaces() создает первичную поверхность со вторичным буфером, а функция StorePixelFormatData() проверяет, не устарел ли формат пикселей DirectDrawWin (форматы пикселей подробно рассматриваются в главе 5). Наконец, мы вызываем функцию CreateCustomSurfaces(), отвечающую за создание вспомогательных поверхностей приложения.
Итак, функция ActivateDisplayMode() автоматизирует процесс переключения видеорежимов. Сначала она проверяет, будут ли при вызове функции SetDisplayMode() использоваться правильные аргументы, а затем восстанавливает поверхности приложения. Настало время применить ее на практике.
Программа Switch — полноэкранное приложение DirectDraw, которое выводит меню всех поддерживаемых видеорежимов и позволяет активизировать любой из них. На рис. 4.1 показано, как она выглядит.
Рис. 4.1. Программа Switch
Эта программа представляет собой модифицированное полноэкранное приложение, сгенерированное DirectDraw AppWizard. В программу было добавлено меню, позволяющее выбрать видеорежим (с помощью клавиш со стрелками) и активизировать его (клавишей Enter). Клавиша Escape завершает работу программы. Программа Switch также вычисляет и отображает FPS приложения (количество кадров в секунду).
В программе Switch мы научимся:
• переключать видеорежимы;
• выводить текст на поверхностях DirectDraw;
• рассчитывать FPS приложения;
• работать с цветовыми ключами.
Программа Switch, как и все остальные программы в этой книге, была создана с помощью DirectDraw AppWizard, так что ее структура покажется вам знакомой, если вы прочитали главу 3. Реализация программы основана на двух классах, SwitchWin и SwitchApp, производных от классов DirectDrawWin и DirectDrawApp соответственно. Класс SwitchApp остался в том виде, в котором он был сгенерирован AppWizard, и потому дальнейшему обсуждению не подлежит.
Класс SwitchWin создает три поверхности: одна используется для перемещения растрового изображения на экране, вторая реализует меню видеорежимов, а третья — вывод FPS. Но перед тем, как рассматривать код программы, давайте поговорим о том, как вывести на поверхность текст и как рассчитать FPS приложения.
Самый простой способ вывести текст на поверхность — получить у Windows DC (контекст устройства) с помощью функции GetDC() интерфейса DirectDrawSurface. После этого можно вывести текст на поверхность стандартными функциями TextOut() и TextOutExt() и освободить DC функцией DirectDrawSurface::ReleaseDC(). Атрибуты текста (цвет, фон и способ вывода) выбираются следующими функциями Win32:
• SelectObject()
• SetBkMode()
• SetBkColor()
• SetTextColor()
Мы воспользуемся этими функциями в программе Switch для вывода меню видеорежимов и значения FPS.
Вычисление FPS
FPS приложения можно вычислить несколькими способами. Наиболее точный из них — подсчитать общее количество кадров, выведенных приложением, и затем разделить его на время работы приложения в секундах. Недостаток этого способа заключается в том, что значение FPS можно получить лишь после того, как приложение завершится.
Чтобы вычислить FPS во время работы приложения, необходимо производить периодические измерения. К сожалению, скорость работы приложения может изменяться в зависимости от сложности графического вывода и объема внутренних вычислений. Кроме того, Windows замедляет работу приложения при передаче части процессорного времени другим приложениям или при переносе содержимого памяти на диск. В момент запуска приложение обычно работает медленнее, потому что Windows начинает сбрасывать данные на диск. Только после того, как Windows «успокоится» и перестанет работать с диском, можно будет получить достоверные значения FPS.
В программе Switch мы будем периодически вычислять FPS и отображать результат до истечения следующего интервала. Если запустить программу Switch, вы заметите, что значение FPS появляется не сразу; это происходит из-за того, что для получения достоверных показаний должно пройти некоторое время.
Для хронометража используется функция Win32 timeGetTime(), которая возвращает количество миллисекунд, прошедших с момента запуска Windows. В программе Switch функция timeGetTime() вызывается после каждых 100 кадров; значение FPS равно 100, разделенному на количество прошедших секунд.
Функция timeGetTime() не обеспечивает максимальной точности измерений, которую можно получить в Windows (для более точного хронометража можно воспользоваться функцией QueryPerformanceCounter()). Если бы мы отслеживали очень короткие периоды времени (например, интервалы по 10 миллисекунд), то функция timeGetTime() не давала бы приемлемых результатов, но поскольку таймер используется не чаще одного раза в секунду, подходит и timeGetTime().
Давайте рассмотрим код программы Switch. Начнем с определения класса SwitchWin (см. листинг 4.2).
Листинг 4.2. Объявление класса SwitchWin
class SwitchWin : public DirectDrawWin {
public:
SwitchWin();
protected:
//{{AFX_MSG(SwitchWin)
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
private:
int SelectDriver();
int SelectInitialDisplayMode();
BOOL CreateCustomSurfaces();
void DrawScene();
void RestoreSurfaces();
BOOL CreateMenuSurface();
BOOL UpdateMenuSurface();
BOOL CreateFPSSurface();
BOOL UpdateFPSSurface();
private:
LPDIRECTDRAWSURFACE bmpsurf;
int x, y;
int xinc, yinc;
LPDIRECTDRAWSURFACE menusurf;