VR
Virtual Reality On-line   Журнал
Новости   |     Журнал    |    Хаkер    |     Магазин   |   Проекты
[   Вход    ]
[Kарта сайтa]

[ Download  ]
[  Конкурс  ]
[ Анекдоты  ]
[  Ссылки   ]
[  Реклама  ]
[ Почтальон ]
[ О проекте ]






TopList
Геймер.
Программирование с помощью Direct Draw
:

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

Мы остановились на том, что запустили в работу DirectDraw. После этого нет никаких заданий, поэтому программа выдаст сообщение OnIdlе. Как я уже говорил, это сообщение генерируется каждый раз, когда программе нечего делать. Мы создали обработчик этого события, поэтому посмотрим, что в нём происходит:

procedure TForm1.ProgIdle(Sender: TObject; var Done: Boolean);
var
 hr: HResult;
begin
 Done := False;
 Drawer;

 while (True) do
  begin
   hr := FPrimarySurface.Flip(nil, 0);
   if (hr = DD_OK) then break;

   if(hr = DDERR_SURFACELOST) then
    hr := FPrimarySurface.Restore();

    if(hr <> DDERR_WASSTILLDRAWING) then break;
  end;
end;

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

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

function Flip(
lpDDSurfaceTargetOverride: IDirectDrawSurface;
dwFlags: DWORD): HResult; stdcall;

lpDDSurfaceTargetOverride - адрес структуры, описывающей поверхность. Именно эта поверхность станет первичной. Если этот параметр = nil, то поверхности будут переключаться циклически.

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

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

Если произошла ошибка DDERR_SURFACELOST, то значит поверхность потеряна. Это происходит, когда ты сворачиваешь окно или каким либо другим способом отдаёшь управление другой программе. Это происходит из-за того, что DirectDraw использует монопольный режим. Как только другое приложение получило возможность вывода, оно разрушает поверхности DirectDraw. Если это произошло, то я использую функцию FPrimarySurface.Restore(), которая восстанавливает поверхности. Если ты используешь палитру, то её тоже надо восстановить.

Если произошла ошибка DDERR_WASSTILLDRAWING, то это значит, что поверхность ещё рисуется. Нельзя рисовать следующую поверхность, пока не прорисовалась эта.

Теперь давай перейдём к процедуре Drawer.

procedure TForm1.Drawer;
var
 DC: HDC;
begin
 if (FBackSurface.GetDC(DC) = DD_OK) then
  begin
   DrawShape(DC);
   FBackSurface.ReleaseDC(DC);
  end;
end;

FBackSurface.GetDC - возвращает контекст рисования на вторичном буфере.

DrawShape -вызываю функцию, которая рисует на вторичном буфере.

FBackSurface.ReleaseDC(DC) -Уничтожаю контекст рисования.

И на последок у нас осталась только одна функция - DrawShape, которая непосредственно рисует фигуры. В этой процедуре я рисую средствами Windows. Мы с тобой уже рисовали на контексте устройства, поэтому следующие функции я не буду подробно описывать.

procedure TForm1.DrawShape(var DC: HDC);
var
 Brush, OldBrush: HBrush;
begin
//Создаю временную кисть чёрного цвета.
Brush := CreateSolidBrush(RGB(0, 0, 0));
// Выбираю её в контекст
OldBrush := SelectObject(DC, Brush);

//Рисую квадрат. Во всех последующих проходах, этот квадрат
//будет зарисовывать старое изображение.
Rectangle(DC, FRect.left, FRect.top,FRect.left+30, FRect.top+30);
//Востанавливаю старую кисть
SelectObject(DC, OldBrush);
//Уничтожаю временную кисть
DeleteObject(Brush);

//Изменяю положение квадрата
FRect.left := FRect.Left + FXAdd;
FRect.Top := FRect.Top + FYAdd;

//Проверяю на выход за пределы экрана
if (FRect.left+50 > 795) then FXAdd := -2;
if (FRect.left < 3) then FXAdd := 2;
if (FRect.Top+50 > 595) then FYAdd := -2;
if (FRect.Top < 3) then FYAdd := 2;

//Создаю новую кисть и рисую квадрат в новом месте.
Brush := CreateSolidBrush(RGB(200,10,10));
OldBrush := SelectObject(DC, Brush);
Rectangle(DC, FRect.left, FRect.top,FRect.left+30, FRect.top+30);
SelectObject(DC, OldBrush);
DeleteObject(Brush);
end;

Со всем, что здесь происходит ты можешь разобраться по комментариям. Остаётся разобраться только с деструктором. При закрытии окна вызывается следующая процедура:

procedure TForm1.FormDestroy(Sender: TObject);
begin
 if(FDirectDraw <> nil) then
  begin
   FDirectDraw.FlipToGDISurface;
   FDirectDraw.SetCooperativeLevel(Handle, DDSCL_NORMAL);
   if FBackSurface <> nil then FBackSurface := nil;
   if FPrimarySurface <> nil then FPrimarySurface := nil;
   FDirectDraw := nil;
  end;
end;

FDirectDraw.FlipToGDISurface Отключает DirectDraw поверхности, делая поверхность GDI (в этой поверхности рисует Windows) первичной.

SetCooperativeLevel - выставляю нормальный режим.

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

Удачи тебе.

 Исходники примера забирай здесь


Design by FMk group ©
Copyright©: Horrific aka Флёнов Михаил ©