Глава 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<h; 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() при многократной блокировке одной поверхности. Для сценариев с однократной блокировкой (включая наш) можно просто передать ноль.
Содержание Назад Вперед