function TfrmDD.Circle (const X, Y, R : Integer;
const Color : Byte) : HRESULT;
function DDPutPixel (const X, Y, R, G, В : Integer) : HRESULT; var
ddbfx : TDDBLTFX;
rcDest : TRECT; begin
ZeroMemory (@ddbfx, SizeOf(ddbfx));
ddbfx.dwSize := SizeOf(ddbfx);
ddbfx.dwFillColor := RGB(R, G, B);
// Перекрашиваться будет маленький квадрат
SetRect(rcDest, X, Y, X + 1, Y + I);
Result := FDDSBack.Blt(OrcDest, nil, nil,
DDBLTJVAIT or DDBLT_COLORFILL, @ddbfx); end;
var
a : 0..359;
hRet : HRESULT; begin
for a := 0 to 359 do begin
hRet := DDPutPixel(X + trunc (cos (a) * R), У + trunc (sin (a) * R),
Color, Color, Color); if Failed (hRet) then begin Result := hRet;
Exit;
end;
end;
end;
Цвет задается тройкой одинаковых чисел. Для повышения красочности вы можете попробовать генерировать отдельное значение для каждой составляющей цвета. И если вы хорошенько поработаете с этим примером, то обнаружите небольшой обман: функция RGB в примере не работает должным образом, цвета получаются отнюдь не ожидаемые. Режим здесь 16-битный. Позднее, когда мы познакомимся с форматом пикселов, то найдем хорошее решение для этой проблемы.
Переключение буферов в данном примере из обработчика Onldle перенесено непосредственно в код обновления кадра.
При воспроизведении, аналогично предыдущему примеру, рисуем окружность в заднем буфере, затем буферы переключаем, и повторяем рисование окружности на том же самом месте, но уже во втором буфере:
function TfrmDD.UpdateFrame : HRESULT; var
X, Y, R : Integer;
Color : Byte;
hRet : HRESULT; begin
X := random (ScreenWidth - 30) + 15;
Y := random (ScreenHeight - 30) + 15;
R := random (10) + 5;
Color := random (256);
// Рисуем окружность в заднем буфере первый раз
hRet := Circle (X, Y, R, Color);
if Failed (hRet) then begin Result := hRet;
Exit;
end;
if FDDSPrimary.Flip(nil, DDFLIP_WAIT) = DDERR_SURFACELOST then begin
hRet := RestoreAll; if Failed (hRet) then begin
Result := hRet;
Exit;
end;
end;
// Рисуем ту же окружность в заднем буфере второй раз Result := Circle (X, Y, R, Color);
end;
Поворот изображения
Такая эффектная операция, как я уже говорил, аппаратно поддерживается далеко не каждой видеокартой. Посмотрим, как можно использовать пикселные операции для осуществления поворота изображения (проект каталога Ех13). На экране вращается жуткое изображение (рис. 3.5).
Не пугайтесь, хоть картинка и страшная, сам пример совершенно безобиден, если только вы не будете лицезреть его работу чересчур долго.
Используется картинка размером 256x256 пикселов, для работы с которыми введен пользовательский тип:
type
TByteArray = Array [0..255, 0..255] of Byte;
Переменная Pict данного типа хранит растровое изображение, а массив заполняется в пользовательской процедуре, вызываемой в начале работы приложения и при каждом восстановлении поверхностей:
function TfrmDD.Prepare : HRESULT; var
desc : TDDSURFACEDESC2;
i, j : Integer;
hRet : HRESULT;
begin
hRet := Clear; // Очистка первичной поверхности
if Failed (hRet) then begin Result := hRet;
Exit;
end;
// Посередине экрана выводится картинка с черепом hRet := FDDSPrimary.BltFast (193, 113, FDDSImage, nil,
DDBLTFAST_WAIT or DDBLTFAST_SRCCOLORKEY);
if Failed (hRet) then begin Result := hRet; Exit;
end;
ZeroMemory (@desc, SizeOf(desc));
desc.dwSize := SizeOf(desc);
// Запираем поверхность
hRet := FDDSPrimary.Lock (nil, desc, DDLOCK_WAIT, 0);
if Failed (hRet) then begin
Result := hRet;
Exit;
end;
// Считываем в массив Pict содержимое нужных пикселов экрана for i := 0 to 255 do
for j := 0 to 255 do
Pict [i, j] := PBYTE (Integer (desc.IpSurface) +
(j + 113) * desc.lPitch + (i + 193)); Result := FDDSPrimary.Unlock (nil);
end;
Заполнить массив можно многими разными способами, например напрямую из растра. Также обращаю внимание, что массив можно заполнять и из содержимого поверхности FDDSImage, без промежуточного блиттинга на первичную. Если ключом является не черный цвет, следует анализировать цвет каждого пиксела и отбрасывать пиксел с цветом ключа, а при использовании черного цвета в качестве ключа можно просто копировать значения пикселов в массив. Так мы будем поступать в последующих примерах.
Переменная Angle хранит текущее значение угла поворота растрового изображения в радианах. Изменяется ее значение при обновлении окна через некоторый промежуток времени:
function TfrmDD.UpdateFrame : HRESULT; var
hRet : HRESULT; begin
Result := DD FALSE;
ThisTickCount := GetTickCount;
if ThisTickCount - LastTickCount > 30 then begin
Angle := Angle +0.1; // Угол в радианах
// Надо уберечься от переполнения
if Angle > 2 * Pi then Angle := Angle - 2 * Pi;
while True do begin
if Failed (Rotating) then begin // Поворот на Angle
hRet := RestoreAll;
if Failed (hRet) then begin // Неустранимая ошибка Result := hRet; Exit; end
end else Break end;
LastTickCount := GetTickCount; end;
Result := DD_OK; end;
Пользовательская функция Rotating, несмотря на свое название, не содержит кода самого поворота картинки, а лишь заменяет содержимое части экрана:
function TfrmDD.Rotating : HRESULT;
var
desc : TDDSURFACEDESC2;
Читать дальше
Конец ознакомительного отрывка
Купить книгу