Конференция "Игры" » Загрузка текстуры в ручную. DirectX. [Delphi]
 
  • eXAAAXe (16.05.11 10:45) [0]
    Привет.
    Написал загрузку бмп. (Только 24 и 32 битных)
    1) Но как залить им текстуру не понимаю.
    2) Почему Device.FDevice.CreateTexture возвращает ИнвалидКал.

    function LoadTexture(const FileName: string; var W, H: LongWord; var Data: Pointer; var Format: TD3DFormat): boolean;
    var
     Bpp: LongWord;
    begin
     Result:= LoadBmp(FileName, W, H, Bpp, Data);

     If Result then
     Case Bpp of
       24: Format:= D3DFMT_R8G8B8;
       32: Format:= D3DFMT_X8B8G8R8;
     end;
    end;

    function TTexture.Load(const FileName: string): boolean;
    var
     W, H  : LongWord;
     Format: TD3DFormat;
     pScr  : Pointer;
     LRect : TD3DLockedRect;
    begin
     Result:= False;

     If LoadTexture(FileName, W, H, pScr, Format) then
     begin
       If Check(Device.FDevice.CreateTexture(W, H, 0, 0, Format, D3DPOOL_MANAGED, FHandle, nil)) then
       begin
         If Check(FHandle.LockRect(0, LRect, nil, D3DLOCK_DISCARD)) then
         try
           // ?

         finally
           Result:= UnLock;
         end;
       end;

     end;
    end;

  • CrytoGen (16.05.11 10:46) [1]
    (Width,Height,1,0,D3DFMT_A8R8G8B8,D3DPOOL_MANAGED,d3dt,nil))
  • eXAAAXe (16.05.11 18:06) [2]
    Спасибо. Инвалид калл исчез.
    Картинка (бмп24) загрузилась, но изображение серое и раздробленное.
    Ещё формат D3DFMT_R8G8B8 для бмп24 должен был подойти, но нет.
    Почему?


    If Check(FHandle.LockRect(0, LRect, nil, D3DLOCK_DISCARD)) then
    try
     Move(pScr^, LRect.pBits^, W * H * 3);
    finally
     Result:= UnLock;
    end;

  • CrytoGen (16.05.11 19:11) [3]
    Учтите LRect.pitch и чО в bmp выравнивание есть, точно не помню какое.
  • eXAAAXe (16.05.11 22:01) [4]
    Да, точно.
    Решил для начала залить текстуру нужным цветом.
    На выходе получаю один мусор в текстуре.


    For y:= 0 to H - 1 do
      For x:= 0 to W - 1 do
      begin
         PDWORD(DWORD(LRect.pBits) + (Y * DWORD(LRect.Pitch)) + (X * 4))^:= D3DCOLOR_XRGB(255, 0, 0);
         Inc(PDWORD(LRect.pBits)^);
      end;

  • CrytoGen (16.05.11 22:10) [5]
    бред же написали :)
  • CrytoGen (16.05.11 22:10) [6]
    чтобы незапутаться попробуйте тупо FillChar
  • CrytoGen (16.05.11 22:23) [7]
    D3DFMT_R8G8B8 - Трёх байтовая структура, смещение по строкам у вас дважды получается и оба раза не верно.
  • eXAAAXe (17.05.11 09:29) [8]
    Сделал вот так, работает:


    function TTexture.Load(const FileName: string; Custom: boolean = False): boolean;
    var
     X, Y  : LongWord;
     W, H  : LongWord;
     P     : PRGB;
     pScr  : Pointer;
     LRect : TD3DLockedRect;
     Format: TD3DFormat;
    begin
     If Custom then
     begin
       Result:= False;

       // Инфо: Bmp. (BGR, FlipH)
       If LoadTexture(FileName, W, H, pScr, Format) then
       try
         If not DXCheck(Device.FDevice.CreateTexture(W, H, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, FHandle, nil)) then Exit;

         If DXCheck(FHandle.LockRect(0, LRect, nil, 0)) then
         try
           P:= pScr;
           For Y:= H - 1 downto 0 do
             For X:= 0 to W - 1 do
             with P^ do
             begin
               PDWORD(DWORD(LRect.pBits) + Y * LRect.Pitch + X * 4)^:= D3DCOLOR_XRGB(B, G, R);
               Inc(P);
             end;
         finally
           Result:= DXCheck(FHandle.UnlockRect(0));
         end;
       finally
         FreeMem(pScr);
       end;
     end else
       Result:= DXCheck(D3DXCreateTextureFromFile(Device.GetHandle, XPChar(FileName), FHandle));
    end;



    Но есть вопросы:

    1) Текстуры обязательно должны быть кратны 2-ке?
    2) Работает только при D3DPOOL_MANAGED.
    3) Перенос пикселей в 2-х циклах да и ещё с D3DCOLOR_XRGB - жирёт время.
       Как-то не оптимально получилось.

    Заранее благодарен. :)
  • CrytoGen (17.05.11 10:26) [9]
    1) вроде не обязательно
    2) почитайте, сейчас на вскидку не подскажу
    3) а вы часто текстуры загружаете? если нет, то какая разница - надёжность важнее


            with P^ do
            begin
              PDWORD(DWORD(LRect.pBits) + Y * LRect.Pitch + X * 4)^:= D3DCOLOR_XRGB(B, G, R);
              Inc(P);
            end;


    чО за P?

    посмотрите типы RGBQuad и RGBTriple. чтобы не заморачиваться с альфой воспользуйтесь трёх байтной структурой.
  • Sapersky (17.05.11 11:41) [10]
    1) Современные карты поддерживают некратные, но с ограничениями (мип-мэппинг с ними не работает и ещё что-то). Для 2D можно использовать, для 3D лучше не.
    2) Да, так и было задумано MS'ом. К POOL_DEFAULT доступа через Lock нет.
    3) Ничего там особенно не "жирёт". Инициализация DX больше времени займёт, чем загрузка текстур. Но если так уж хочется максимально "вылизать", убирай вызов функции, вычисление DWORD(LRect.pBits) + Y * LRect.Pitch на каждом шаге по X (оно же одинаковое остаётся).
  • eXAAAXe (17.05.11 14:40) [11]
    > CrytoGen   (17.05.11 10:26) [9]

    > чО за P?



    type
     PRGB = ^TRGB;
     TRGB = record
       R, G, B: byte;
     end;



    > Sapersky   (17.05.11 11:41) [10]
    > 1) Современные карты поддерживают некратные, но с ограничениями
    > (мип-мэппинг с ними не работает и ещё что-то). Для 2D можно использовать, для 3D лучше не.

    Проверил капсы.
    Оказывается моя видеокарта не поддерживает такие текстуры.

    Всем спасибо. :)
  • eXAAAXe (18.05.11 14:31) [12]
    Проверил на другом аппарате.
    Текстуры не кратные 2-ке - поддерживаются.
    Решил загрузить текстуру 50x50 бмп, 24 бит.
    Картинка получилась такая:
    http://imglink.ru/show-image.php?id=b844ba551e10c15c664aab989915ec68

    В чём дело?
  • CrytoGen (18.05.11 14:50) [13]
    у bmp выравнивание по 4 байта в строках
  • eXAAAXe (18.05.11 17:11) [14]

    > CrytoGen   (18.05.11 14:50) [13]


    А как тогда сделать?
    Поменял так, но получается мусор:


    type
    PRGBA = ^TRGBA;
    TRGBA = record
      R, G, B, A: byte;
    end;




    Или Вы о чем?
  • CrytoGen (18.05.11 19:10) [15]
         
          For Y:= H - 1 downto 0 do
          begin
            P:= Pointer(Integer(pScr)+((Y*W*3+3) div 4)*4);//выровняли по 4 байта
            For X:= 0 to W - 1 do
            with P^ do
            begin
              PDWORD(DWORD(LRect.pBits) + Y * LRect.Pitch + X * 4)^:= D3DCOLOR_XRGB(B, G, R);
              Inc(P);
            end;
          end;


    у вас получаются данные из битмапа без разрыва, а они на каждой новой строке должны быть выровнены по 4-м байтам.
  • CrytoGen (18.05.11 19:11) [16]
    Правда с Pointer'ами и Interger'ами так лучше не делать, а переписать с промежуточным PByte
  • eXAAAXe (18.05.11 20:24) [17]
    Для кратных 2-ке нормально, а для остальных нет.
  • CrytoGen (18.05.11 21:20) [18]

         For Y:= H - 1 downto 0 do
         begin
           For X:= 0 to W - 1 do
           with P^ do
           begin
             PDWORD(DWORD(LRect.pBits) + Y * LRect.Pitch + X * 4)^:= D3DCOLOR_XRGB(B, G, R);
             Inc(P);
           end;
           P:= Pointer(((Integer(P)+3) div 4)*4);//выровняли по 4 байта
         end;


    Попробуйте так. И поищите ответ сами, что ли :)
  • Sapersky (19.05.11 00:43) [19]
    Проще говоря, у битмапов как и у текстур есть Pitch, который не обязательно равен Width * BytesPerPixel. Посчитать его можно функцией BytesPerScanline из Graphics.pas.
  • !!! (19.05.11 13:32) [20]
    Когда-то использовал следующую функцию загрузки bmpшек на поверхность directx7 ...
    у меня тоже не получалось правильно загрузить, но на этом форуме помогли.

    // ================================================================================ ====
    // структура для хранения спрайта
    typedef struct
    {
    int xsize;
    int ysize;

    LPDIRECTDRAWSURFACE7 Surf;
    }
    spriteTag;

    // ================================================================================ ====
    // Загружает спрайт из архива
    spriteTag* Pak_LoadSprite (packfile_t *pf, char *filename, int r, int g, int b)
    {
    char *buf_data;   // Буфер данных

      // Грузим данные в буффер, используя функцию из библиотеки
      /*
    unpak.c   Copyright (C) 1998-2000 Vitaly Ovtchinnikov
             and Damir Sagidullin         */

    int filesize = PackFileGet (pf, filename, &buf_data);

    if (!filesize || !(*buf_data))  // Если ничего не загрузилось
    {
     free (buf_data);
     return NULL;
    }


    // Копируем заголовок
    BITMAPFILEHEADER bmpHEAD;
    memcpy (&bmpHEAD, buf_data, sizeof(bmpHEAD));

    // Проверяем, действительно ли это БМП файл
    char *bmpType = (char*)
    &bmpHEAD.bfType;

    if (*bmpType != 'B' || *++bmpType != 'M')  // Если нет
    {
     free (buf_data);
     return NULL;
    }


    // Копируем второй - информацинный заголовок
    BITMAPINFOHEADER bmpINFO;
    memcpy (&bmpINFO, buf_data + sizeof(bmpHEAD), sizeof(bmpINFO));

    if (bmpINFO.biCompression != BI_RGB) // Не сжатое ли изображение
    {
     free (buf_data);
     return NULL;
    }


    // Устраивают ли нас пиксели
    if (bmpINFO.biBitCount != 24)
    {
     free (buf_data);
     return NULL;
    }


    // Выделяем место под спрайт
    spriteTag *newSprite = new spriteTag;

    // Если не удалось выделеть место
    if (!newSprite)
    {
     free (buf_data);
     return NULL;
    }


    // сохраним в спрайте размеры картинки
    newSprite->xsize = bmpINFO.biWidth;
    newSprite->ysize = bmpINFO.biHeight;

    // Создаем поверхность
    if (DirectDraw7_CreateSurface (&(newSprite->Surf), newSprite->xsize, newSprite->ysize))
    {
     free (buf_data);
     delete newSprite;
     return NULL;
    }


    // Установим прозрачный цвет для поверхности
    DirectDraw7_SetColorKey (newSprite->Surf, r, g, b);

    // Вычисляем размер изображения, если нужно
    int ImageSize = bmpINFO.biSizeImage;
    if (!ImageSize)
     ImageSize = ((bmpINFO.biWidth*(bmpINFO.biBitCount/8)+3 & ~3)*bmpINFO.biHeight);

    // Теперь займемся копированием точек на поверхность
    BYTE *bmpbuf = (BYTE*)
    (buf_data + sizeof(bmpHEAD) + bmpINFO.biSize);

    DDSURFACEDESC2 desc;
    ZeroMemory (&desc, sizeof (desc));
    desc.dwSize = sizeof (desc);

    // Залочим поверхность чтобы с ней можно было работать
    HRESULT res = newSprite->Surf->Lock( 0, &desc, DDLOCK_WAIT | DDLOCK_WRITEONLY, 0 );

    // Если не получилось, то на выход
    if (res != DD_OK)
    {
     free (buf_data);
     delete newSprite;
     return false;
    }


    int BytesRequired = bmpINFO.biWidth * 3;
    int BytesGiven = (BytesRequired + 3) & ~3;
    BYTE *surfBits = (BYTE*)desc.lpSurface;
    BYTE *imageBits = (BYTE*)(&bmpbuf[(bmpINFO.biHeight-1)*BytesGiven]);

    for (int i=0; i<bmpINFO.biHeight; i++)
    {
     WORD *pixptr = (WORD*)surfBits;
     RGBTRIPLE *triple = (RGBTRIPLE*)imageBits;

     for (int p=0; p<bmpINFO.biWidth; p++)
     {
      BYTE rf = triple->rgbtRed >> 3;
      BYTE gf = triple->rgbtGreen >> 2;
      BYTE bf = triple->rgbtBlue >> 3;

      *pixptr = (WORD)(bf | (gf << 5) | (rf << 11));
      triple++;
      pixptr++;
     }

     surfBits += desc.lPitch;
     imageBits -= BytesGiven;
    }

    // Разлочим поверхность
    newSprite->Surf->Unlock (NULL);

      // вернем готовый спрайт
    return newSprite;
    }

  • eXAAAXe (20.05.11 11:49) [21]

    > CrytoGen   (18.05.11 21:20) [18]


    Выравнял по 4 байта, для не кратных 2-ке, всё осталось также как на картинке.

    > Попробуйте так. И поищите ответ сами, что ли :)

    У меня плохо гуглится. :)

    >Sapersky   (19.05.11 00:43) [19]

    Спасибо.

    >!!!   (19.05.11 13:32) [20]

    Посмотрел код, вроде тоже самое: выравнивание, RGB-структура.
  • CrytoGen (20.05.11 12:37) [22]
    Для всех надо выравнивать.

         For Y:= H - 1 downto 0 do
         begin
           P:= Pointer(Integer(pScr)+((Y*3+3)*W div 4)*4);//выровняли по 4 байта
           For X:= 0 to W - 1 do
           with P^ do
           begin
             PDWORD(DWORD(LRect.pBits) + Y * LRect.Pitch + X * 4)^:= D3DCOLOR_XRGB(B, G, R);
             Inc(P);
           end;
         end;


    Ну так попробуйте. И вообще если у вас проблемы отладить такую вещь, то используйте более стандартные подходы. Если бы взяли TBitmap.Scanline, вообще такой проблемы не было бы.
  • CrytoGen (20.05.11 13:23) [23]
    Лучше конечно такие вещи с дельфёй проверять.
        For Y:= H - 1 downto 0 do
        begin
          P:= Pointer(Integer(pScr)+((Y*3+3) div 4)*4*W);//выровняли по 4 байта
          For X:= 0 to W - 1 do
          with P^ do
          begin
            PDWORD(DWORD(LRect.pBits) + Y * LRect.Pitch + X * 4)^:= D3DCOLOR_XRGB(B, G, R);
            Inc(P);
          end;
        end;

  • eXAAAXe (20.05.11 16:11) [24]

    > CrytoGen  


    > Sapersky  


    Большое спасибо, что терпели меня. =)
    Сделал как в ScanLine у TBitmap.
 
Конференция "Игры" » Загрузка текстуры в ручную. DirectX. [Delphi]
Есть новые Нет новых   [118656   +19][b:0][p:0.005]