Графика DirectX в Delphi
Шрифт:
Целочисленная переменная kr задает текущую незатемняемую палитру и изменяется от шестнадцати до двух, уменьшаясь на каждом шаге:
function TfrmDD.UpdateFrame : HRESULT;
var
k : Integer;
DefPal : Array[0..255] of TPaletteEntry; // Массив цветов палитры
hRet : HRESULT;
begin
ThisTickCount := GetTickCount;
if ThisTickCount - LastTickCount > 10 then begin
// Берем текущую палитру
hRet := FDDPal.GetEntries(0, 0, 256, SDefPal);
if Failed (hRet) then begin Result := hRet;
Exit;
end;
for k := 0 to 14 do begin //
DefPal [kr * 15 + k].peBlue := 0;
DefPal [kr * 15 + k].peRed := 0;
DefPal [kr * 15 + k].peGreen := 0;
end;
Dec (kr); // Переходим к следующему цвету палитры
if kr < 2 then kr := 16;
for k := 0 to 14 do begin // Подменяем текущий цвет желтоватым
DefPal [kr * 15 + k].peBlue := 0;
DefPal [kr * 15 + k].peRed :== 128;
DefPal [kr * 15 + k].peGreen := 100;
end;
// Устанавливаем измененную палитру
hRet := FDDPal.SetEntries(0, 0, 256, @DefPal);
if Failed (hRet) then begin Result := hRet;
Exit;
end;
LastTickCount := GetTickCount;
hRet := FDDSPrimary.Flip(nil, DDFLIP_WAIT);
if Failed (hRet) then begin Result := hRet;
Exit;
end;
end;
Result := DD_OK;
end;
Обратите внимание, что при запуске и восстановлении приложения появляется первоначальная фоновая картинка, поскольку затеняются "ненужные" цвета палитры только после первого прохождения значения kr по кругу.
Оконные приложения
Вы, должно быть, уже привыкли к тому, что наши примеры работают в полноэкранном режиме. Обычно оконные приложения создаются в DirectDraw только в случае крайней необходимости, т. к. слишком многое мы теряем при его использовании. Главная потеря здесь - скорость работы приложения.
Скорость воспроизведения, в общем случае, выше у полноэкранных приложений. Конечно же, при отображении небольшого числа блоков в маленьком окне вы сможете добиться очень высокой скорости.
Для оконных приложений нельзя использовать переключение страниц или двойную буферизацию.
По своей сути, оконные приложения похожи на наши самые первые примеры, с выводом кружка на поверхности окна. Точно так же первичной поверхностью является весь рабочий стол экрана, и приложение должно отслеживать положение окна.
Рассмотрим простейший пример, располагающийся в каталоге Ех25. Работа его совсем проста, в пределах окна
Свойство Borderstyle формы приняло теперь свое обычное значение bssizeabie, удалены единственный компонент и все, связанное с курсором. Не можем мы также здесь задавать параметры экрана и устанавливать исключительный уровень кооперации, поскольку для оконных приложений задается обычный уровень доступа:
hRet := FDD.SetCooperativeLevel(Handle, DDSCL_NORMAL);
Появился обработчик перерисовки окна, в котором определяем текущее положение окна приложения и выводим на него масштабированный растр:
procedure TfrmDD.FormPaint(Sender: TObject);
var
rcDest : TRECT;
p : TPOINT; // Вспомогательная точка для определения положения окна begin
р.Х := 0;
p.Y := 0;
// Находим положение на экране точки левого верхнего угла
// клиентской части окна приложения
Windows.ClientToScreen(Handle, p);
// Получаем прямоугольник размерами клиентской части окна
Windows.GetClientRect(Handle, rcDest);
OffsetRect(rcDest, p.X, p.Y); // Сдвигаем прямоугольник на р.Х, p.Y
if Failed (FDDSPrimary.Blt (@rcDest, FDDSBackGround, nil,
DDBLT_WAIT, nil)) // Выводим растр then RestoreAll;
end;
Перед именами некоторых процедур я указал, что имеются в виду процедуры именно модуля windows. Если для вас привычнее использовать аналогичные методы формы, то эти строки можете записать так:
р := ClientToScreen(р); rcDest := GetClientRect;
Хоть в рассматриваемом примере и приходится следовать рекомендациям разработчиков, пытаясь восстанавливать все поверхности в случае неудачи при воспроизведении, но сделано это большей частью формально. Если по ходу приложения поменять установки экрана, то оно не сумеет восстановить первичную поверхность. Это не является недостатком конкретно нашего примера. Точно так же ведут себя все оконные приложения, использующие DirectDraw.
Если вы внимательно посмотрите на работу приложения, то должны заметить, как плохо масштабируется картинка при изменении размеров окна. Для более удовлетворительной работы обработчик этого события должен вызывать код перерисовки окна.
Оконное приложение может рисовать в любом месте рабочего стола. Малейшая ошибка в коде приведет к очень некрасивым результатам. Обычно такие приложения ограничивают область вывода, для чего используется объект класса IDirectDrawClipper.
Посмотрим проект каталога Ех2б, в коде модуля которого появилась переменная FDDCiipper такого типа. В начале и конце работы приложения ее значение, как принято, устанавливается в nil.