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

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 10 11 12 13 14 15 16 17 18 ... 66

Перед тем как начинать работу, необходимо создать экземпляры всех основных классов приложения. В нашем случае это будут классы BounceWin и BounceApp. Объект приложения создается способом, традиционным для MFC, то есть объявлением глобального экземпляра:

BounceApp theapp;

Класс BounceApp наследует свои функциональные возможности от DirectDrawApp, и больше ему почти ничего не требуется. Есть всего одно исключение: класс BounceApp отвечает за создание объекта BounceWin. Это происходит в функции InitInstance(), вызываемой MFC при запуске приложения. Функция InitInstance() выглядит так:

BOOL BounceApp::InitInstance() {

 BounceWin* win=new BounceWin;

 if (!win->Create("High Performance Bounce Demo", IDI_ICON)) {

  AfxMessageBox("Failed to create window");

  return FALSE;

 }

 m_pMainWnd=win;

 return DirectDrawApp::InitInstance();

}

Функция InitInstance() создает экземпляр класса BounceWin и вызывает функцию BounceWin::Create(). При вызове Create() необходимо передать два аргумента: строку с названием окна и идентификатор ресурса значка. Хотя название окна не отображается во время работы приложения (потому что приложение занимает весь экран и не имеет строки заголовка), оно будет выводиться в списке задач, а также на панели задач при сворачивании приложения. Если вызов Create() закончится неудачей, то функция InitInstance() возвращает FALSE. По этому признаку MFC узнает о том, что приложение следует аварийно завершить.

Затем переменная m_pMainWnd инициализируется указателем на созданный объект окна. Эта переменная принадлежит классу CWinApp; инициализируя ее, вы сообщаете классу CWinApp о том, каким объектом окна он будет управлять. Если m_pMainWnd не будет присвоен указатель на окно, MFC завершает приложение с ошибкой.

Наконец, мы вызываем функцию DirectDrawApp:InitInstance() и используем полученное от нее значение в качестве результата функции BounceApp::InitInstance(). Функция InitInstance() класса DirectDrawApp выглядит так:

BOOL DirectDrawApp::InitInstance() {

 ASSERT(m_pMainWnd);

 m_pMainWnd->ShowWindow(SW_SHOWNORMAL);

 m_pMainWnd->UpdateWindow();

 ShowCursor(FALSE);

 return TRUE;

}

Я уже упоминал о том, что MFC требует задать значение переменной m_pMainWnd, но поскольку значение m_pMainWnd используется в этой функции, проверку можно выполнить и самостоятельно. Макрос MFC ASSERT() проверяет значение переменной m_pMainWnd. Если указатель равен нулю, приложение завершается с ошибкой. Если он отличен от нуля, мы вызываем две функции созданного окна: ShowWindow() и UpdateWindow(). Эти функции отображают окно на экране. Наконец, функция ShowCursor() отключает курсор мыши.

Создание и отображение окна завершает процесс инициализации классов DirectDrawApp и BounceApp. Теперь давайте посмотрим, как этот процесс отражается на классах DirectDrawWin и BounceWin.

Как мы уже знаем, функция Create() вызывается из функции BounceApp:: InitInstance(). Она не реализуется классом BounceWin, а наследуется от DirectDrawWin. Функция Create() выглядит так:

BOOL DirectDrawWin::Create(const CString& title,int icon) {

 CString sClassName;

 sClassName = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,   LoadCursor(0, IDC_ARROW), (HBRUSH)(COLOR_WINDOW + 1),   LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(icon)));

 return CWnd::CreateEx(WS_EX_TOPMOST, sClassName, title, WS_POPUP, 0, 0, 100, 100, 0, 0);

}

Сначала функция Create() регистрирует класс окна с помощью функции AfxRegisterWndClass(). Затем она вызывает функцию CreateEx(), в которой и происходит фактическое создание окна.

Обратите внимание на то, что создаваемое окно имеет размеры 100x100 (седьмой и восьмой аргументы CreateEx()). Такой размер выбран произвольно. DirectDraw при подключении окна автоматически изменяет его размер так, чтобы оно занимало весь экран. Также обратите внимание на флаг WS_EX_TOPMOST: окно полноэкранного приложения DirectDraw должно выводиться поверх остальных окон.

Атрибут верхнего окна, а также занятие им всего экрана необходимы для того, чтобы механизм GDI не смог ничего вывести на экран. GDI ничего не знает о DirectDraw, поэтому наше окно «обманывает» GDI на то время, пока весь экран находится под управлением DirectDraw. Вообще говоря, вывод средствами GDI может происходить и в полноэкранном режиме, но обычно это не рекомендуется, потому что вывод GDI может попасть на невидимую поверхность. Эта тема более подробно рассматривается в главе 5.

Инициализация DirectDraw

Фактическое создание окна (вызов функции CreateEx()) заставляет Windows послать нашему приложению сообщение WM_CREATE. Класс DirectDrawWin перехватывает это сообщение в обработчике OnCreate(), созданном ClassWizard (см. листинг 3.1).

Листинг 3.1. Функция DirectDrawWin::OnCreate()

int DirectDrawWin::OnCreate(LPCREATESTRUCT) {

 DirectDrawEnumerate(DriverAvailable, this);

 if (totaldrivers==0) {

  AfxMessageBox("No DirectDraw drivers detected");

  return -1;

 }

 int driverindex=SelectDriver();

 if (driverindex<0) {

  TRACE("No DirectDraw driver selectedn");

  return -1;

 } else if (driverindex>totaldrivers-1) {

  AfxMessageBox("Invalid DirectDraw driver selectedn");

  return -1;

 }

 LPDIRECTDRAW ddraw1;

 DirectDrawCreate(driver[driverindex].guid, &ddraw1, 0);

 HRESULT r;

 r=ddraw1->QueryInterface(IID_IDirectDraw2, (void**)&ddraw2);

 if (r!=S_OK) {

  AfxMessageBox("DirectDraw2 interface not supported");

  return -1;

 }

 ddraw1->Release(), ddraw1=0;

 ddraw2->SetCooperativeLevel(GetSafeHwnd(), DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX);

 ddraw2->EnumDisplayModes(0, 0, this, DisplayModeAvailable);

 qsort(displaymode, totaldisplaymodes, sizeof(DisplayModeInfo),   CompareModes);

 int initmode=SelectInitialDisplayMode();

 if (ActivateDisplayMode(initmode)==FALSE) return -1;

 return 0;

}

Вся инициализация DirectDraw выполняется в функции OnCreate() (при поддержке нескольких вспомогательных функций). Процесс инициализации состоит из семи этапов:

• Получение списка всех драйверов DirectDraw.

• Выбор драйвера DirectDraw.

• Инициализация DirectDraw с использованием выбранного драйвера.

• Получение списка поддерживаемых видеорежимов.

• Выбор исходного видеорежима.

• Активизация выбранного видеорежима.

• Создание поверхностей приложения.

Все эти этапы рассматриваются в последующих разделах.

Получение списка драйверов DirectDraw

Функция DirectDrawEnumerate() предназначена для составления списка доступных драйверов DirectDraw. Чаще всего обнаруживается всего один драйвер DirectDraw — тот, который управляет установленной видеокартой. Тем не менее в некоторых конфигурациях может присутствовать несколько видеоустройств. В таких случаях DirectDrawEnumerate() покажет отдельный драйвер для каждого видеоустройства, поддерживаемого DirectDraw.

Функция DirectDrawEnumerate() получает два аргумента: указатель на косвенно вызываемую (callback) функцию и указатель на данные, определяемые приложением, которые передаются этой функции при вызове. В нашем случае аргументами являются косвенно вызываемая функция DriverAvailable() и указатель на класс DirectDrawWin (this). Функция DriverAvailable() определяется так:

BOOL WINAPI DirectDrawWin::DriverAvailable(LPGUID guid, LPSTR desc, LPSTR name, LPVOID p) {

 DirectDrawWin* win=(DirectDrawWin*)p;

 if (win->totaldrivers >= MAXDRIVERS) return DDENUMRET_CANCEL;

 DriverInfo& info=win->driver[win->totaldrivers];

 if (guid)  {

  info.guid=(GUID*)new BYTE[sizeof(GUID)];

  memcpy(info.guid, guid, sizeof(GUID));

 } else info.guid=0;

 info.desc=strdup(desc);

 info.name=strdup(name);

 win->totaldrivers++;

 return DDENUMRET_OK;

}

Сначала указатель на данные, определяемые приложением (p), преобразуется в указатель на класс DirectDrawWin (win). Поскольку функция DriverAvailable() объявлена как статическая (косвенно вызываемые функции обязаны быть статическими), на нее в отличие от обычных функций класса не распространяются правила автоматического доступа; соответственно доступ к переменным и функциям класса приходится осуществлять через указатель win.

DirectDraw вызывает функцию DriverAvailable() один раз для каждого обнаруженного драйвера. При каждом вызове передаются три информационных объекта: GUID, описание и имя. GUID (глобально-уникальный идентификатор) однозначно идентифицирует драйвер. Описание и имя представляют собой строки для неформальной идентификации драйвера. Функция DriverAvailable() сохраняет сведения о каждом драйвере в массиве с именем driver и отслеживает количество драйверов в переменной totaldrivers. Наконец, функция DriverAvailable() возвращает DDNUMRET_OK, показывая, что перечисление драйверов должно продолжаться. При получении кода возврата DDENUMRET_CANCEL DirectDraw прекращает перечисление драйверов.

1 ... 10 11 12 13 14 15 16 17 18 ... 66
На этой странице вы можете бесплатно читать книгу Графика для Windows средствами DirectDraw - Стэн Трухильо бесплатно.
Похожие на Графика для Windows средствами DirectDraw - Стэн Трухильо книги

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