Сегодня я собираюсь разобраться с задачей, с которой Вы, возможно, уже сталкивались, или столкнетесь в ближайшем будущем: наложение 24-разрядного изображения на 16-разрядную поверхность DirectDraw.
Несколько дней назад я работал на моем старом компьютере с видеокартой ATI VGA Wonder. Видеокарта использовала по 5 бит для каждого значения R, G и B (всего 15 бит), так что формат пикселя выглядел что-то вроде этого:
XRRRRRGGGGGBBBBB
Сейчас у моего нового компьютера более лучшая видеокарта. Она использует все 16 бит, делая формат пикселя похожим на:
RRRRRGGGGGGBBBBB
Я стал размышлять о том, как сделать так, чтобы я мог указать любой цвет для вывода на экран, так что бы он отображался корректно, независимо от того, какая видеокарта установлена.
Кстати, я написал свой собственный загрузчик растровых изображений, читающий 24-разрядные BMP и накладывающий их на 16-разрядную поверхность (я, вероятно, расскажу про это позже, скорее всего в отдельной статье).
Итак, я уселся и приступил к решению этой задачи. Первое, что я сделал, это открыл файл DirectX.hlp и нашел описание интерфейса IDirectDrawSurface. Одна из функций интерфейса называется GetPixelFormat. Отлично. У меня есть что-то, с чем можно работать.
GetPixelFormat берет указатель на структуру DDPIXELFORMAT (что не удивительно). Я рассмотрел структуру DDPIXELFORMAT и нашел пару полей, которые заинтересовали меня, а именно dwRBitMask, dwGBitMask, dwBBitMask.
Теперь у меня есть вся необходимая информация, только не в том формате, который я мог бы использовать.
Ну, чтобы выяснить, насколько влево нужно сдвинуть биты, я сделал так:
// Предупреждаю, этот код УЖАСТЕН
var
dwBMask, dwRMask, dwGMask,
dwBSHL, dwRSHL, dwGSHL :DWORD;
dwBMask := ddpf.dwBBitMask;
dwRMask := ddpf.dwRBitMask;
dwGMask := ddpf.dwGBitMask;
dwBSHL=0;
dwRSHL=0;
dwGSHL=0;
while (dwBMask AND 1) = 0 do
begin
dwBMask := dwBMask shl 1;
Inc(dwBSHL);
end;
while (dwGMask AND 1) = 0 do
begin
dwGMask:= dwGMask shl 1;
Inc(dwGSHL);
end;
while (dwRMask AND 1) = 0 do
begin
dwRMask:= dwRMask shl 1;
Inc(dwRSHL);
end;
В этом месте, если мы примем, что в трех UCHARS, названных Red, Green и Blue, хранится правильное число бит, то можно вычислить 16-разрядный цвет:
Color := Blue shr dwBSHL +
Green shr dwGSHL +
Red shr dwRSHL;
Однако, сейчас у нас по 8 бит в каждом из Red, Green и Blue, а требуется только 5 или 6. Нам нужно сдвинуть биты цветов направо перед смещением их налево, чтобы получить 16-разрядный цвет.
Итак, давайте определим, насколько бит мы должны сдвинуть их направо:
var
dwBSHR, dwRSHR, dwGSHR :DWORD;
dwBSHR=0;
dwRSHR=0;
dwGSHR=0;
while (dwBMask AND 1) = 1 do
begin
dwBMask := dwBMask shl 1;
Dec(dwBSHL);
end;
while (dwGMask AND 1) = 1 do
begin
dwGMask:= dwGMask shl 1;
Dec(dwGSHL);
end;
while (dwRMask AND 1) = 1 do
begin
dwRMask:= dwRMask shl 1;
Dec(dwRSHL);
end;
Теперь, мы можем точно вычислить 16 разрядный цвет из 24 разрядного