Выбрать главу

Переходим к очередному примеру - проекту каталога Ех17. Смысл примера состоит в следующем: поместим на переднюю и заднюю поверхности разные образы и с течением времени будем только переключать их, не перерисовывая.

На переднюю поверхность я помещаю растянутую картинку с пейзажем, на задней поверхности (она как раз и является задним буфером) нарисован тот же пейзаж посреди черного поля. Код переключения буферов из обработчика OnPaint формы переместился в обработчик единственного события таймера, а начинается код, связанный с перерисовкой окна, с заполнения переднего буфера:

hRet := FDDSPrimary.Bit (nil, FDDSImage, nil, 0, nil) ;

Эта строка, а также код, связанный с заполнением заднего буфера, может спокойно перекочевать в обработчик OnCreate формы, он в этом примере вызывается и при восстановлении окна.

Чтобы таймер не работал при неактивном состоянии приложения, применяется событие объекта ApplicationEventsi, связанное с "уходом" окна приложения:

procedure TfrmDD.ApplicationEventslDeactivate(Sender: TObject);

begin

Timer1.Enabled := False; // Выключаем таймер Application.Minimize; // Минимизируем приложение

end;

Включается же таймер в обработчике OnCreate, специально для обработки восстановления окна.

Заполнение черным или любым другим цветом поверхности заднего плана для подобных примеров является обязательным. Если этого не делать, то в незаполненных участках буфера будет выводиться "мусор", искаженные следы работы системы с канвой рабочего стола. Если вы удалите этот код, вам может показаться, что все работает прекрасно, но только потому, что перед этим вы запускали приложение, аккуратно заполнившее экран.

Итак, интересен для нас этот несложный пример демонстрацией того, что при переключении буферов их содержимое не теряется, а перекочевывает в следующий буфер. Буферы заполняются при создании и восстановлении окна. В обработчике таймера происходит только переключение буферов.

В рассмотренном примере существуют два буфера. Это обычно для приложений, использующих DirectDraw. Если же буферов больше, то содержимым они меняются по цепочке (рис. 2.4).

Последний пример главы, проект каталога Ех18, на страницах книги разбирать не будем. Проект этот станет для вас полезным тогда, когда вам потребуется код получения информации о системе.

Отладка приложений

Надеюсь, у вас уже выработалась привычка запускать наши проекты, использующие DirectDraw, отдельно от среды Delphi. Полноэкранные приложения на основе DirectDraw тяжело отлаживать так, как вы привыкли это делать с обычными проектами.

Если вы установите точку останова в коде, то при достижении этой строки среда IDE попытается осуществить вывод на занятой поверхности, и ничего хорошего из этого не получится - система может зависнуть.

Ошибки, возникающие при создании и подготовке поверхностей, легко нами обрабатываются. Но как только полноэкранное приложение заняло канву рабочего стола, сообщения, выводимые нашей функцией ErrorOut, просто перестанут быть видны.

У каждого есть свои способы работы в такой ситуации. Я могу порекомендовать свой: пользуйтесь подачей звукового сигнала в тех точках, прохождение которых ставится под вопрос. Если есть сомнения в успешности каких-либо действий, подавайте различные сигналы, в зависимости от значения проверяемого выражения.

В ситуациях, когда такой способ существенно не поможет, придется использовать вывод в файл. Ведите протокол ваших действий, дописывая в отладочный файл информацию о выполненных операциях.

В остальных примерах использования DirectDraw расшифровка произошедшей ошибки будет выводиться в текстовый файл:

procedure TfrmDD.ErrorOut(hRet : HRESULT; FuncName : String);

var

t : TextFile; begin

AssignFile (t, 'Debug.txt');

Rewrite (t);

WriteLn (t, FuncName + ' : ' + DDErrorString (hRet));

CloseFile (t);

Destroy;

end;

Что вы узнали в этой главе

Главное предназначение DirectDraw - вывод содержимого одной поверхности или части поверхности на другую. Поверхностей может быть столько, сколько требуется разработчику, но для построений должна быть, как минимум, одна, первичная поверхность. Первичная поверхность связана с экраном, и пользователь видит то, что в конечном итоге оказывается на ней.

Методы поверхности Bit и BitFast предназначены для осуществления блиттинга - вывода на поверхность.

В построениях, как правило, используется двойная буферизация: вывод осуществляется на поверхность заднего буфера, затем передний и задний буферы меняются местами.

Глава 3 Приемы использования DirectDraw

Цветовой ключ

Полноэкранные приложения

Частичное обновление экрана

Непосредственный доступ к пикселам поверхности

Согласование содержимого буферов

Поворот изображения

Визуальные эффекты

Сохранение растровых изображений

Доступ к пикселам в 16-битном режиме

Полупрозрачность

Выбор объектов

Лупа

Палитры

Оконные приложения

Комбинированные приложения

Осциллограф

Что вы узнали в этой главе

Данная глава является логическим продолжением предыдущей и предлагает описание основных типов приложений, использующих DirectDraw. Рассматриваемые примеры освещают основные приемы, используемые в дальнейших главах, и представляют собой более совершенные проекты.

В главе уделено много внимания вопросам доступа к содержимому поверхности, приводится масса вариантов манипуляции с этим содержимым для создания визуальных эффектов.

Примеры располагаются в каталоге \Examples\Chapter03.

Цветовой ключ

Вы должны четко определить для себя, что DirectDraw предназначен главным образом для быстрой смены растровых изображений на экране и ограничен по своим возможностям в действиях с канвой формы. Здесь нет каких-либо примитивов, команд рисования кругов, отрезков и т. п. В случае крайней необходимости можно использовать команды вывода GDI, но их желательно избегать, поскольку они слишком медленны для обычных методов DirectDraw.

Но если использовать только блиттинг прямоугольных блоков, то получается, что мы имеем дело лишь с прямоугольными вставками. Как же тогда рисуются картинки сложной формы, мы узнаем в этом разделе.

DirectDraw предоставляет на этот случай элегантный механизм, называемый цветовым ключом (color key). Заключается этот механизм в том, что оговариваемый цвет становится при выводе поверхности прозрачным.

Нам известны два метода для блиттинга. Посмотрим, как цветовой ключ может использоваться для метода BitFast, который мы стараемся использовать всегда, когда нам это позволительно.

В проекте каталога Ex01 в качестве фона используется знакомая нам по предыдущим примерам картинка. На ее фоне двигается стрелка, положение которой управляется мышью (рис. 3.1). Фактически, здесь мы заменили вид курсора приложения.

В примере используется две вторичных поверхности: одна для вывода фона, другая - для хранения растра курсора:

FDDSBackGround : IDirectDrawSurface7; FDDSImage : IDirectDrawSurfaceV;

Для загрузки растров необходима пользовательская функция DDLoadBitmap:

// Обратите внимание, что загружаемый растр растягивается FDDSBackGround := DDLoadBitmap(FDD, groundBmp, ScreenWidth,

ScreenHeight); // Загружаем фоновое изображение

if FDDSBackGround = nil then ErrorOut(DD_FALSE,DDLoadBitmap');

// Загружаем изображение со стрелкой

FDDSImage := DDLoadBitmap (FDD, imageBmp, 0, 0);

if FDDSImage = nil then ErrorOut (DD_FALSE, 'DDLoadBitmap1);

После создания поверхности FDDSImage и загрузки в нее растра задаем цветовой ключ, используя вспомогательную функцию модуля DDUticlass="underline"