|
|
@@ -591,7 +591,7 @@ type |
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
TglBitmapFormat = ( |
|
|
|
tfEmpty = 0, |
|
|
|
tfEmpty = 0, //must be smallest value! |
|
|
|
|
|
|
|
tfAlpha4, |
|
|
|
tfAlpha8, |
|
|
@@ -1609,8 +1609,6 @@ end; |
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
function FormatGetSupportedFiles(const aFormat: TglBitmapFormat): TglBitmapFileTypes; |
|
|
|
begin |
|
|
|
result := [ftDDS]; |
|
|
|
|
|
|
|
if (aFormat in [ |
|
|
|
//4 bbp |
|
|
|
tfLuminance4, |
|
|
@@ -1646,9 +1644,29 @@ begin |
|
|
|
tfRGB10A2, tfRGBA8, tfBGR10A2, tfBGRA8]) then |
|
|
|
result := result + [ftTGA]; |
|
|
|
|
|
|
|
//TODO Supported File Formats! |
|
|
|
if (aFormat in [ |
|
|
|
//8 bpp |
|
|
|
tfAlpha8, tfLuminance8, tfLuminance4Alpha4, tfLuminance6Alpha2, |
|
|
|
tfR3G3B2, tfRGBA2, tfBGRA2, |
|
|
|
|
|
|
|
//16 bpp |
|
|
|
tfAlpha16, tfLuminance16, tfLuminance8Alpha8, tfLuminance12Alpha4, |
|
|
|
tfRGB4, tfR5G6B5, tfRGB5, tfRGBA4, tfRGB5A1, |
|
|
|
tfBGR4, tfB5G6R5, tfBGR5, tfBGRA4, tfBGR5A1, |
|
|
|
|
|
|
|
(* |
|
|
|
//24 bpp |
|
|
|
tfRGB8, tfBGR8, |
|
|
|
|
|
|
|
//32 bbp |
|
|
|
tfLuminance16Alpha16, |
|
|
|
tfRGBA8, tfRGB10A2, |
|
|
|
tfBGRA8, tfBGR10A2, |
|
|
|
|
|
|
|
//compressed |
|
|
|
tfS3tcDtx1RGBA, tfS3tcDtx3RGBA, tfS3tcDtx5RGBA]) then |
|
|
|
result := result + [ftDDS]; |
|
|
|
|
|
|
|
(* TODO |
|
|
|
{$IFDEF GLB_SUPPORT_PNG_WRITE} |
|
|
|
if aFormat in [ |
|
|
|
tfAlpha4, tfAlpha8, tfAlpha12, tfAlpha16, |
|
|
@@ -6974,7 +6992,7 @@ end; |
|
|
|
//DDS///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
const |
|
|
|
DDS_MAGIC = $20534444; |
|
|
|
DDS_MAGIC: Cardinal = $20534444; |
|
|
|
|
|
|
|
// DDS_header.dwFlags |
|
|
|
DDSD_CAPS = $00000001; |
|
|
@@ -6988,6 +7006,7 @@ const |
|
|
|
|
|
|
|
// DDS_header.sPixelFormat.dwFlags |
|
|
|
DDPF_ALPHAPIXELS = $00000001; |
|
|
|
DDPF_ALPHA = $00000002; |
|
|
|
DDPF_FOURCC = $00000004; |
|
|
|
DDPF_INDEXED = $00000020; |
|
|
|
DDPF_RGB = $00000040; |
|
|
@@ -7032,7 +7051,6 @@ type |
|
|
|
end; |
|
|
|
|
|
|
|
TDDSHeader = packed record |
|
|
|
dwMagic: Cardinal; |
|
|
|
dwSize: Cardinal; |
|
|
|
dwFlags: Cardinal; |
|
|
|
dwHeight: Cardinal; |
|
|
@@ -7050,8 +7068,14 @@ type |
|
|
|
function TglBitmap.LoadDDS(const aStream: TStream): Boolean; |
|
|
|
var |
|
|
|
Header: TDDSHeader; |
|
|
|
Converter: TbmpBitfieldFormat; |
|
|
|
|
|
|
|
function GetDDSFormat: TglBitmapFormat; |
|
|
|
var |
|
|
|
fd: TFormatDescriptor; |
|
|
|
i: Integer; |
|
|
|
Range: TglBitmapColorRec; |
|
|
|
match: Boolean; |
|
|
|
begin |
|
|
|
result := tfEmpty; |
|
|
|
with Header.PixelFormat do begin |
|
|
@@ -7062,66 +7086,79 @@ var |
|
|
|
D3DFMT_DXT3: result := tfS3tcDtx3RGBA; |
|
|
|
D3DFMT_DXT5: result := tfS3tcDtx5RGBA; |
|
|
|
end; |
|
|
|
end else |
|
|
|
|
|
|
|
// RGB |
|
|
|
if (dwFlags and (DDPF_RGB or DDPF_ALPHAPIXELS or DDPF_LUMINANCE)) > 0 then begin |
|
|
|
case dwRGBBitCount of |
|
|
|
8: begin |
|
|
|
if ((dwFlags and DDPF_ALPHAPIXELS) > 0) then |
|
|
|
result := tfAlpha8 |
|
|
|
else if ((dwFlags and DDPF_LUMINANCE) > 0) then |
|
|
|
result := tfLuminance8; |
|
|
|
end; |
|
|
|
|
|
|
|
16: begin |
|
|
|
if ((dwFlags and DDPF_ALPHAPIXELS) > 0) then begin |
|
|
|
case CountSetBits(dwRBitMask) of |
|
|
|
5: result := tfRGB5A1; |
|
|
|
4: result := tfRGBA4; |
|
|
|
else |
|
|
|
result := tfLuminance8Alpha8; |
|
|
|
end; |
|
|
|
end else if (CountSetBits(dwGBitMask) = 6) then |
|
|
|
result := tfR5G6B5 |
|
|
|
else |
|
|
|
result := tfRGB5; |
|
|
|
end; |
|
|
|
end else if ((Header.PixelFormat.dwFlags and (DDPF_RGB or DDPF_ALPHAPIXELS or DDPF_LUMINANCE)) > 0) then begin |
|
|
|
|
|
|
|
//find matching format |
|
|
|
for result := High(TglBitmapFormat) downto Low(TglBitmapFormat) do begin |
|
|
|
fd := TFormatDescriptor.Get(result); |
|
|
|
if fd.MaskMatch(dwRBitMask, dwGBitMask, dwBBitMask, dwABitMask) and |
|
|
|
(8 * fd.PixelSize = dwRGBBitCount) then |
|
|
|
exit; |
|
|
|
end; |
|
|
|
|
|
|
|
24: begin |
|
|
|
result := tfRGB8; |
|
|
|
end; |
|
|
|
//find format with same Range |
|
|
|
Range.r := dwRBitMask; |
|
|
|
Range.g := dwGBitMask; |
|
|
|
Range.b := dwBBitMask; |
|
|
|
Range.a := dwABitMask; |
|
|
|
for i := 0 to 3 do begin |
|
|
|
while ((Range.arr[i] and 1) = 0) and (Range.arr[i] > 0) do |
|
|
|
Range.arr[i] := Range.arr[i] shr 1; |
|
|
|
end; |
|
|
|
for result := High(TglBitmapFormat) downto Low(TglBitmapFormat) do begin |
|
|
|
fd := TFormatDescriptor.Get(result); |
|
|
|
match := true; |
|
|
|
for i := 0 to 3 do |
|
|
|
if (fd.Range.arr[i] <> Range.arr[i]) then begin |
|
|
|
match := false; |
|
|
|
break; |
|
|
|
end; |
|
|
|
if match then |
|
|
|
break; |
|
|
|
end; |
|
|
|
|
|
|
|
32: begin |
|
|
|
if CountSetBits(dwRBitMask) = 10 then |
|
|
|
result := tfRGB10A2 |
|
|
|
else |
|
|
|
result := tfRGBA8; |
|
|
|
end; |
|
|
|
//no format with same range found -> use default |
|
|
|
if (result = tfEmpty) then begin |
|
|
|
if (dwABitMask > 0) then |
|
|
|
result := tfBGRA8 |
|
|
|
else |
|
|
|
result := tfBGR8; |
|
|
|
end; |
|
|
|
|
|
|
|
if (dwRBitMask <> 0) and (dwBBitMask <> 0) and (dwRBitMask > dwBBitMask) then |
|
|
|
result := TFormatDescriptor.Get(result).RGBInverted; |
|
|
|
Converter := TbmpBitfieldFormat.Create; |
|
|
|
Converter.RedMask := dwRBitMask; |
|
|
|
Converter.GreenMask := dwGBitMask; |
|
|
|
Converter.BlueMask := dwBBitMask; |
|
|
|
Converter.AlphaMask := dwABitMask; |
|
|
|
Converter.PixelSize := dwRGBBitCount / 8; |
|
|
|
end; |
|
|
|
end; |
|
|
|
end; |
|
|
|
|
|
|
|
var |
|
|
|
StreamPos: Int64; |
|
|
|
Y, LineSize: Cardinal; |
|
|
|
RowSize: Cardinal; |
|
|
|
NewImage, TmpData: PByte; |
|
|
|
x, y, j, LineSize, RowSize, Magic: Cardinal; |
|
|
|
NewImage, TmpData, RowData, SrcData: PByte; |
|
|
|
SourceMD, DestMD: Pointer; |
|
|
|
Pixel: TglBitmapPixelData; |
|
|
|
ddsFormat: TglBitmapFormat; |
|
|
|
FormatDesc: TFormatDescriptor; |
|
|
|
|
|
|
|
begin |
|
|
|
result := false; |
|
|
|
|
|
|
|
// Header |
|
|
|
result := false; |
|
|
|
Converter := nil; |
|
|
|
StreamPos := aStream.Position; |
|
|
|
aStream.Read(Header, sizeof(Header)); |
|
|
|
|
|
|
|
if (Header.dwMagic <> DDS_MAGIC) or (Header.dwSize <> 124) or |
|
|
|
// Magic |
|
|
|
aStream.Read(Magic, sizeof(Magic)); |
|
|
|
if (Magic <> DDS_MAGIC) then begin |
|
|
|
aStream.Position := StreamPos; |
|
|
|
exit; |
|
|
|
end; |
|
|
|
|
|
|
|
//Header |
|
|
|
aStream.Read(Header, sizeof(Header)); |
|
|
|
if (Header.dwSize <> SizeOf(Header)) or |
|
|
|
((Header.dwFlags and (DDSD_PIXELFORMAT or DDSD_CAPS or DDSD_WIDTH or DDSD_HEIGHT)) <> |
|
|
|
(DDSD_PIXELFORMAT or DDSD_CAPS or DDSD_WIDTH or DDSD_HEIGHT)) then |
|
|
|
begin |
|
|
@@ -7133,39 +7170,74 @@ begin |
|
|
|
raise EglBitmapException.Create('LoadDDS - CubeMaps are not supported'); |
|
|
|
|
|
|
|
ddsFormat := GetDDSFormat; |
|
|
|
if (ddsFormat = tfEmpty) then |
|
|
|
raise EglBitmapException.Create('LoadDDS - unsupported Pixelformat found.'); |
|
|
|
|
|
|
|
FormatDesc := TFormatDescriptor.Get(ddsFormat); |
|
|
|
LineSize := Trunc(Header.dwWidth * FormatDesc.PixelSize); |
|
|
|
GetMem(NewImage, Header.dwHeight * LineSize); |
|
|
|
try |
|
|
|
TmpData := NewImage; |
|
|
|
|
|
|
|
// Compressed |
|
|
|
if ((Header.PixelFormat.dwFlags and DDPF_FOURCC) > 0) then begin |
|
|
|
RowSize := Header.dwPitchOrLinearSize div Header.dwWidth; |
|
|
|
for Y := 0 to Header.dwHeight-1 do begin |
|
|
|
aStream.Read(TmpData^, RowSize); |
|
|
|
Inc(TmpData, LineSize); |
|
|
|
end; |
|
|
|
end else |
|
|
|
|
|
|
|
// Uncompressed |
|
|
|
if (Header.PixelFormat.dwFlags and (DDPF_RGB or DDPF_ALPHAPIXELS or DDPF_LUMINANCE)) > 0 then begin |
|
|
|
RowSize := (Header.PixelFormat.dwRGBBitCount * Header.dwWidth) shr 3; |
|
|
|
for Y := 0 to Header.dwHeight-1 do begin |
|
|
|
aStream.Read(TmpData^, RowSize); |
|
|
|
Inc(TmpData, LineSize); |
|
|
|
end; |
|
|
|
end else |
|
|
|
if (ddsFormat = tfEmpty) then |
|
|
|
raise EglBitmapException.Create('LoadDDS - unsupported Pixelformat found.'); |
|
|
|
|
|
|
|
SetDataPointer(NewImage, ddsFormat, Header.dwWidth, Header.dwHeight); |
|
|
|
result := true; |
|
|
|
except |
|
|
|
FreeMem(NewImage); |
|
|
|
raise; |
|
|
|
FormatDesc := TFormatDescriptor.Get(ddsFormat); |
|
|
|
LineSize := Trunc(Header.dwWidth * FormatDesc.PixelSize); |
|
|
|
GetMem(NewImage, Header.dwHeight * LineSize); |
|
|
|
try |
|
|
|
TmpData := NewImage; |
|
|
|
|
|
|
|
//Converter needed |
|
|
|
if Assigned(Converter) then begin |
|
|
|
RowSize := Round(Header.dwWidth * Header.PixelFormat.dwRGBBitCount / 8); |
|
|
|
GetMem(RowData, RowSize); |
|
|
|
SourceMD := Converter.CreateMappingData; |
|
|
|
DestMD := FormatDesc.CreateMappingData; |
|
|
|
try |
|
|
|
for y := 0 to Header.dwHeight-1 do begin |
|
|
|
TmpData := NewImage + y * LineSize; |
|
|
|
SrcData := RowData; |
|
|
|
aStream.Read(SrcData^, RowSize); |
|
|
|
for x := 0 to Header.dwWidth-1 do begin |
|
|
|
Converter.Unmap(SrcData, Pixel, SourceMD); |
|
|
|
//TODO use converter function |
|
|
|
for j := 0 to 3 do |
|
|
|
if (Converter.Range.arr[j] <> FormatDesc.Range.arr[j]) then begin |
|
|
|
if (Converter.Range.arr[j] > 0) then |
|
|
|
Pixel.Data.arr[j] := Round(Pixel.Data.arr[j] / Converter.Range.arr[j] * FormatDesc.Range.arr[j]) |
|
|
|
else |
|
|
|
Pixel.Data.arr[j] := 0; |
|
|
|
end; |
|
|
|
FormatDesc.Map(Pixel, TmpData, DestMD); |
|
|
|
end; |
|
|
|
end; |
|
|
|
finally |
|
|
|
Converter.FreeMappingData(SourceMD); |
|
|
|
FormatDesc.FreeMappingData(DestMD); |
|
|
|
FreeMem(RowData); |
|
|
|
end; |
|
|
|
end else |
|
|
|
|
|
|
|
// Compressed |
|
|
|
if ((Header.PixelFormat.dwFlags and DDPF_FOURCC) > 0) then begin |
|
|
|
RowSize := Header.dwPitchOrLinearSize div Header.dwWidth; |
|
|
|
for Y := 0 to Header.dwHeight-1 do begin |
|
|
|
aStream.Read(TmpData^, RowSize); |
|
|
|
Inc(TmpData, LineSize); |
|
|
|
end; |
|
|
|
end else |
|
|
|
|
|
|
|
// Uncompressed |
|
|
|
if (Header.PixelFormat.dwFlags and (DDPF_RGB or DDPF_ALPHAPIXELS or DDPF_LUMINANCE)) > 0 then begin |
|
|
|
RowSize := (Header.PixelFormat.dwRGBBitCount * Header.dwWidth) shr 3; |
|
|
|
for Y := 0 to Header.dwHeight-1 do begin |
|
|
|
aStream.Read(TmpData^, RowSize); |
|
|
|
Inc(TmpData, LineSize); |
|
|
|
end; |
|
|
|
end else |
|
|
|
raise EglBitmapException.Create('LoadDDS - unsupported Pixelformat found.'); |
|
|
|
|
|
|
|
SetDataPointer(NewImage, ddsFormat, Header.dwWidth, Header.dwHeight); |
|
|
|
result := true; |
|
|
|
except |
|
|
|
FreeMem(NewImage); |
|
|
|
raise; |
|
|
|
end; |
|
|
|
finally |
|
|
|
FreeAndNil(Converter); |
|
|
|
end; |
|
|
|
end; |
|
|
|
|
|
|
@@ -7173,55 +7245,55 @@ end; |
|
|
|
procedure TglBitmap.SaveDDS(const aStream: TStream); |
|
|
|
var |
|
|
|
Header: TDDSHeader; |
|
|
|
Pix: TglBitmapPixelData; |
|
|
|
FormatDesc: TFormatDescriptor; |
|
|
|
begin |
|
|
|
//if not FormatIsUncompressed(InternalFormat) then |
|
|
|
// raise EglBitmapUnsupportedFormatFormat.Create('SaveDDS - ' + UNSUPPORTED_FORMAT); |
|
|
|
if not (ftDDS in FormatGetSupportedFiles(Format)) then |
|
|
|
raise EglBitmapUnsupportedFormatFormat.Create('SaveDDS - ' + UNSUPPORTED_FORMAT); |
|
|
|
|
|
|
|
(* TODO if Format = tfAlpha8 then |
|
|
|
FORMAT_DESCRIPTORS[tfLuminance8].PreparePixel(Pix); |
|
|
|
else *) |
|
|
|
TFormatDescriptor.Get(Format).PreparePixel(Pix); |
|
|
|
FormatDesc := TFormatDescriptor.Get(Format); |
|
|
|
|
|
|
|
// Generell |
|
|
|
FillChar(Header, SizeOf(Header), 0); |
|
|
|
Header.dwMagic := DDS_MAGIC; |
|
|
|
Header.dwSize := 124; |
|
|
|
Header.dwFlags := DDSD_PITCH or DDSD_CAPS or DDSD_PIXELFORMAT; |
|
|
|
|
|
|
|
if Width > 0 then begin |
|
|
|
Header.dwWidth := Width; |
|
|
|
Header.dwFlags := Header.dwFlags or DDSD_WIDTH; |
|
|
|
end; |
|
|
|
|
|
|
|
if Height > 0 then begin |
|
|
|
Header.dwHeight := Height; |
|
|
|
Header.dwFlags := Header.dwFlags or DDSD_HEIGHT; |
|
|
|
end; |
|
|
|
Header.dwSize := SizeOf(Header); |
|
|
|
Header.dwFlags := DDSD_WIDTH or DDSD_HEIGHT or DDSD_CAPS or DDSD_PIXELFORMAT; |
|
|
|
|
|
|
|
Header.dwPitchOrLinearSize := fRowSize; |
|
|
|
Header.dwMipMapCount := 1; |
|
|
|
Header.dwWidth := Max(1, Width); |
|
|
|
Header.dwHeight := Max(1, Height); |
|
|
|
|
|
|
|
// Caps |
|
|
|
Header.Caps.dwCaps1 := DDSCAPS_TEXTURE; |
|
|
|
|
|
|
|
// Pixelformat |
|
|
|
Header.PixelFormat.dwSize := Sizeof(Header.PixelFormat); |
|
|
|
Header.PixelFormat.dwFlags := DDPF_RGB; |
|
|
|
Header.PixelFormat.dwSize := sizeof(Header); |
|
|
|
if (FormatDesc.IsCompressed) then begin |
|
|
|
Header.PixelFormat.dwFlags := Header.PixelFormat.dwFlags or DDPF_FOURCC; |
|
|
|
case Format of |
|
|
|
tfS3tcDtx1RGBA: Header.PixelFormat.dwFourCC := D3DFMT_DXT1; |
|
|
|
tfS3tcDtx3RGBA: Header.PixelFormat.dwFourCC := D3DFMT_DXT3; |
|
|
|
tfS3tcDtx5RGBA: Header.PixelFormat.dwFourCC := D3DFMT_DXT5; |
|
|
|
end; |
|
|
|
end else if (Format in [tfAlpha8, tfAlpha16]) then begin |
|
|
|
Header.PixelFormat.dwFlags := Header.PixelFormat.dwFlags or DDPF_ALPHA; |
|
|
|
Header.PixelFormat.dwRGBBitCount := Round(FormatDesc.PixelSize * 8); |
|
|
|
Header.PixelFormat.dwABitMask := FormatDesc.AlphaMask; |
|
|
|
end else if (FormatDesc.RedMask = FormatDesc.GreenMask) and (FormatDesc.GreenMask = FormatDesc.BlueMask) then begin |
|
|
|
Header.PixelFormat.dwFlags := Header.PixelFormat.dwFlags or DDPF_LUMINANCE; |
|
|
|
Header.PixelFormat.dwRGBBitCount := Round(FormatDesc.PixelSize * 8); |
|
|
|
Header.PixelFormat.dwRBitMask := FormatDesc.RedMask; |
|
|
|
Header.PixelFormat.dwABitMask := FormatDesc.AlphaMask; |
|
|
|
end else begin |
|
|
|
Header.PixelFormat.dwFlags := Header.PixelFormat.dwFlags or DDPF_RGB; |
|
|
|
Header.PixelFormat.dwRGBBitCount := Round(FormatDesc.PixelSize * 8); |
|
|
|
Header.PixelFormat.dwRBitMask := FormatDesc.RedMask; |
|
|
|
Header.PixelFormat.dwGBitMask := FormatDesc.GreenMask; |
|
|
|
Header.PixelFormat.dwBBitMask := FormatDesc.BlueMask; |
|
|
|
Header.PixelFormat.dwABitMask := FormatDesc.AlphaMask; |
|
|
|
end; |
|
|
|
|
|
|
|
(* TODO tfAlpha8 |
|
|
|
if FORMAT_DESCRIPTORS[Format].HasAlpha and (Format <> tfAlpha8) then |
|
|
|
if (FormatDesc.HasAlpha) then |
|
|
|
Header.PixelFormat.dwFlags := Header.PixelFormat.dwFlags or DDPF_ALPHAPIXELS; |
|
|
|
*) |
|
|
|
|
|
|
|
FormatDesc := TFormatDescriptor.Get(Format); |
|
|
|
Header.PixelFormat.dwRGBBitCount := Trunc(FormatDesc.PixelSize * 8); |
|
|
|
Header.PixelFormat.dwRBitMask := FormatDesc.RedMask; |
|
|
|
Header.PixelFormat.dwGBitMask := FormatDesc.GreenMask; |
|
|
|
Header.PixelFormat.dwBBitMask := FormatDesc.BlueMask; |
|
|
|
Header.PixelFormat.dwABitMask := FormatDesc.AlphaMask; |
|
|
|
|
|
|
|
aStream.Write(DDS_MAGIC, sizeof(DDS_MAGIC)); |
|
|
|
aStream.Write(Header, SizeOf(Header)); |
|
|
|
aStream.Write(Data^, FormatDesc.GetSize(Dimension)); |
|
|
|
end; |
|
|
|