Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > разработка игр, графический дизайн и моделирование > Gamedev - cоздание игр: Unity, OpenGL, DirectX
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 13.04.2008, 23:14   #21
Beermonza
Инженер ИС
Старожил
 
Аватар для Beermonza
 
Регистрация: 13.12.2006
Сообщений: 2,671
По умолчанию

Kostia, расскажи пожалуйста, как же применить маску к текстуре, с ключем все ясно, но он грубый сильно. Вот к примеру текстура 100х100 в 24bit глубины, и такая же маска 100х100 в 24bit, кроме того фон задний, и еще процедура обрезания текстуры при выходе за экран. Какая процедура нужна Blt, BitBlt, BtlFast или еще какая?
Руководитель проекта MMO 2D RPG: Настоящее имя Денис Стрижак (10.05.1981-6.02.2019) Мир духу его
Beermonza вне форума Ответить с цитированием
Старый 14.04.2008, 05:30   #22
Kostia
Участник клуба
 
Аватар для Kostia
 
Регистрация: 21.11.2007
Сообщений: 1,690
По умолчанию

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

Для начала нужно создать две вспомогательные поверхности в одну будем результировать рассчитанную поверхность, в одну скопируем участок фона и еще две сама картинка и маска.
Код:
//------------------------------------------------------------------
// Создает поверхность DirectDraw нужных размеров
//------------------------------------------------------------------
function CreateSurface(var Surf: IDirectDrawSurface7;dwWidth, dwHeight: DWORD; fSurfLoc: DDSURF_LOCATION ): boolean;
var
  ddsd2:  TDDSURFACEDESC2;
  dwCaps: DWORD;
  piDD7: IDirectDraw7;
begin
  result := false;

  if FAILED( DirectDrawCreateEx( nil, piDD7, IID_IDirectDraw7, nil ) ) then
     exit;

  if FAILED( piDD7.SetCooperativeLevel( 0, DDSCL_NORMAL ) ) then
     exit;

  if Surf <> nil then
     Surf := nil;

  ZeroMemory( @ddsd2, sizeof( TDDSURFACEDESC2 ) );
  ddsd2.dwSize := sizeof( TDDSURFACEDESC2 );

  dwCaps := DDSCAPS_OFFSCREENPLAIN;
  case fSurfLoc of
    DDSL_VIDEOMEM:
      dwCaps := dwCaps or DDSCAPS_VIDEOMEMORY;

    DDSL_SYSTEMMEM:
      dwCaps := dwCaps or DDSCAPS_SYSTEMMEMORY;

    DDSL_BOTH:
  end;

  ddsd2.dwFlags        := DDSD_CAPS or DDSD_WIDTH or DDSD_HEIGHT;
  ddsd2.ddsCaps.dwCaps := dwCaps;
  ddsd2.dwWidth        := dwWidth;
  ddsd2.dwHeight       := dwHeight;

  if FAILED( ppiDD.CreateSurface( ddsd2, Surf, nil ) ) then
  begin
    piDD7 := nil;
    exit;
  end;

  piDD7 := nil;

  result := true;
end;
Вместо комментариев одна абракадабра, поэтому постараюсь так объяснить.
У функции четыре параметра: Результирующая поверхность, ее размеры, и в какой памяти создать поверхность(DDSCAPS_VIDEOMEMORY или DDSCAPS_SYSTEMMEMORY). Если бы DD умел задавать прозрачность аппаратно, то мы бы создали поверхность в видеопамяти, а так придется создавать в оперативке, так быстрее альфа рассчитается.

Код:
function BltTrans(var OutSurf: IDirectDrawSurface7;
                             Desc,Source,Mask: IDirectDrawSurface7): boolean;
var
  ddsd2d: TDDSURFACEDESC2;
  ddsd2s: TDDSURFACEDESC2;
  ddsd2m: TDDSURFACEDESC2;
  ddsd2o: TDDSURFACEDESC2;

  i: integer;
  v: single;

  Color32d,
  Color32s,
  Color32m,
  Color32o: PByteArray;

begin
  result := false;

  if AlphaBlend = 0 then
  begin
    result := false;
    OutSurf.bltfast(0,0,Source,nil,DDBLTFAST_WAIT);
    exit;
  end;

  if AlphaBlend = 255 then
  begin
    result := true;
    exit;
  end;

  ZeroMemory( @ddsd2d, sizeof( TDDSURFACEDESC2 ) );
  ZeroMemory( @ddsd2s, sizeof( TDDSURFACEDESC2 ) );
  ZeroMemory( @ddsd2m, sizeof( TDDSURFACEDESC2 ) );
  ZeroMemory( @ddsd2o, sizeof( TDDSURFACEDESC2 ) );

  ddsd2d.dwSize := sizeof( TDDSURFACEDESC2 );
  ddsd2s.dwSize := sizeof( TDDSURFACEDESC2 );
  ddsd2m.dwSize := sizeof( TDDSURFACEDESC2 );
  ddsd2o.dwSize := sizeof( TDDSURFACEDESC2 );

  if FAILED( Desc.Lock( nil, ddsd2d, DDLOCK_WAIT, 0 ) ) then
     exit;

  if FAILED( Source.Lock( nil, ddsd2s, DDLOCK_WAIT or DDLOCK_READONLY, 0 ) ) then
     exit;

  if FAILED( Mask.Lock( nil, ddsd2m, DDLOCK_WAIT, 0 ) ) then
     exit;

  if FAILED( OutSurf.Lock( nil, ddsd2o, DDLOCK_WAIT, 0 ) ) then
     exit;

  i:=0;

  Color32d:=PByteArray((ddsd2d.lpSurface));
  Color32s:=PByteArray((ddsd2s.lpSurface));
  Color32m:=PByteArray((ddsd2m.lpSurface));
  Color32o:=PByteArray((ddsd2o.lpSurface));

  while i<ddsd2m.dwWidth*ddsd2m.dwHeight*4 do
  begin
    v := (Color32m[i]+Color32m[i+1]+Color32m[i+2]) / 765;
    Color32o[i]:=round(Color32d[i]* v + Color32s[i] * (1 - v));
    Color32o[i+1]:=round(Color32d[i+1]* v + Color32s[i+1] * (1 - v));
    Color32o[i+2]:=round(Color32d[i+2]* v + Color32s[i+2] * (1 - v));
    i:=i+4;
  end;

  Desc.Unlock( nil );
  Source.Unlock( nil );
  Mask.Unlock(nil);
  OutSurf.Unlock(nil);

  result := true;
end;
Эта функция смешивает Desc и Source в соответствии с маской Mask и выводит результат в OutSurf.
BltTrans я писал на глаз и не тестировал, но я уверен, что она будет работать.
Загружаете вы маску и картинку, создаете две вспомогательные поверхности (в системной памяти), копируете в Desc кусочек фона, вызываете функцию BltTrans и потом любым из способов выводите уже рассчитанную картинку на задний буфер.
Предупреждаю это очень медленно, для маленьких объектов тормозов незаметно, но вот больших будет сильный тормоз.
Kostia вне форума Ответить с цитированием
Старый 14.04.2008, 15:47   #23
Beermonza
Инженер ИС
Старожил
 
Аватар для Beermonza
 
Регистрация: 13.12.2006
Сообщений: 2,671
По умолчанию

Kostia, большое спасибо! Все не так медленно будет, если на GDI я умудрился все это проделать с нормальной скоростью, то тут будет быстрее, а оптимизация все устранит тормозное.
Руководитель проекта MMO 2D RPG: Настоящее имя Денис Стрижак (10.05.1981-6.02.2019) Мир духу его
Beermonza вне форума Ответить с цитированием
Старый 14.04.2008, 22:59   #24
Beermonza
Инженер ИС
Старожил
 
Аватар для Beermonza
 
Регистрация: 13.12.2006
Сообщений: 2,671
По умолчанию Оптимизация...

Вот, собственно, что сразу бросилось в глаза, эта странная структура смешивания цветов:

результат := round( задник * маска + текстура * (1 - маска) );

надеюсь, ничего не напутал с расстановкой переменных, ...не удивительно, что вся функция BltTrans работает так тормозно.
Вот что должно быть на самом деле (для 24bit глубины):

результат := задник + ( текстура - задник ) * маска shr 8;

...это для каждого цвета по RGB, думаю больше пояснений не требуется.
Руководитель проекта MMO 2D RPG: Настоящее имя Денис Стрижак (10.05.1981-6.02.2019) Мир духу его

Последний раз редактировалось Beermonza; 14.04.2008 в 23:15.
Beermonza вне форума Ответить с цитированием
Старый 15.04.2008, 08:25   #25
Kostia
Участник клуба
 
Аватар для Kostia
 
Регистрация: 21.11.2007
Сообщений: 1,690
По умолчанию

Beermonza, Спасибо за оптимизацию. Я в интернете нашел пример как реализовать полупрозрачность и автор утверждал, что это самый быстрый способ смешивания цветов, но когда я запустил пример на менее мощном компьютере, то сразу заметил тормоза, но искать более быстрого способа смешать цвета не стал т.к. перешел на Direct3D.
Kostia вне форума Ответить с цитированием
Старый 15.04.2008, 14:48   #26
mutabor
Телепат с дипломом
Старожил
 
Аватар для mutabor
 
Регистрация: 10.06.2007
Сообщений: 4,929
По умолчанию

То есть DirectX в 2D не умеет полупрозрачность аппаратно применять? А с помощью Direct3D двухмерную игру в буквальном понимании создать невозможно? Получается частично тормознутая альфа в любом случае если я правильно понял?
А как OpenGL, аппаратно альфу в 2D применяет?
Можно ли из этого сделать вывод, что одинаковая 2D графика на DirectX более требовательна к железу, чем на OpenGL?
The future is not a tablet with a 9" screen no more than the future was a 9" black & white screen in a box. It’s the paradigm that survives. (Kroc Camen)
Проверь себя! Онлайн тестирование | Мой блог

Последний раз редактировалось mutabor; 15.04.2008 в 14:54.
mutabor вне форума Ответить с цитированием
Старый 15.04.2008, 15:27   #27
Kostia
Участник клуба
 
Аватар для Kostia
 
Регистрация: 21.11.2007
Сообщений: 1,690
По умолчанию

Цитата:
То есть DirectX в 2D не умеет полупрозрачность аппаратно применять?
DirectDraw нет, он с седьмой версии DX не развивается, а Direct3D может работать как Hardware или Software достаточно установить при инициализации соответствующий флаг.
Цитата:
А с помощью Direct3D двухмерную игру в буквальном понимании создать невозможно?
В буквальном невозможно. В Direct3D нужно задать координаты вершин треугольников и натянуть на полученную фигуру текстуру. Координаты можно задать по разному(в экранных координатах или в пространственных).
Цитата:
А как OpenGL, аппаратно альфу в 2D применяет?
С OpenGL не знаком.
Цитата:
Можно ли из этого сделать вывод, что одинаковая 2D графика на DirectX более требовательна к железу, чем на OpenGL?
Если речь идет о DirectDraw то да
Kostia вне форума Ответить с цитированием
Старый 15.04.2008, 15:37   #28
Beermonza
Инженер ИС
Старожил
 
Аватар для Beermonza
 
Регистрация: 13.12.2006
Сообщений: 2,671
По умолчанию

Так и есть. 2D в Direct3D не что иное, как построение полигона и натягивание на него текстуры, которая меняется в зависимости от цикла смены кадров.

Раз уж тема про DirectDrаw, то я разработаю более скоростную функцию, ...пока что далеко не предел оптимизации со сменой алгоритма смешивания цветов.
Руководитель проекта MMO 2D RPG: Настоящее имя Денис Стрижак (10.05.1981-6.02.2019) Мир духу его
Beermonza вне форума Ответить с цитированием
Старый 15.04.2008, 15:56   #29
Kostia
Участник клуба
 
Аватар для Kostia
 
Регистрация: 21.11.2007
Сообщений: 1,690
По умолчанию

С DirectDraw еще та замута, Beermonza. Я делал модуль для упрощения работы с DirectDraw, там и поворот и масштабирование и обрезание и полупрозрачность, одним словом все необходимое и все это можно было применить одновременно. Я два дня сидел только над тем как можно масштабировать и правильно обрезать картинку, а про повороты и полупрозрачность вообще молчу. В конце концов я пришел к выводу, не делать и не пользоваться разными движками, а делать все на низком уровне самому. Так можно воспользоваться всеми возможностями API и скорость работы приложения будет больше.

Beermonza, можешь покопаться в моих наработках, может что интересного найдешь.
Вложения
Тип файла: rar Max2D.rar (6.8 Кб, 30 просмотров)
Kostia вне форума Ответить с цитированием
Старый 15.04.2008, 22:35   #30
Beermonza
Инженер ИС
Старожил
 
Аватар для Beermonza
 
Регистрация: 13.12.2006
Сообщений: 2,671
Счастье Вот оно!

Как и обещал, выкладываю оптимизированную функцию отображения с альфа-каналом. Быстрее будет только аппаратная )

Обязателен свой тип для RGB:

Код:
// тип представления RGB ------------------------
type
  PRGB = ^TRGB;
  tagRGB = packed record
    R: Byte;
    B: Byte;
    G: Byte;
  end;
  TRGB = tagRGB;
// ----------------------------------------------
Вот она функция:

Код:
//==============================================================================
// BltFastAlpha Function 15/04/2008
// Create by Beermonza
// Реализует быстрое построение изображений с альфа-каналом
//==============================================================================
function BltFastAlpha(var DDS7Desc:   DDSurf7; // DDS-поверхность заднего фона
                          X:          DWORD;   // Точка копирования заднего фона по-X
                          Y:          DWORD;   // Точка копирования заднего фона по-Y
                          W:          DWORD;   // Ширина копирования
                          H:          DWORD;   // Высота копирования
                      var DDS7Source: DDSurf7; // DDS-поверхность текстуры
                      var DDS7Mask:   DDSurf7; // DDS-поверхность маски
                      var DDS7Buf:    DDSurf7   { DDS-поверхность буфера }): boolean;
var
  DDSD2Buf:    TDDSURFACEDESC2;  // буфер
  DDSD2Source: TDDSURFACEDESC2;  // текстура
  DDSD2Mask:   TDDSURFACEDESC2;  // маска

  xx: DWORD; // для цикла
  RectDDS7Desc: TRect; // область для копирования заднего фона
  SourcePix, MaskPix, BufPix: PRGB; // RGB структурирование

begin
  Result:=False;

// Создаем область копирования
  SetRect(RectDDS7Desc, X, Y, X+W, Y+H);

// Коприруем область заднего фона в буфер
  DDS7Buf.BltFast(0, 0, DDS7Desc, @RectDDS7Desc, DDBLTFAST_WAIT);

// Очищаем память под структуры DDSD2
  ZeroMemory(@DDSD2Buf,    sizeof(TDDSURFACEDESC2));
  ZeroMemory(@DDSD2Source, sizeof(TDDSURFACEDESC2));
  ZeroMemory(@DDSD2Mask,   sizeof(TDDSURFACEDESC2));

// Задаем размер
  DDSD2Buf.dwSize    := sizeof(TDDSURFACEDESC2);
  DDSD2Source.dwSize := sizeof(TDDSURFACEDESC2);
  DDSD2Mask.dwSize   := sizeof(TDDSURFACEDESC2);

// Блокируем спрайт буфера
  If FAILED(DDS7Buf.Lock(nil, DDSD2Buf, DDLOCK_WAIT, 0)) then exit;
// Блокируем спрайт текстуры
  If FAILED(DDS7Source.Lock(nil, DDSD2Source, DDLOCK_WAIT or DDLOCK_READONLY, 0)) then exit;
// Блокируем спрайт маски
  If FAILED(DDS7Mask.Lock(nil, DDSD2Mask, DDLOCK_WAIT, 0)) then exit;

// Получаем указатели на начало данных
  DWORD(SourcePix) := DWORD(DDSD2Source.lpSurface);
  DWORD(MaskPix)   := DWORD(DDSD2Mask.lpSurface);
  DWORD(BufPix)    := DWORD(DDSD2Buf.lpSurface);

  // Цикл перебирает все байты данных
  For xx:=0 to (W-1)*(H-1) do
    Begin
      // Если чвет пиксела маски не черный (полная прозрачность)
      If (MaskPix.R>0) And (MaskPix.G>0) And (MaskPix.B>0) then
        Begin
          // Смешиваем цвета по формуле прозрачности (24bit)
          BufPix.R := BufPix.R + (SourcePix.R - BufPix.R) * MaskPix.R shr 8;
          BufPix.G := BufPix.G + (SourcePix.G - BufPix.G) * MaskPix.G shr 8;
          BufPix.B := BufPix.B + (SourcePix.B - BufPix.B) * MaskPix.B shr 8;
        end;
      // Получаем указатели на следующие байты данных
      DWORD(SourcePix) := DWORD(SourcePix) + 4;
      DWORD(MaskPix)   := DWORD(MaskPix)   + 4;
      DWORD(BufPix)    := DWORD(BufPix)    + 4;
    end;

// Разблокируем поверхности
  DDS7Buf.Unlock(nil);
  DDS7Source.Unlock(nil);
  DDS7Mask.Unlock(nil);

  // Копируем содержимое буфера на задний фон
  DDS7Desc.BltFast(X, Y, DDS7Buf, nil, DDBLTFAST_WAIT);

  Result:=True;
end;
Теперь, как ей пользоваться.

function BltFastAlpha(DDS7Desc, X, Y, W, H, DDS7Source, DDS7Mask, DDS7Buf): boolean;

DDS7Desc - поверхность заднего фона IDirectDrawSurface7 (это буфер, в котором строится весь кадр, перед выводом на экран, созданный в памяти видеокарты);
X - точка копирования заднего фона по-X (от куда начинать копировать);
Y - точка копирования заднего фона по-Y;
W - ширина области копирования (по этим данным строится область копирования TRect типа);
H - высота области копирования;
...следующие 3 поверхности должны быть одного размера и созданы заранее в системной памяти...
DDS7Source - поверхность текстуры IDirectDrawSurface7;
DDS7Mask - поверхность маски IDirectDrawSurface7;
DDS7Buf - поверхность буфера IDirectDrawSurface7;

Пробуйте, ...пишите в этой теме отзывы.
Руководитель проекта MMO 2D RPG: Настоящее имя Денис Стрижак (10.05.1981-6.02.2019) Мир духу его

Последний раз редактировалось Beermonza; 15.04.2008 в 22:55.
Beermonza вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
подключение DirectDraw g@mbler Общие вопросы Delphi 1 09.11.2006 20:18