VR
Virtual Reality On-line   DirectX
Новости   |     Журнал    |    Хаkер   |     Магазин   |   Проекты
[   Вход    ]
[Kарта сайтa]
[ Download  ]
[  Конкурс  ]
[  Анекдоты ]
[  Ссылки   ]
[  Реклама  ]
[ Почтальон ]
[ О проекте ]






TopList
DirectX.
Приёмы работы с прямым доступом к памяти
:

В журнале ][ я описал теорию прямого доступа к памяти, да и на этом сайте ты найдёшь статью по этой теме. Здесь же я хочу показать на практике некоторые приёмы анимации с помощью этого нехитрого приёма.

Возьмём пример из предыдущего номера ][, статьи "Первая анимация" и дополним его графическими эффектами. Открой тот пример в Delphi и найди в процедуре WindowProc код вывода фонового изображения на экран:

FBackgroundSurface.BltFast (175, 75, FImageSurface, nil, DDBLTFAST_WAIT);

Модернизируем этот код следующим образом.


//Обнуляю структуру desk
ZeroMemory (@desc, SizeOf(desc));
desc.dwSize := SizeOf(desc);

//Блокирую поверхность
hRet:=FImageSurface.Lock(nil, desc, DDLOCK_WAIT, 0);

//Засыпаем поверхность белым цветом
for i:=0 to 10 do
 PWord (Integer(desc.lpSurface) + random(450) * desc.lPitch + random(450)*2)^ := $FFFF;

//Разблокируем
FImageSurface.Unlock(nil);

//А вот теперь можно выводить на экран картинку
FBackgroundSurface.BltFast (175, 75, FImageSurface, nil, DDBLTFAST_WAIT;

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

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

Результат работы программы ты можешь увидеть на скрине выше, а исходник находиться в директории Source1.

Первый примерчик был достаточно простой, но малоэффективный на практике. Давай познакомимся с чем-нибудь более стоящим. Опять возьмём пример из предыдущего номера ][, статьи "Первая анимация" и дополним его более продвинутыми графическими эффектами.

Перед разделом var добавь раздел type и добавь туда объявление следующего типа:


{$R *.RES}

type
 TByteArray = Array [0..900, 0..450] of Byte;

var

Мы тут просто объявили новый тип TByteArray как двухмерный массив из чисел типа Byte.

В разделе var объявим две новые переменные:


 AnimePict : TByteArray;
 AnimationState:Integer;

Первая переменная имеет тип TByteArray - массив целых чисел. Мы могли и не объявлять нового типа, а просто написать так:


AnimePict : Array [0..900, 0..450] of Byte;

результат был бы один и тот же, но я всё же люблю иногда объявить новый тип, чтобы было легче после этого работать с объявлениями.

Теперь переходим к кодингу. Перед запуском бесконечного цикла. Здесь добавь две строки:


 AnimationState:=10;
 GetAnimationBmp;

В первой мы задаём начальное значение переменной AnimationState. Эта переменная будет использоваться для хранения состояния анимации.

После этого я вызываю процедуру GetAnimationBmp, но она пока не существует, поэтому давай её напишем:


procedure GetAnimationBmp;
var
 hRet:HRESULT;
 desc:TDDSURFACEDESC2;
 i, J:Integer;
begin
 FillChar (desc, SizeOf(desc), 0);
 desc.dwSize := SizeOf(desc);

 hRet:=FImageSurface.Lock(nil, desc, DDLOCK_WAIT, 0);
 if hRet <> DD_OK then exit;

 for i := 0 to 900 do
  for j := 0 to 450 do
   begin
   //Копирую содержимое текущей точки поверхности
    AnimePict [i, j] := PBYTE (Integer (desc.lpSurface) +j * desc.lPitch + (i))^;
   //Обнуляю содержимое текущей точки поверхности
    PBYTE (Integer (desc.lpSurface) +j * desc.lPitch + (i))^:=$00;
   end;

 FImageSurface.Unlock(nil);
end;

Здесь я получаю уже знакомым способом прямой доступ к поверхности FImageSurface, в которой храниться изображение фона. Получив прямой доступ, я запускаю цикл от 0 до 900 и от 0 до 450 внутри которого копирую содержимое поверхности (картинку фона) в массив AnimePict и тут же обнуляю содержимое поверхности. Диапазон цикла выбран не случайно. Переменная i изменяется от 0 до 900 и будет показывать ширину картинки. Так как у нас 16 битный цвет, то для хранения каждой точки изображения используется 2 байта, а значит в памяти ширина картинки будет равна ширине изображения (у меня это 450 пикселей) умноженное на 2. В высоту картинка будет занимать такое же количество памяти, что и реальная высота - 450.

Скопировав всё необходимое в свой массив, поверхность можно разблокировать.

Теперь перейдём к тому месту, где происходит отображение поверхности (туда же, где мы корректировали в предыдущем примере) и напишем там следующее:


   FillChar (desc, SizeOf(desc), 0);
   desc.dwSize := SizeOf(desc);
   hRet:=FImageSurface.Lock(nil, desc, DDLOCK_WAIT, 0);

   if AnimationState<5000 then
    for index:=0 to AnimationState do
     begin
      i:=Random(450)*2;
      j:=Random(450);
      PByte (Integer (desc.lpSurface) + (j) * desc.lPitch+i)^ := AnimePict [i, j];
      PByte (Integer (desc.lpSurface) + (j) * desc.lPitch+i+ 1)^ := AnimePict [i+1, j];
     end
   else
    for index:=5000 to AnimationState do
     begin
      i:=Random(450)*2;
      j:=Random(450);
      PByte (Integer (desc.lpSurface) + (j) * desc.lPitch+i)^ := $00;
      PByte (Integer (desc.lpSurface) + (j) * desc.lPitch+i+ 1)^ := $00;
     end;

   FImageSurface.Unlock(nil);

   if AnimationState>10000 then
    AnimationState:=10;
 
  AnimationState:=AnimationState+10;

  FBackgroundSurface.BltFast (175, 75, FImageSurface, nil, DDBLTFAST_WAIT);

Здесь опять блокируем поверхность фона FImageSurface. Если AnimationState меньше 5000, то запускаем цикл от 0 до значения в переменной AnimationState. Внутри цикла случайным образом выбираем координаты точки и копируем из массива AnimePict (где у нас храниться копия поверхности) в память поверхности. Так как при создании копии поверхности мы её обнулили, то на первом этапе она будет пустой (залита чёрным цветом) и этим кодом мы будем случайными точками засыпать поверхность точками от изображения.

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

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

На этом наверно уже можно и закруглиться. На сегодня эффектов больше нет. Увидимся в следующем номере.

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


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