Конференция "Игры" » DDS-Загрузка [Delphi, Windows]
 
  • eXAAAXe (26.05.11 02:14) [0]
    Всем привет.
    Пытаюсь загрузить dds.
    Памяти под изображение выделяю:  dwPOLS * Height.
    Изображение без мипмапов, формат D3DFMT_A8R8G8B8:


    function TTexture.Load2(const FileName: string; Custom: boolean = False): boolean;
    var
     P    : PRGBA; // TRGBA = record R, G, B, A: byte; end;
     pScr : Pointer;
     X, Y : LongWord;
     W, H : LongWord;
     Format: TD3DFormat;
     LRect: TD3DLockedRect;

     function PitchDds(Bpp: LongWord): Pointer;
     begin
       LONGINT(Result):= LONGINT(pScr) + ((W + Bpp + 7) div 8);
     end;

    begin
     If Custom then
     begin
       Result:= False;

       If LoadDds(FileName, W, H, pScr, Format) then
       try
         If not CreateTexture(W, H, Format) then Exit;

         If DXCheck(FHandle.LockRect(0, LRect, nil, 0)) then
         try
           For Y:= 0 to H - 1 do
           begin
             P:= PitchDds(32);
             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;
         finally
           Result:= DXCheck(FHandle.UnlockRect(0));
         end;
       finally
         FreeMem(pScr);
       end;
     end else
       Result:= DXCheck(D3DXCreateTextureFromFile(Device.GetHandle, XPChar(FileName), FHandle));

     If Result
     then GetInfo;
    end;




    В итоге получаю чёрную текстуру.
    Хотя как и бмп выравниваю по dds pitch.

    Что не так?
  • CrytoGen (26.05.11 18:28) [1]
    что такое LoadDds ? вы какие-то странные функции используете и не проверяете как они работают.
  • eXAAAXe (26.05.11 18:54) [2]
    Вот:


    function LoadDds(const FileName: XString; var W, H: LongWord; var Data: Pointer; var Format: TD3DFormat): boolean;
    var
     DDS : TDDS;              // Хидер dds. См MSDN
     Size: LongWord;
    begin
     Result:= False;

     with TMyStream.Create do // Мой поток.
     try
       If Init(FileName) then // Открываем.
       begin
         ZeroMemory(@DDS, SizeOf(DDS));
         Read(DDS, SizeOf(DDS));
         with DDS do
         begin
           LogAssert(dwMagic = MAKEFOURCC('D', 'D', 'S', ' '), FFormat('No dds-file: \"%s\".',  [FileName]));
           LogAssert(not BitCheck(dwFlags, DDSD_MIPMAPCOUNT),  FFormat('Found mipmaps. (Count: %d)', [dwMipMapCount]));

           with ddsPixelFormat do
           If ((not BitCheck(dwPFFlags, DDPF_FOURCC)) and   // Не сжатая.
               (dwRGBBitCount = 32) and                     // Проверяем на D3DFMT_A8R8G8B8.
               (dwRBitMask    = $00FF0000)  and
               (dwGBitMask    = $0000FF00)  and
               (dwBBitMask    = $000000FF)  and
               (dwABitMask    = $FF000000)) then
           begin
             W     := dwWidth;
             H     := dwHeight;
             Format:= D3DFMT_A8R8G8B8;

             LogPrint('Check');                             // Правильно ли загрузили?

             If not BitCheck(dwFlags, DDSD_PITCH)           // Если флаг не указан, то сами считаем питч.
             then dwPOLS:= ((W + dwRGBBitCount + 7) div 8);

             Size:= dwPOLS * H;
             // Size:= W * H * 4;
             GetMem(Data, Size);
             Read(Data, Size);

             Result:= Assigned(Data);
           end;
         end;
       end;
     finally
       Free;
     end;
    end;


  • eXAAAXe (26.05.11 19:07) [3]
    Вот так правильней:


    function LoadDds(const FileName: XString; var W, H: LongWord; var Data: Pointer; var Format: TD3DFormat): boolean;
    var
     DDS : TDDS;              // Хидер dds. См MSDN
     Size: LongWord;
    begin
     Result:= False;

     with TMyStream.Create do // Мой поток.
     try
       If Init(FileName) then // Открываем.
       begin
         ZeroMemory(@DDS, SizeOf(DDS));
         Read(DDS, SizeOf(DDS));
         with DDS do
         begin
           LogAssert(dwMagic = MAKEFOURCC('D', 'D', 'S', ' '), FFormat('No dds-file: \"%s\".',  [FileName]));
           LogAssert(not BitCheck(dwFlags, DDSD_MIPMAPCOUNT),  FFormat('Found mipmaps. (Count: %d)', [dwMipMapCount]));

           with ddsPixelFormat do
           If ((not BitCheck(dwPFFlags, DDPF_FOURCC)) and   // Не сжатая.
               (dwRGBBitCount = 32)         and             // Проверяем на D3DFMT_A8R8G8B8.
               (dwRBitMask    = $00FF0000)  and
               (dwGBitMask    = $0000FF00)  and
               (dwBBitMask    = $000000FF)  and
               (dwABitMask    = $FF000000)) then
           begin
             W     := dwWidth;
             H     := dwHeight;
             Format:= D3DFMT_A8R8G8B8;

             LogPrint('Check');                             // Правильно ли загрузили?

             LogPrint('1) ' + IntToStr(dwPOLS));            // 1 и 3 совпадают.
             LogPrint('2) ' + IntToStr(((W + dwRGBBitCount + 7) div 8) * H));
             LogPrint('3) ' + IntToStr(W * H * 4));

             Size:= dwPOLS;
             // Size:= W * H * 4;
             GetMem(Data, Size);
             Read(Data, Size);

             Result:= Assigned(Data);
           end;
         end;
       end;
     finally
       Free;
     end;
    end;




    1) Почему питч вычисленный в ручную (2)) меньше записанного в хидере?
    Хотя делалось по MSDN.
    2) В итоге чёрная текстура.
  • CrytoGen (26.05.11 19:13) [4]
    Сдаётся мне что чёрная текстура потому, что неправильно грузите данные. Вы трассировку делали? Что у вас в хидер попадает смотрели? может вы неправильно хидер читаете? Как у вас выглядит соответствующая структура?
  • CrytoGen (26.05.11 19:19) [5]
    Size of structure. This member must be set to 124.

    проверяли?
  • eXAAAXe (26.05.11 19:56) [6]
    >CrytoGen   (26.05.11 19:13) [4]
    >Как у вас выглядит соответствующая структура?


    type
     TDDS = packed record
       dwMagic      : LongWord;
       dwSize       : LongWord;
       dwFlags      : LongWord;
       dwHeight     : LongWord;
       dwWidth      : LongWord;
       dwPOLS       : LongWord;
       dwDepth      : LongWord;
       dwMipMapCount: LongWord;
       dwReserved1  : array [0..10] of LongWord;
       ddsPixelFormat : packed record
         dwSize       : LongWord;
         dwPFFlags    : LongWord;
         dwFourCC     : LongWord;
         dwRGBBitCount: LongWord;
         dwRBitMask   : LongWord;
         dwGBitMask   : LongWord;
         dwBBitMask   : LongWord;
         dwABitMask   : LongWord;
       end;
       dwCaps       : LongWord;
       dwCaps2      : LongWord;
       dwCaps3      : LongWord;
       dwCaps4      : LongWord;
       dwReserved2  : LongWord;
     end;

    const
     DDSD_CAPS        = $00000001;
     DDSD_HEIGHT      = $00000002;
     DDSD_WIDTH       = $00000004;
     DDSD_PITCH       = $00000008;
     DDSD_PIXELFORMAT = $00001000;
     DDSD_MIPMAPCOUNT = $00020000;
     DDSD_LINEARSIZE  = $00080000;

     DDPF_ALPHAPIXELS = $00000001;
     DDPF_ALPHA       = $00000002;
     DDPF_FOURCC      = $00000004;
     DDPF_RGB         = $00000040;
     DDPF_LUMINANCE   = $00020000;

     DDSCAPS_TEXTURE  = $00001000;




    >проверяли?

    Конечно.
    Размер хидера 124 + 4 под поле Magic.
  • eXAAAXe (26.05.11 20:08) [7]
    Теперь можете собрать у себя и проверить.
  • CrytoGen (26.05.11 21:40) [8]
    Неее :) Спасибо конечно, но это ваша работа. Вот это ещё покажите CreateTexture(W, H, Format).
  • eXAAAXe (26.05.11 21:44) [9]
    Тут то всё в порядке, ведь загрузка бмп нормально работала. :)


    function TTexture.CreateTexture(W, H: LongWord; Format: TD3DFormat): boolean;
    begin
     Result:= False;

     If not Device.IsCaps(dcPow2) then         // Если карточка не держит POT-текстуры.
        If not IsPow2(W) or not IsPow2(H) then // Проверяем кратность текстуры.
        begin
          LogPrint(FFormat('NPOT texture. (%d x %d)', [W, H]));
          Exit;
        end;

     Result:= DXCheck(Device.GetHandle.CreateTexture(W, H, 1, 0, Format, D3DPOOL_MANAGED, FHandle, nil));
     If not Result
     then LogPrint(FFormat('No create texture. (%d x %d x %s)', [W, H, D3DFormatToStr(Format)]));
    end;


  • eXAAAXe (26.05.11 21:46) [10]

    > CrytoGen   (26.05.11 21:40) [8]


    > Неее :) Спасибо конечно, но это ваша работа.


    Я говорю - можете у себя проверить код, чтоб помочь разобраться так сказать. :)
  • Sapersky (27.05.11 00:15) [11]
    В PitchDds фигня написана, во всяком случае, с учётом места, где оно вызывается - точно фигня.

    В Vampyre (Imaging) library есть загрузка DDS.
  • eXAAAXe (27.05.11 02:36) [12]
    > Sapersky   (27.05.11 00:15) [11]

    >В PitchDds фигня написана, во всяком случае, с учётом места, где оно
    > вызывается - точно фигня.

    Делал по аналогии с бмп.

    > В Vampyre (Imaging) library есть загрузка DDS.

    Посмотрел, т.к. загружаю 1 формат, без мипмапов (0), обычное 2D изображение.
    То в итоге код не сильно изменился:
    Там по другому считается питч.


    If (dwPOLS = 0) then dwPOLS:= (W * dwRGBBitCount + 3) div 4 * 4;

    Size:= dwPOLS * H;



    В итоге текстура чёрная.

    Решил сильнее покопаться и смог выдернуть так код:


    procedure FillLockedRectWithImage(var Rect: TD3DLockedRect; W, H, Size: LongWord; Bits: Pointer; IsSpecial: boolean = False);
    var
     I, LineBytes: LongInt;

    begin
     LineBytes := W * 1 * 4; // GetStdPixelsSize = W * H * 4 (Для формата A8R8G8B8 размер так считается)

     if (not IsSpecial) and (LineBytes < Rect.Pitch) then
     begin
       for I := 0 to H - 1 do
         Move(PByteArray(Bits)[I * LineBytes], PByteArray(Rect.pBits)[I * Rect.Pitch], LineBytes);
     end
     else
       Move(Bits^, Rect.pBits^, Size);
    end;

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

       If LoadDds2(FileName, W, H, pScr, Size) then
       try
         If not CreateTexture(W, H, D3DFMT_A8R8G8B8) then Exit;

         If DXCheck(FHandle.LockRect(0, LRect, nil, 0)) then
         try
           FillLockedRectWithImage(LRect, W, H, Size, pScr);
         finally
           Result:= DXCheck(FHandle.UnlockRect(0));
         end;
       finally
         FreeMem(pScr);
       end;
     end else
       Result:= DXCheck(D3DXCreateTextureFromFile(Device.GetHandle, XPChar(FileName), FHandle));

     If Result
     then GetInfo;
    end;




    В результате AV.
  • eXAAAXe (27.05.11 02:38) [13]
    Вот информация о нужном ПОКА мне формате D3DFMT_A8R8G8B8:


    (*
    A8R8G8B8Info: TImageFormatInfo = (
       Format: ifA8R8G8B8;
       Name: 'A8R8G8B8';
       BytesPerPixel: 4;
       ChannelCount: 4;
       HasAlphaChannel: True;
       GetPixelsSize: GetStdPixelsSize;
       CheckDimensions: CheckStdDimensions;
       GetPixel32: GetPixel32ifA8R8G8B8;
       GetPixelFP: GetPixelFPifA8R8G8B8;
       SetPixel32: SetPixel32ifA8R8G8B8;
       SetPixelFP: SetPixelFPifA8R8G8B8);
    *)



  • CrytoGen (27.05.11 09:46) [14]
    попробуйте вывести, полученный при загрузке, буфер на обычный canvas через pixels. если будет работать, то проблема не в загрузке. учитесь локализовать ошибки.
  • Sapersky (27.05.11 12:22) [15]
    Автор, а какая вообще цель?
    Сделать самому - ну тогда нужно не пытаться скроить что-то из надёрганных кусочков, а разбираться, как оно работает и писать осмысленный код, чётко понимая что он делает.

    Для начала - представлять, в каком виде данные лежат в памяти и что мы делаем той или иной манипуляцией с указателями. Cложно работать с указателями - ну можно без, использовать что-то вроде:
     PByteArr = ^TByteArr;
     TByteArr = array [0..MAXINT-1] of Byte;
    Var
     Src, Dst : PByteArr;

    Src := PByteArr(SrcData); ...
    и работать исключительно с индексами, т.е. Src[n] берёт n-ый байт от начала блока данных.

    Или можно временно перегнать данные в дин. массив (их содержимое видно при отладке) + подготовить маленькую специально нарисованную текстурку, у которой известно где какие пиксели должны быть. Хотя в поздних версиях Delphi вроде можно и содержимое обычных указателей смотреть.

    Сложно/лень? Ну так какая проблема, всё уже написано до нас в D3DX и Vampyre.
  • eXAAAXe (27.05.11 22:51) [16]


    > CrytoGen   (27.05.11 09:46) [14]
    > попробуйте вывести, полученный при загрузке, буфер на обычный
    > canvas через pixels. если будет работать, то проблема не
    > в загрузке. учитесь локализовать ошибки.


    Сам dds чую загружается правильно.
    А вот заливается в текстуру нет.
    Ведь по аналогии с бмп не работает.

    > Sapersky   (27.05.11 12:22) [15]

    > Ну так какая проблема, всё уже написано до нас в D3DX и
    > Vampyre.


    Таскать ддллы Д3ДХ не хочется и Вампира таскать тоже не желательно.
    Ведь по сути одного формата ддс. хватит.


    > Автор, а какая вообще цель?
    > Сделать самому - ну тогда нужно не пытаться скроить что-то из > > надёрганных кусочков, а разбираться, как оно работает и писать осмысленный > код, чётко понимая что он делает.


    Код пишу полностью сам.
    Загрузка ддс. самая простая из всех форматов 2Д-изображений.
    Считать хидер, определить формат и считать данные - все!


    > Для начала - представлять, в каком виде данные лежат в памяти и что мы > делаем той или иной манипуляцией с указателями. Cложно работать с > указателями - ну можно без, использовать что-то вроде:


    Да, надо почитать по теории хранения изображений.
  • Sapersky (28.05.11 01:31) [17]
    Таскать ддллы Д3ДХ не хочется и Вампира таскать тоже не желательно.

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

    Код пишу полностью сам.

    Я просто не мог понять, как можно самому и осмысленно написать:
    LONGINT(Result):= LONGINT(pScr) + ((W + Bpp + 7) div 8);
    и вызывать это в вертикальном цикле. Сразу же видно, что Y никак не используется.
  • eXAAAXe (28.05.11 03:12) [18]
    > Sapersky   (28.05.11 01:31) [17]
    > Я просто не мог понять, как можно самому и осмысленно написать:

    Действительно, спасибо.
    Впопыхах так написал и не проверил как уже говорил по аналогии с бмп. :)

    Правильно будет так:


    function GetDdsScanLine(Row, Bpp: LongWord): Pointer;
     begin
       // LONGINT(Result):= LONGINT(pScr) + (Row * (((W * Bpp + 3) div 4)) * 4); // Так говорит Вампир.
       LONGINT(Result):= LONGINT(pScr) + (Row * ((W + Bpp + 7) div 8));          // Так говорит MSDN.
     end;




    Но результат тот же.
  • eXAAAXe (29.05.11 01:46) [19]
    Проверил загрузку DDS в ОпенGL. (Немного изменив)
    Работает как надо. Т.е. загрузка самого изображения правильная.
    А вот как залить RGBA изображение в D3D текстуру не понятно.
    В GL загрузка сделана просто, передаешь указатель на данные и все.
    А в DX надо какие-то питчи учитывать. >_<

    Заливающая функция FillLockedRectWithImage из Вампира - работает
    некорректно. Хотя вроде универсальна.
 
Конференция "Игры" » DDS-Загрузка [Delphi, Windows]
Есть новые Нет новых   [118487   +56][b:0][p:0.008]