-
Всем привет. Пытаюсь загрузить dds. Памяти под изображение выделяю: dwPOLS * Height. Изображение без мипмапов, формат D3DFMT_A8R8G8B8:
function TTexture.Load2(const FileName: string; Custom: boolean = False): boolean;
var
P : PRGBA; 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. Что не так?
-
что такое LoadDds ? вы какие-то странные функции используете и не проверяете как они работают.
-
Вот:
function LoadDds(const FileName: XString; var W, H: LongWord; var Data: Pointer; var Format: TD3DFormat): boolean;
var
DDS : TDDS; 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 (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;
GetMem(Data, Size);
Read(Data, Size);
Result:= Assigned(Data);
end;
end;
end;
finally
Free;
end;
end;
-
Вот так правильней:
function LoadDds(const FileName: XString; var W, H: LongWord; var Data: Pointer; var Format: TD3DFormat): boolean;
var
DDS : TDDS; 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 (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)); LogPrint('2) ' + IntToStr(((W + dwRGBBitCount + 7) div 8) * H));
LogPrint('3) ' + IntToStr(W * H * 4));
Size:= dwPOLS;
GetMem(Data, Size);
Read(Data, Size);
Result:= Assigned(Data);
end;
end;
end;
finally
Free;
end;
end;
1) Почему питч вычисленный в ручную (2)) меньше записанного в хидере? Хотя делалось по MSDN. 2) В итоге чёрная текстура.
-
Сдаётся мне что чёрная текстура потому, что неправильно грузите данные. Вы трассировку делали? Что у вас в хидер попадает смотрели? может вы неправильно хидер читаете? Как у вас выглядит соответствующая структура?
-
Size of structure. This member must be set to 124.
проверяли?
-
>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.
-
Теперь можете собрать у себя и проверить.
-
Неее :) Спасибо конечно, но это ваша работа. Вот это ещё покажите CreateTexture(W, H, Format).
-
Тут то всё в порядке, ведь загрузка бмп нормально работала. :)
function TTexture.CreateTexture(W, H: LongWord; Format: TD3DFormat): boolean;
begin
Result:= False;
If not Device.IsCaps(dcPow2) then 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;
-
> CrytoGen (26.05.11 21:40) [8]
> Неее :) Спасибо конечно, но это ваша работа.
Я говорю - можете у себя проверить код, чтоб помочь разобраться так сказать. :)
-
В PitchDds фигня написана, во всяком случае, с учётом места, где оно вызывается - точно фигня.
В Vampyre (Imaging) library есть загрузка DDS.
-
> 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;
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.
-
Вот информация о нужном ПОКА мне формате D3DFMT_A8R8G8B8:
-
попробуйте вывести, полученный при загрузке, буфер на обычный canvas через pixels. если будет работать, то проблема не в загрузке. учитесь локализовать ошибки.
-
Автор, а какая вообще цель? Сделать самому - ну тогда нужно не пытаться скроить что-то из надёрганных кусочков, а разбираться, как оно работает и писать осмысленный код, чётко понимая что он делает.
Для начала - представлять, в каком виде данные лежат в памяти и что мы делаем той или иной манипуляцией с указателями. Cложно работать с указателями - ну можно без, использовать что-то вроде: PByteArr = ^TByteArr; TByteArr = array [0..MAXINT-1] of Byte; Var Src, Dst : PByteArr;
Src := PByteArr(SrcData); ... и работать исключительно с индексами, т.е. Src[n] берёт n-ый байт от начала блока данных.
Или можно временно перегнать данные в дин. массив (их содержимое видно при отладке) + подготовить маленькую специально нарисованную текстурку, у которой известно где какие пиксели должны быть. Хотя в поздних версиях Delphi вроде можно и содержимое обычных указателей смотреть.
Сложно/лень? Ну так какая проблема, всё уже написано до нас в D3DX и Vampyre.
-
> CrytoGen (27.05.11 09:46) [14] > попробуйте вывести, полученный при загрузке, буфер на обычный > canvas через pixels. если будет работать, то проблема не > в загрузке. учитесь локализовать ошибки.
Сам dds чую загружается правильно. А вот заливается в текстуру нет. Ведь по аналогии с бмп не работает.
> Sapersky (27.05.11 12:22) [15]
> Ну так какая проблема, всё уже написано до нас в D3DX и > Vampyre.
Таскать ддллы Д3ДХ не хочется и Вампира таскать тоже не желательно. Ведь по сути одного формата ддс. хватит.
> Автор, а какая вообще цель? > Сделать самому - ну тогда нужно не пытаться скроить что-то из > > надёрганных кусочков, а разбираться, как оно работает и писать осмысленный > код, чётко понимая что он делает.
Код пишу полностью сам. Загрузка ддс. самая простая из всех форматов 2Д-изображений. Считать хидер, определить формат и считать данные - все!
> Для начала - представлять, в каком виде данные лежат в памяти и что мы > делаем той или иной манипуляцией с указателями. Cложно работать с > указателями - ну можно без, использовать что-то вроде:
Да, надо почитать по теории хранения изображений.
-
Таскать ддллы Д3ДХ не хочется и Вампира таскать тоже не желательно.
Вампира я сам не использовал - но думаю, что если все форматы не подключать, то много тащить не придётся, ну может 100-200 кб к экзешнику добавит.
Код пишу полностью сам.
Я просто не мог понять, как можно самому и осмысленно написать: LONGINT(Result):= LONGINT(pScr) + ((W + Bpp + 7) div 8); и вызывать это в вертикальном цикле. Сразу же видно, что Y никак не используется.
-
> Sapersky (28.05.11 01:31) [17]> Я просто не мог понять, как можно самому и осмысленно написать: Действительно, спасибо. Впопыхах так написал и не проверил как уже говорил по аналогии с бмп. :) Правильно будет так:
function GetDdsScanLine(Row, Bpp: LongWord): Pointer;
begin
LONGINT(Result):= LONGINT(pScr) + (Row * ((W + Bpp + 7) div 8)); end;
Но результат тот же.
-
Проверил загрузку DDS в ОпенGL. (Немного изменив) Работает как надо. Т.е. загрузка самого изображения правильная. А вот как залить RGBA изображение в D3D текстуру не понятно. В GL загрузка сделана просто, передаешь указатель на данные и все. А в DX надо какие-то питчи учитывать. >_< Заливающая функция FillLockedRectWithImage из Вампира - работает некорректно. Хотя вроде универсальна.
|