Чтение онлайн

ЖАНРЫ

Графика DirectX в Delphi

Краснов Михаил

Шрифт:

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

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

строкой переключение осуществить не удастся. Также при каждом переключении надо повторять все действия деактивации диалога с DirectDraw.

Вот и все тонкости, которые связаны с комбинированными приложениями, можем переходить к иллюстрации - проекту каталога Ех29. Этот пример является моим переложением на Delphi программы из пакета DirectX 7.0 SDK. Работа приложения очень простая: по экрану перемещается одинокий кружок, отскакивающий от границ окна подобно бильярдному шару. Приложение запускается в полноэкранном режиме, но в любой момент работы программы можно переключиться в альтернативный режим, нажав комбинацию клавиш <Alt>+<Enter>, о чем информирует пользователя подсказка, располагающаяся в левом верхнем углу экрана (рис. 3.14).

Для упрощения кодирования поведения кружочка окно приложения устанавливаем 640x480 пикселов и не допускаем изменения его размеров:

procedure TfrmDD.FormCanResize(Sender: TObject; var NewWidth,

NewHeight: Integer; var Resize: Boolean);

begin

Resize := False; // Запрещаем любые изменения размеров окна

end;

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

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

// Круг рисуется средствами GDI, вписанным в квадрат

xl : Integer =0; // Левый верхний угол квадрата

yl : Integer = 0;

х2 : Integer =40; // Правый нижний угол квадрата

у2 : Integer = 40;

xDir : Integer =4; // Текущее приращение координаты X

yDir : Integer =4; // Текущее приращение координаты Y

rcScreen : TRECT; // Позиция окна, используется для оконного режима

rcViewport : TRECT; // Область вывода, 640x480

rcWindow : TRECT; // Структура для хранения позиции окна на экране

flgWindowed : BOOL = False; // Текущий режим работы приложения

Код обработчика создания окна будет вызываться при каждом переключении режима:

procedure TfrmDD.FormCreate(Sender: TObject);

var

hRet : HRESULT;

begin

// Обнуляем все объекты DirectDraw

FDDClipper := nil; // Объект отсечения будет удаляться дважды,

FDDSBack := nil; // можно этого и не выполнять, но для корректности

FDDSPrimary := nil; // первого вызова FormCreate

лучше все-таки сделать

FDD := nil;

//В зависимости от режима задаем стиль рамки и видимость курсора

if flgWindowed then begin

BorderStyle := bsSizeable; // Обычный стиль, с областью заголовка

ShowCursor(True);

end

else begin

BorderStyle := bsNone; // Без рамки и области заголовка

ShowCursor(False);

end;

// Создается главный объект DirectDraw

hRet := DirectDrawCreateEx (nil, FDD, IDirectDraw7, nil);

if Failed(hRet) then ErrorOut(hRet, 'DirectDrawCreateEx');

// Инициализация поверхностей

if Failed (InitSurfaces(Handle)) then Close;

FActive := True;

end;

Процедура инициализации поверхностей объединяет в себе оба подхода, изученные нами для полноэкранного и оконного режимов:

function TfrmDD.InitSurfaces(Window : THandle) : HRESULT;

var

hRet : HRESULT;

ddsd : TDDSURFACEDESC2;

ddscaps : TDDSCAPS2;

p : TPoint;

begin

if flgWindowed then begin // Оконный режим

// Получить обычный доступ

hRet := FDD.SetCooperativeLevel(Window, DDSCL_NORMAL);

if Failed(hRet) then begin Result := hRet;

ErrorOut(hRet, 'SetCooperativeLevel');

Exit;

end;

// Получаем размеры области вывода и границы экрана

Windows.GetClientRect(Window, rcViewport);

Windows.GetClientRect(Window, rcScreen);

// Находим позицию клиентской области окна на экране

р.Х := rcScreen.Left;

p.Y := rcScreen.Top;

Windows.ClientToScreen(Window, p);

OffsetRect(rcScreen, p.X, p.Y);

// Создаем первичную поверхность

ZeroMemory(@ddsd, SizeOf(ddsd));

with ddsd do begin

dwSize := SizeOf(ddsd);

dwFlags := DDSD_CAPS;

ddsCaps.dwCaps := DDSCAPS_PRIMARYSURFACE;

end;

hRet := FDD.CreateSurface(ddsd, FDDSPrimary, nil);

if Failed(hRet) then ErrorOut(hRet, 'CreateSurface FAILED');

// Для оконного приложения создаем объект отсечения

hRet := FDD.CreateClipper(0, FDDClipper, nil);

if Failed(hRet) then ErrorOut(hRet, 'CreateClipper FAILED');

// Ассоциируем отсечение с окном приложения

FDDClipper.SetHWnd(0, Window);

FDDSPrimary.SetClipper(FDDClipper) ;

FDDClipper := nil;

// Создаем поверхность заднего буфера, непосредственного вывода with ddsd do begin

dwFlags := DDSD_WIDTH or DDSD_HEIGHT or DDSD_CAPS;

dwWidth := 640;

dwHeight := 480;

ddsCaps.dwCaps := DDSCAPS_OFFSCREENPLAIN;

end;

hRet := FDD.CreateSurface(ddsd, FDDSBack, nil);

if Failed(hRet) then ErrorOut(hRet, 'CreateSurface2 FAILED');

end

else begin // Полноэкранный режим

// Задаем режим исключительного доступа

hRet := FDD.SetCooperativeLevel(Window, DDSCL_EXCLUSIVE or

DDSCL_FULLSCREEN);

if Failed(hRet) then ErrorOut(hRet, 'SetCooperativeLevel FAILED')

Поделиться с друзьями: