KnigaRead.com/

Михаил Краснов - Графика DirectX в Delphi

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Михаил Краснов, "Графика DirectX в Delphi" бесплатно, без регистрации.
Перейти на страницу:

Начнем знакомство с этим механизмом с помощью проекта каталога Ех05. Пример является продолжением предыдущей программы. Первичная поверхность все также полноэкранная, на нее с помощью вспомогательной канвы выводится растровое изображение. Это изображение, используемое здесь и во многих последующих примерах, взято из DirectX SDK производства Microsoft. Содержит эта картинка потрясающий по своей красоте пейзаж.

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

Поскольку это полноэкранное приложение, то обработчики событий OnCanResize и OnResize ему не нужны. Не пропустите также, что свойство Borderstyle формы я установил в bsNone. Это важно, если этого не сделать, то приложение будет работать прекрасно, но при движении курсора вблизи границ экрана и в районе системного заголовка окна приложения сквозь "экран" будет проглядывать другое окно. Обязательно проверьте это, вернув обычное значение указанного свойства формы. Полноэкранная поверхность занимает рабочий стол, загораживает собой все окна, но они продолжают реагировать на поступающие им сообщения.

Чтобы при восстановлении приложения его окно появлялось распахнутым на весь экран, появился обработчик события onRestore компонента

ApplicationEventsL:


procedure TfrmDD.ApplicationEventslRestore(Sender: TObject);

begin

WindowState := wsMaximized; end;

Следует задавать это свойство именно динамически, т. е. принудительно распахивать окно при каждом его восстановлении.

Главные изменения коснулись кода, связанного с перерисовкой окна. Часть кода, предназначенную для вывода изображения, рассматривать не будем. Здесь ничего нового для нас нет. Посмотрим внимательно на то, что ему предшествует, а именно на заполнение фона черным цветом. Кстати, обратите внимание, что порядок действий такой: закрашиваем фон, на закрашенный фон выводим растр. Замечу, что работа с растром в примере выполнена не оптимально, растр загружается при каждой перерисовке окна. Пока наши примеры очень просты и вполне терпят подобное, но при интенсивной работе с растровыми изображениями, конечно, так писать программы не будем.

Процедура обработчика перерисовки окна имеет локальную вспомогательную переменную ddbltfx типа TDDBLTFX, который представляет собой запись И является вспомогательным, подобным использованному нам при создании поверхности типу TDDSurfaceDesc2, но применяется лишь для задания параметров блиттинга. Поля этой структуры мы изучим по ходу дальнейшего изложения. Пока ограничимся тем, что значение поля dwFillcoior задает цвет заполнения поверхности. Как указывалось ранее, работа с подобными структурами начинается с обнуления всех полей и задания ее размера указанием значения поля dwSize:


ZeroMemory(@ddbltfx, SizeOf (ddbitfx)); // Обнуляем все поля

ddbitfx.dwSize := SizeOf (ddbitfx); // Обязательно задаем размер

ddbitfx.dwFillColor := 0; // Цвет заполнения - черный

Для блиттинга используем метод Bit первичной поверхности:


hRet := FDDSPrimary.Blt(nil, nil, nil, DDBLT_COLORFILL or DDBLT_WAIT, @ddbltfx);


Первым трем аргументам присваиваем значение nil (смысл их раскроим позже). Четвертый аргумент метода является битовым флагом: у нас это комбинация двух констант. Константа DDBLT_WAIT задает режим ожидания для вывода. В этом режиме вывод станет осуществляться, когда устройство будет готово к нему, и поэтому метод не возвратит никогда значение

DDERR_WASSTILLDRAWING. Флаг DDBLT_COLORFILL сообщает методу Blt о том, что вместо блиттинга выполняется цветовое заполнение. Последний аргумент указывает адрес переменной, хранящей параметры блиттинга.

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


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


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

Переходим к иллюстрации - проекту каталога Ех06. От предыдущего он отличается только тем, что код обработчика onCreate формы дополнился строками:


hRet := FDD. SetDisplayMode (640, 480, 16, 0, 0); // Задаем режим

if hRet <> DD_OK then begin // Обязательно анализируем результат

ErrorOut (hRet, ' SetDisplayMode ') ;

Exit ; end;

Установка режима является методом главного объекта, поэтому должна происходить строго после его создания, но не обязательно первым же действием. Первые три аргумента метода, надеюсь, сразу же ясны: высота, ширина экрана и разрешение (число бит, необходимых для определения цвета пиксела). Последние два аргумента метода всегда будем задавать нулевыми. Первый из них определяет частоту регенерации. При нулевом значении параметра отдается на усмотрение DirectDraw. Последний аргумент задает дополнительные флаги, пока из них доступен только DDSDM_STANDARDVGAMODE, связанный с особым режимом Mode X (320x200x8).

Итак, на время работы приложения мы задаем режим 640x480x16. Эта тройка чисел не может браться наобум, а должна принадлежать набору поддерживаемых системой режимов.


Запустив утилиту диагностики DirectX, вы можете найти список поддерживаемых режимов.

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

Обратите внимание, что нет необходимости по окончании работы приложения возвращаться к режиму, установленному пользователем. Это произойдет автоматически.

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

Раздел private описания класса формы дополнился строкой объявления дополнительной поверхности, предназначенной для хранения образа:


FDDSImage : IDirectDrawSurface7;

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


if Assigned(FDD) then begin

if Assigned(FDDSImage) then FDDSImage := nil; // Перед первичной

if Assigned(FDDSPrimary) then FDDSPrimary := nil; // поверхностью

FDD := nil

end;


Растровое изображение считывается только один раз. У обработчика OnCreate появился вспомогательный объект wrkBitmap класса TBitmap. Вторичная поверхность создается после первичной и заполняется считанным растром:


wrkBitmap := TBitmap.Create; // Создание объекта растра

wrkBitmap.LoadFromFile ('..lake.bmp'); // Считывание файла растра // Напоминаю, что обнулять поля можно и с помощью ZeroMemory FillChar (ddsd, SizeOf(ddsd), 0} ; with ddsd do begin // Как для любой записи, можно использовать with

dwSize := SizeOf(ddsd); // Обязательное действие

// Будем задавать размеры поверхности (+ DDSDJiEIGHT и DDSD_WIDTH)

dwFlags := DDSD_CAPS or DDSD_HEIGHT or DDSD_WIDTH;

ddsCaps.dwCaps := DDSCAPS_OFFSCREENPLAIN; // Внеэкранная поверхность

dwWidth := wrkBitmap.Width; // Ширина поверхности равна ширине растра

dwHeight := wrkBitmap.Height; // Задаем высоту поверхности end; // with

// Собственно создание вспомогательной поверхности

hRet := FDD.CreateSurfасе(ddsd, FDDSImage, nil);

if hRet <> DD_OK then begin // Анализируем на предмет успешности

ErrorOut(hRet, 'Create Image Surface');

Exit;

end;


// Копирование растра из wrkBitmap во вспомогательную поверхность

hRet := DDCopyBitmap (FDDSImage, wrkBitmap.Handle, 0, 0, wrkBitmap.Width,

wrkBitmap.Height);

if hRet <> DD_OK then begin // Обязательно анализируем результат

ErrorOut(hRet, 'DDCopyBitmap');

Exit;

end;


// Удаление вспомогательного объекта wrkBitmap.Free;


Вспомогательная, внеэкранная поверхность Foosimage создается с описанием DDSCAPSJDFFSCREENPLAIN. Здесь есть некоторые нюансы, но пока рассматривать их не будем.

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

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

Вспомогательная поверхность создана и заполнена растром размером 256x256 пикселов. Среди аргументов операции блиттинга присутствуют структуры типа TRECT, задающие местоположение в принимающей поверхности и копируемую область. Поэтому код обработчика перерисовки окна дополнился переменными dstRect и srcRect типа TRECT. Заполняем их поля с помощью API-функции setRect:

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*