Наконец, функция SetPalette()интерфейса DirectDrawSurface()присоединяет палитру к поверхности. Обратите внимание на то, что палитра присоединяется к первичной поверхности. Хотя палитры можно присоединять и к другим поверхностям, на системную палитру влияет только палитра, присоединенная к первичной поверхности.
Передача графических данных
Как видно из функции CreateSurface(), передача графических данных BMP-файла на поверхность осуществляется функцией Copy_Bmp_Surface(). Функция Copy_Bmp_Surface()пользуется услугами четырех вспомогательных функций, каждая из которых специализируется на пикселях определенной глубины. Код Copy_Bmp_Surface()выглядит так:
BOOL DirectDrawWin::Copy_Bmp_Surface(LPDIRECTDRAWSURFACE surf, BITMAPINFOHEADER* bmphdr, BYTE* buf) {
if (surf==0 || bmphdr==0 || buf==0) return FALSE;
int imagew=bmphdr->biWidth;
int imageh=bmphdr->biHeight;
int imagebitdepth=bmphdr->biBitCount;
BOOL ret=FALSE;
if (imagebitdepth==8) {
if (displaydepth==8) ret=Copy_Bmp08_Surface08(surf, buf, imagew, imageh);
} else if (imagebitdepth==24) {
if (displaydepth==16) ret=Copy_Bmp24_Surface16(surf, buf, imagew, imageh);
else if (displaydepth==24) ret=Copy_Bmp24_Surface24(surf, buf, imagew, imageh);
else if (displaydepth==32) ret=Copy_Bmp24_Surface32(surf, buf, imagew, imageh);
}
return ret;
}
Вспомогательные функции предназначены для передачи графических данных в зависимости от глубины пикселей BMP-файла и текущего видеорежима. Все четыре функции получают одни и те же четыре аргумента: указатель на поверхность-приемник, буфер с графическими данными из BMP-файла, ширину и высоту изображения. Каждая функция копирует графические данные BMP-файла на поверхность-приемник.
8-битные поверхности
Начнем с самой простой из четырех функций, Copy_Bmp08_Surface08(). Она выглядит так:
BOOL DirectDrawWin::Copy_Bmp08_Surface08(LPDIRECTDRAWSURFACE surf, BYTE* bmpbuf, int w, int h) {
if (surf==0 || bmpbuf==0) return FALSE;
DDSURFACEDESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.dwSize = sizeof(desc);
HRESULT r=surf->Lock(0, &desc, DDLOCK_WAIT | DDLOCK_WRITEONLY, 0);
if (r!=DD_OK) {
TRACE("ShowBmp: Lock() failed\n");
return FALSE;
}
int bytesgiven=(w+3) & ~3;
BYTE* surfbits = (BYTE*)desc.lpSurface;
BYTE* imagebits = (BYTE*)(&bmpbuf[(h-1)*bytesgiven]);
for(int i=0; i
memcpy(surfbits, imagebits, w);
surfbits += desc.lPitch;
imagebits -= bytesgiven;
}
surf->Unlock(0);
return TRUE;
}
После проверки обоих аргументов-указателей мы подготавливаем экземпляр структуры DDSURFACEDESC( desc) и используем его при вызове функции Lock()интерфейса DirectDrawSurface. После возвращения из функции Lock()поле lpSurfaceсодержит указатель на память поверхности, и мы можем спокойно изменять содержимое поверхности через этот указатель до вызова Unlock(). Безопасная работа с поверхностью стала возможной только потому, что мы указали флаг DDLOCK_WRITEONLY. Если вы собираетесь осуществлять и чтение, и запись, не устанавливайте этот флаг.
Далее мы инициализируем целую переменную bytesgiven. Присваиваемое значение определяется шириной изображения ( w), выровненного по границе параграфа. Получившаяся величина равна объему памяти, необходимой для хранения одной строки пикселей. Если ширина изображения кратна четырем, переменная bytesgivenсовпадает с w.
Указатель на поверхность ( surfbits) инициализируется значением поля lpSurface. Этот указатель используется для обращений к памяти поверхности. Указатель на графические данные ( imagebits) инициализируется адресом последней строки пикселей BMP-файла, поскольку в формате BMP изображение хранится в перевернутом виде.
Затем мы в цикле перебираем все строки пикселей изображения. Благодаря тому, что формат графических данных BMP-файла совпадает с форматом поверхности, для копирования можно воспользоваться функцией memcopy(). Для поверхностей остальных типов такая удобная возможность часто отсутствует. Поле lPitchопределяет смещение для указателя на поверхность при переходе к следующей строке. Вспомните, что в этом поле хранится шаг поверхности, который может не совпадать с ее шириной. Целая переменная bytesgivenаналогичным образом используется для перехода к следующей строке буфера графических данных. Поскольку чтение начинается с конца буфера, указатель imagebitsуменьшается с каждой очередной итерацией.
Наконец, мы вызываем функцию Unlock()интерфейса DirectDrawSurfaceи в качестве аргумента передаем ей ноль. С помощью этого аргумента можно сбалансировать вызовы Lock()и Unlock()при многократной блокировке одной поверхности. Для сценариев с однократной блокировкой (включая наш) можно просто передать ноль.
Читать дальше