Графика DirectX в Delphi
Шрифт:
Первичная поверхность в нашей программе является канвой рабочего стола, так мы сами задали ее свойства. Поэтому канва связана с областью всего экрана, и прямоугольник, ограничивающий кружок, мы задаем в координатах рабочего стола, а не в координатах окна приложения. Затем мы освобождаем память и контекст вывода. Это действие является предельно важным. Если его не выполнить, то приложение просто закроет доступ к рабочему столу для всех остальных приложений и для операционной системы. Страшная ситуация!
Поработайте с проектом. При перемещении окна все работает так, как мы того ожидаем, но вот если размеры окна сделать слишком маленькими, то кружок
Мы подходим к очень важным вопросам, специфичным именно для DirectDraw. Ситуацию, когда приложение временно убирается с экрана, а затем восстанавливается, необходимо в приложениях фиксировать.
Посмотрите проект каталога Ех03, в котором отслеживается ошибка, возникающая при такой ситуации, и пользователю выдается осмысленное сообщение (рис. 2.1).
Код ошибки - DDERR_SURFACELOST. Как сообщается в его расшифровке, в таком случае необходимо использовать метод Restore поверхности.
Пример делает прозрачным причины потери поверхности. Первичную поверхность мы связали с рабочим столом, и, конечно, после того, как окно "ушло" с экрана, оно освободило память поверхности для других приложений. Теперь ему надо заново вернуть свои исключительные права на область памяти. Такая же ситуация возникает при изменении параметров рабочего стола по ходу работы приложения.
Также многие из функций DirectDraw могут вернуть код ошибки DDERR_WASSTILLDRAWING, означающий, что аппаратное обеспечение занято и запрос необходимо повторять до тех пор, пока не добьемся успеха или не получим иного сообщения об ошибке.
Взгляните на проект каталога Ех04, здесь решены все эти проблемы, и первое, что изменилось, - это код, связанный с перерисовкой окна. Теперь код собственно воспроизведения заключен внутрь цикла, из которого мы выходим либо в случае успешного воспроизведения, либо если поверхность восстановить не удается, либо код ошибки отличен от DDERR_WASSTILLDRAWING:
while True do begin возможно, // Код придется повторять неоднократно
hRet := FDDSPrimary.GetDC(DC); // Заново получаем дескриптор
if Succeeded (hRet) then begin
wrkCanvas := TCanvas.Create;
wrkCanvas.Handle := DC; wrkCanvas.Ellipse (Left + 50, Top + 50, Left + 100, Top + 100);
wrkCanvas.Free; FDDSPrimary.ReleaseDC (DC); Break;
end;
// Поверхность потеряна, надо восстановить if hRet = DDERR_SURFACELOST then begin
hRet := FDDSPrimary._Restore;
// Если не удалось восстановить, дальше продолжать нельзя
if hRet <> DD_OK then Break; end;
// Ошибка отлична от DDERR_WASSTILLDRAWING, следовательно непоправима if hRet <> DDERR_WASSTILLDRAWING then Break;
end;
Чтобы кружок не рисовался за пределами окна приложения, можно просто не разрешать уменьшать высоту окна. Таким образом, появился обработчик
события OnCanResize:
procedure TfrmDD.FormCanResize(Sender: TObject; var NewWidth,
NewHeight: Integer; var Resize: Boolean); begin
if NewHeight < 110 //
Высота окна не должна быть меньше 110then Resize := False
else Resize := True;
end;
Что еще надо сделать, так это при обработке события OnResize окна вызывать тот же код, что и при событии OnPaint.
Для обработки тех ситуаций, когда восстановить поверхность не удается, в проект добавлен компонент класса TAppLicationEvents, на события OnActivate и onRestore которого вызывается такой же код, как и при создании окна. То есть при восстановлении минимизированного окна и каждой активизации окна приложения заново создаем первичную поверхность.
Хорошенько поработайте с проектом: протестируйте его работу в самых различных ситуациях, минимизируйте и восстанавливайте окно, активизируйте самыми различными способами, поменяйте установки экрана по ходу работы этого приложения. Кружок должен появляться всегда, когда мы его ожидаем. При деактивизации окно может вести себя непривычно для обычных приложений, можете записать Application.Minimize в обработчике события OnDeactivate единственного компонента проекта. Восстанавливается окно тоже особым образом, распахиваясь на весь экран.
Такое использование полноэкранной первичной поверхности, как в этом примере, когда воспроизведение осуществляется только функциями GDI в пределах окна приложения, редко применяется в практических задачах.
В примере есть небольшое упрощение. Так как при восстановлении окна приложения и его активизации (пользователь переходит на него с помощью комбинации клавиш <Alt>+<Tab>) поверхность создается заново, то она никогда не будет потеряна. Такой прием можно использовать только для простейших приложений, поскольку весьма неэкономно тратить время подготовки работы при каждой активизации приложения.
Блиттинг
Блиттингом называется копирование графических изображений в память видеоустройств, и DirectDraw представляет собой просто механизм блиттинга.
Начнем знакомство с этим механизмом с помощью проекта каталога Ех05. Пример является продолжением предыдущей программы. Первичная поверхность все также полноэкранная, на нее с помощью вспомогательной канвы выводится растровое изображение. Это изображение, используемое здесь и во многих последующих примерах, взято из DirectX SDK производства Microsoft. Содержит эта картинка потрясающий по своей красоте пейзаж.
Главное отличие данного примера от предыдущего состоит в том, что поверхность, служащая фоном нашего растра, закрашивается. Работа приложения теперь выглядит естественной для полноэкранных приложений вообще, и для приложений, использующих DirectDraw, в частности.
Поскольку это полноэкранное приложение, то обработчики событий OnCanResize и OnResize ему не нужны. Не пропустите также, что свойство Borderstyle формы я установил в bsNone. Это важно, если этого не сделать, то приложение будет работать прекрасно, но при движении курсора вблизи границ экрана и в районе системного заголовка окна приложения сквозь "экран" будет проглядывать другое окно. Обязательно проверьте это, вернув обычное значение указанного свойства формы. Полноэкранная поверхность занимает рабочий стол, загораживает собой все окна, но они продолжают реагировать на поступающие им сообщения.