int DirectDrawWin::OnCreate(LPCREATESTRUCT) {
LPDIRECTDRAW ddraw1;
DirectDrawCreate(0, &ddraw1, 0);
ddraw1->QueryInterface(IID_IDirectDraw2, (void**)&ddraw2); ddraw1->Release(), ddraw1=0; ddraw2->SetCooperativeLevel(GetSafeHwnd(), DDSCL_NORMAL);
DetectDisplayMode();
if (CreateFlippingSurfaces()==FALSE) {
AfxMessageBox("CreateFlippingSurfaces() failed");
return FALSE;
}
if (CreateCustomSurfaces()==FALSE) {
AfxMessageBox("CreateCustomSurfaces() failed");
return FALSE;
}
return 0;
}
Сначала указатель на интерфейс DirectDraw(ddraw1)инициализируется функцией DirectDrawCreate(). Указатель ddraw1, как и в полноэкранной версии, используется только для получения указателя на интерфейс DirectDraw2, после чего освобождается.
Затем функция OnCreate()вызывает функцию SetCooperativeLevel(). В полноэкранном приложении уровень кооперации определялся тремя флагами: DDSCL_EXCLUSIVE, DDSCL_FULLSCREENи DDSCL_ALLOWMODEX. В данном случае используется только флаг DDSCL_NORMAL.
Функция DetectDisplayMode()инициализирует некоторые переменные класса DirectDrawWin. Она выглядит так:
BOOL DirectDrawWin::DetectDisplayMode() {
DDSURFACEDESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.dwSize=sizeof(desc);
if (ddraw2->GetDisplayMode(&desc)!=DD_OK) {
TRACE("GetDisplayMode() failed\n");
return FALSE;
}
displayrect.left=0;
displayrect.top=0;
displayrect.right=desc.dwWidth;
displayrect.bottom=desc.dwHeight;
displaydepth=desc.ddpfPixelFormat.dwRGBBitCount;
return TRUE;
}
Функция DetectDisplayMode()с помощью функции GetDisplayMode()интерфейса DirectDrawполучает информацию о текущем видеорежиме Windows. Говоря точнее, разрешение экрана и глубина пикселей текущего видеорежима сохраняются в переменных displayrectи displaydepth.
Далее OnCreate()вызывает функцию CreateFlippingSurfaces(). Хотя оконное приложение не может выполнять настоящего переключения страниц (как можно было бы решить, исходя из имени функции), имя было сохранено, потому что создаваемые в ней поверхности эмулируют переключение страниц. Код функции приведен в листинге 3.4.
Листинг 3.4. Функция CreateFlippingSurfaces() в оконном приложении
BOOL DirectDrawWin::CreateFlippingSurfaces() {
HRESULT r;
DDSURFACEDESC desc;
desc.dwSize = sizeof(desc);
desc.dwFlags = DDSD_CAPS;
desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
r=ddraw2->CreateSurface(&desc, &primsurf, 0);
if (r!=DD_OK) {
TRACE("FAILED to create 'primsurf'\n");
return FALSE;
}
r=ddraw2->CreateClipper(0, &clipper, 0);
if (r!=DD_OK) {
TRACE("CreateClipper() failed\n");
return FALSE;
}
r=clipper->SetHWnd(0, GetSafeHwnd());
if (r!=DD_OK) {
TRACE("SetHWnd() failed\n");
return FALSE;
}
r=primsurf->SetClipper(clipper);
if (r!=DD_OK) {
TRACE("SetClipper() failed\n");
return FALSE;
}
ZeroMemory(&desc, sizeof(desc));
desc.dwSize = sizeof(desc);
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
desc.dwWidth = displayrect.Width();
desc.dwHeight = displayrect.Height();
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
r=ddraw2->CreateSurface(&desc, &backsurf, 0);
if (r!=DD_OK) {
TRACE("failed to create 'backsurf' in video\n");
videobacksurf=FALSE;
} else {
TRACE("Created backsurf in video\n");
videobacksurf=TRUE;
}
return TRUE;
}
Сначала мы создаем первичную поверхность. В полноэкранном варианте код выглядит по-другому, потому что здесь создается обычная, несоставная первичная поверхность. В структуре DDSURFACEDESCмы описываем первичную поверхность, используя только флаг DDSCAPS_PRIMARYSURFACE. Затем описанная поверхность создается функцией CreateSurface()интерфейса DirectDraw.
Далее функция CreateClipper()интерфейса DirectDrawсоздает объект отсечения. CreateClipper()получает три аргумента, однако первый и последний из них чаще всего равны нулю. Второй аргумент представляет собой адрес указателя на интерфейс DirectDrawClipper. В нашем случае используется переменная класса DirectDrawWinс именем clipper.
Объект отсечения нужен для ограничения вывода в программе. Поскольку наше приложение работает в окне, которое находится на рабочем столе вместе с другими окнами, при обновлении изображения необходимо учитывать присутствие этих окон. Чтобы объект отсечения автоматически выполнял свою работу, его необходимо присоединить к окну функцией SetHWnd()интерфейса DirectDrawClipper. Функция SetHWnd()получает два аргумента — двойное слово ( DWORD), которое зарезервировано для будущего использования и пока должно быть равно нулю, и логический номер окна приложения.
Читать дальше