DDSURFACEDESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.dwSize = sizeof(desc);
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
desc.dwWidth = w;
desc.dwHeight = h;
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
LPDIRECTDRAWSURFACE surf;
HRESULT r=ddraw2->CreateSurface(&desc, &surf, 0);
if (r==DD_OK) {
TRACE("CreateSurface(%d,%d) created in video memory \n", w, h);
return surf;
}
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
r=ddraw2->CreateSurface(&desc, &surf, 0);
if (r==DD_OK) {
TRACE("CreateSurface(%d,%d) allocated in system memory \n", w, h);
return surf;
}
TRACE("CreateSurface(%d,%d) failed\n", w, h);
return 0;
}
Функция CreateSurface() с помощью структуры DDSURFACEDESC описывает поверхность, размеры которой равны передаваемым параметрам w и h. Поле dwFlags показывает, какие поля структуры будут инициализироваться. Поля dwWidth и dwHeight определяют размеры поверхности, а поле dwCaps — ее возможности. Обратите внимание на флаг DDSCAPS_VIDEOMEMORY, согласно которому создаваемая поверхность должна находиться в видеопамяти.
Затем мы вызываем функцию DirectDraw CreateSurface(). В качестве первого аргумента передается указатель на структуру с описанием поверхности; если вызов окажется успешным, указатель surf будет ссылаться на созданную поверхность.
При успешном создании поверхности макрос MFC TRACE() выводит отладочное сообщение, а вы получаете указатель surf. Тем не менее раз мы явно указали, что поверхность должна находиться в видеопамяти, при нехватке последней вызов CreateSurface() может закончиться неудачно. В этом случае мы изменяем поле dwCaps, заносим в него флаг DDSCAPS_SYSTEMMEMORY и снова вызываем функцию CreateSurface(). Скорее всего, вторая попытка окажется успешной; если и на этот раз поверхность не будет создана, функция возвратит 0.
Но давайте вернемся к списку функций DirectDrawWin для работы с поверхностями. Функция LoadSurface() загружает содержимое BMP-файла в существующую поверхность. Эта функция будет часто упоминаться, когда речь пойдет о восстановлении потерянных поверхностей. Функция LoadSurface() похожа на первую версию CreateSurface() (с загрузкой BMP-файла).
Функции ClearSurface() могут использоваться для частичного заполнения поверхностей. Первая версия ClearSurface() заполняет поверхность величиной, передаваемой в качестве второго параметра. Необязательный аргумент rect определяет заполняемую прямоугольную область (если он не задан, заполняется вся поверхность). Вторая версия ClearSurface() получает в качестве аргументов RGB-составляющие и на их основании вычисляет значение, присваиваемое каждому пикселю поверхности. Из-за дополнительной работы, затрачиваемой на интерпретацию цветов, вторая версия работает медленнее первой. Первая функция ClearSurface() реализована так:
BOOL DirectDrawWin::ClearSurface(LPDIRECTDRAWSURFACE surf, DWORD clr, RECT* rect) {
if (surf==0) return FALSE;
DDBLTFX bltfx;
ZeroMemory(&bltfx, sizeof(bltfx));
bltfx.dwSize = sizeof(bltfx);
bltfx.dwFillColor = clr;
HRESULT r;
r=surf->Blt(rect, 0, 0, DDBLT_COLORFILL | DDBLT_WAIT, &bltfx);
return r==DD_OK;
}
Функция ClearSurface() получает три аргумента: указатель на заполняемую поверхность; величину, присваиваемую каждому пикселю; и необязательную структуру RECT, которая определяет заполняемую область поверхности.
После проверки указателя мы подготавливаем экземпляр структуры DDBLTFX. Полю dwFillColor присваивается величина, используемая для заполнения, а сама операция осуществляется функцией Blt() интерфейса DirectDrawSurface. Флаг DDBLT_COLORFILL сообщает Blt() о том, что вместо блиттинга выполняется цветовое заполнение.
Получившаяся функция удобна, но ей не хватает универсальности. Дело в том, что величина, применяемая для заполнения поверхности, может иметь различный смысл. Например, для палитровых поверхностей она представляет собой индекс в палитре. Без предварительной проверки палитры невозможно предсказать, какой цвет будет использоваться для заполнения. Аналогичные проблемы возникают и для беспалитровых поверхностей, поскольку конкретное значение пикселя зависит от глубины и формата пикселей. Форматы пикселей особенно часто различаются в режимах High Color, поэтому заполнение поверхности конкретным цветом превращается в нетривиальную задачу.
Вторая версия ClearSurface() получает в качестве аргументов RGB-составляющие и рассчитывает по ним конкретную величину, присваиваемую пикселям поверхности. В таком варианте функция становится более универсальной, но и работает медленнее; быстродействие особенно сильно снижается для палитровых поверхностей, потому что нужный цвет приходится искать в палитре. Код этой функции будет рассмотрен в главе 5.
Нам остается рассмотреть лишь функцию GetSurfaceDimensions(), которая получает указатель на поверхность и возвращает ее ширину и высоту. Код этой функции выглядит так:
BOOL DirectDrawWin::GetSurfaceDimensions(LPDIRECTDRAWSURFACE surf, DWORD& w, DWORD& h) {