Графика DirectX в Delphi
Шрифт:
for j := 0 to 255 do
PByte (Integer (desc.IpSurface) + (j + 113) * desc.lPitch +
i + 193)Л := Image [i, j]; Result := FDDSPrimary.Unlock (nil);
end;
Самая интересная функция примера - пользовательская функция, возвращающая растр, повернутый на заданный угол относительно указанной точки:
function TfrmDD.Rotate (const pictOriginal : TByteArray; // Исходный растр
// Точка в растре, задающая оси поворота
const iRotationAxis, jRotationAxis: Integer;
const ug : Single): TByteArray; //
type // Тип, соответствующий одной строке массива
wrkByteArray = Array [0..255] of Byte;
var
i, j :Integer;
iOriginal: Integer;
iPrime: Integer;
jOriginal: Integer;
jPrime: Integer;
RowOriginal :^wrkByteArray;
RowRotated :^wrkByteArray;
sinTheta :Single;
cosTheta :Single;
begin
sinTheta := sin(ug); // Для оптимизации синусы и косинусы
cosTheta := cos(ug); // Запоминаем в рабочих переменных
for j := 255 downto 0 do begin // Строки результирующего массива
RowRotated := @result [j, 0]; // Указатель на очередную строку
jPrime := j - jRotationAxis; // Смещение от оси по Y
for i := 255 downto 0 do begin // Цикл по столбцам
iPrime := i - iRotationAxis; // Смещение от оси по X
iOriginal := iRotationAxis + trunc(iPrime * cosTheta -
jPrime * sinTheta); // Координаты нужной точки по X
jOriginal := JRotationAxis + trunc(iPrime * sinTheta +
jPrime * cosTheta); // Координаты нужной точки по Y
// После поворота некоторые точки на границе
//не имеют аналога в старом растре
if (iOriginal >= 0) and (iOriginal <= 255) and // He границы
(jOriginal >= 0) and (jOriginal <= 255) then begin
// Копируем в новый растр точку RowOriginal := SpictOriginal[jOriginal, 0];
RowRotated'^ [i] := RowOriginal^[iOriginal]
end
else RowRotated[i] := 0; // Границы заполняем черным цветом
end
end;
end;
В этом и следующем примерах я не применяю двойную буферизацию. Если же с использованием вашей видеокарты по этой причине шоу разворачивается слишком медленно, в качестве упражнения установите двойную буферизацию.
Визуальные эффекты
В данном разделе мы закрепим наши навыки непосредственного доступа к пикселам и научимся создавать некоторые несложные эффекты.
В проекте каталога Ех14 выводится тот же образ, что и в предыдущем примере, но уже весь покрытый "перцем", подобно изображению плохо настроенного телевизора (рис. 3.6).
Добиться
function TfrmDD.Effect : HRESULT; var
desc : TDDSURFACEDESC2;
i, j : Byte;
Image : TByteArray; // Вспомогательный массив,
// размеры равны размеру растра k : Integer; hRet : HRESULT;
begin
Result := DD_FALSE; ZeroMemory (@desc, SizeOf(desc)); desc.dwSize := SizeOf(desc);
// Локальные массивы надо всегда инициализировать ZeroMemory (@Image, SizeOf (Image));
for k := 0 to 100000 do begin // Верхний предел задает густоту перца
i := random (255); // Можно брать и меньший интервал
j := random (255); // Растр занимает не всю область 256x256
Image [i, j] := Pict [i, j]; // Берем точку растра
end;
hRet := FDDSPrimary.Lock (nil, desc, DDLOCK_WAIT, 0}; if Failed (hRet) then begin
Result := hRet;
Exit;
end;
for i := 0 to 255 do
for j := 0 to 255 do
PByte (Integer (desc.IpSurface) + (j + 113) * desc.lPitch + i + 193)^ := Image [i, j];
Resuit := FDDSPrimary. Unlock (nil) ;
end;
Надеюсь, все просто и понятно, и в качестве упражнения модифицируйте пример таким образом, чтобы густота перца менялась с течением времени.
Двигаемся дальше. Рассмотрим проект каталога Ех15 - простой пример на смешивание цветов. Посередине экрана выводится картинка размером 64x64 пикселов, при обновлении кадра вызывается пользовательская процедура, усредняющая цвет для каждого пиксела внутри области растра. Для усреднения берется девять соседних точек:
function TfrmDD.Blend : HRESOLT;
var
desc : TDDSURFACEDESC2 ;
i, j : Byte;
Pict : Array [0..63, 0..63] of Byte;
hRet : HRESULT;
begin
ZeroMemory (@desc, SizeOf(desc)); desc.dwSize := SizeOf(desc);
hRet := FDDSBack.Lock (nil, desc, DDLOCK_WAIT, 0); if Failed (hRet) then begin
Result := hRet;
Exit;
end;
//Во вспомогательный массив заносится область растра for i := 0 to 63 do
for j := 0 to 63 do
Pict [i, j] := PBYTE (Integer (desc.IpSurface) +
(j + 208) * desc.lPitch + (i + 288) P;
// Для каждой точки внутри области растра значение пиксела берется // усредненным значением девяти окружающих точек
for i := 1 to 62 do
for j := 1 to 62 do
PByte (Integer (desc.IpSurface) +
(j + 208) * desc.lPitch + i + 288)^ := (Pict [i - 1, j - 1] +
Pict [i, j - i] +
Pict [i + 1, j - 1] +
Pict [i - 1, j] +
Pict [i, j] +