16-битные поверхности
Загрузка 8-битных изображений выполняется достаточно просто. Давайте перейдем к 16-битным поверхностям, с ними дело обстоит значительно сложнее. Помимо учета разных типов 16-битных форматов пикселей нам придется сокращать количество цветов. 24-битные данные передаются на 16-битную поверхность, поэтому во время передачи необходимо «урезать» каждую цветовую составляющую. Функция Copy_Bmp24_Surface16()приведена в листинге 5.2.
Листинг 5.2. Функция Copy_Bmp24_Surface16()
BOOL DirectDrawWin::Copy_Bmp24_Surface16(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("Copy_Bmp24_Surface16: Lock() failed\n");
return FALSE;
}
int bytesrequired=w*3;
int bytesgiven=(bytesrequired+3) & ~3;
BYTE* surfbits = (BYTE*)desc.lpSurface;
BYTE* imagebits = (BYTE*)(&bmpbuf[(h-1)*bytesgiven]);
float REDdiv=(float)256/(float)pow(2, numREDbits);
float GREENdiv=(float)256/(float)pow(2, numGREENbits);
float BLUEdiv=(float)256/(float)pow(2, numBLUEbits);
for(int i=0; i
USHORT* pixptr=(unsigned short*)surfbits;
RGBTRIPLE* triple=(RGBTRIPLE*)imagebits;
for (int p=0;p>w;p++) {
float rf=(float)triple->rgbtRed/REDdiv;
float gf=(float)triple->rgbtGreen/GREENdiv;
float bf=(float)triple->rgbtBlue/BLUEdiv;
WORD r=(WORD)((WORD)rf<
WORD g=(WORD)((WORD)gf<
WORD b=(WORD)((WORD)bf<
*pixptr = (WORD)(r|g|b);
triple++;
pixptr++;
}
surfbits += desc.lPitch;
imagebits –= bytesgiven;
}
surf->Unlock(0);
return TRUE;
}
Хотя по своей структуре функция Copy_Bmp24_Surface16()напоминает Copy_Bmp 08_Surface08(), она устроена сложнее по причинам, уже упоминавшимся, а также потому, что значение каждого пикселя приходится задавать отдельно. Давайте посмотрим, что происходит в этой функции.
Сначала функция Lock()интерфейса DirectDrawSurfaceиспользуется для получения указателя на поверхность. Затем мы инициализируем две целые переменные, bytesrequiredи bytesgiven. Значение bytesrequiredравно количеству байт, необходимых для представления строки пикселей. Поскольку мы работаем с 24-битными пикселями, для получения этой величины достаточно умножить ширину изображения на три (по три байта на пиксель). По значению bytesrequiredрассчитывается значение bytesgiven, которое равно количеству байт для хранения строки пикселей в памяти (с учетом выравнивания по границе параграфа). Значение bytesgivenиспользуется для перебора строк пикселей в графических данных BMP-файла.
Затем мы инициализируем указатели surfbitsи imagebits; первый указывает на память поверхности, а второй — на буфер графических данных. Как и в функции Copy_Bmp08_Surface08(), imagebitsуказывает на последнюю строку буфера.
Три следующие строки связаны с сокращением цветов. Мы вычисляем три величины (по одной для каждой цветовой составляющей), которые будут использоваться для обработки составляющих, полученных из буфера графических данных. Они зависят от количества бит в представлении каждой цветовой компоненты на поверхности (чаще всего 5 или 6 бит). Обратите внимание на то, что эти величины вычисляются за пределами цикла. Операция деления и вызов функции pow()внутри цикла могли бы существенно замедлить работу программы.
Назначение пикселей происходит во вложенном цикле. Внешний цикл перебирает строки пикселей, а внутренний задает значение для каждого пикселя строки. Внутренний цикл инициализирует два указателя, pixptrи triple, которые используются для обращения к текущему пикселю. Переменная pixptrуказывает на память поверхности, а triple- на буфер графических данных. Обратите внимание — pixptrобъявлен как указатель на 16-битный тип USHORT. В этом случае для перехода к следующему пикселю достаточно увеличить значение указателя. Аналогично tripleуказывает на 24-битный тип RGBTRIPLE.
Внутренний цикл извлекает три цветовые составляющие каждого пикселя и делит их на ранее вычисленную величину. Значения с плавающей точкой, использованные при вычислениях, преобразуются к целым и сдвигаются к нужной позиции в соответствии с переменными loREDbit, loGREENbitи loBLUEbit. Окончательный результат представляет собой тройку «урезанных» цветовых составляющих. Побитовый оператор ORупаковывает составляющие в единую величину, и результат заносится в память поверхности. Указатели pixptrи tripleинкрементируются для перехода к следующему пикселю.
Читать дальше