Last active
August 29, 2015 14:05
-
-
Save XProger/43cf20386b18aecebbcf to your computer and use it in GitHub Desktop.
DDS texture loader (2d, cubemap, OpenGL)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
constructor TTexture.Create(const FileName: string); | |
type | |
TLoadFormat = (lfNULL, lfDXT1c, lfDXT1a, lfDXT3, lfDXT5, lfA8, lfL8, lfAL8, | |
lfBGRA8, lfBGR8, lfBGR5A1, lfBGR565, lfBGRA4, lfR16F, lfR32F, | |
lfGR16F, lfGR32F, lfBGRA16F, lfBGRA32F); | |
TDDS = record | |
dwMagic : LongWord; | |
dwSize : LongInt; | |
dwFlags : LongWord; | |
dwHeight : LongWord; | |
dwWidth : LongWord; | |
dwPOLSize : LongWord; | |
dwDepth : LongWord; | |
dwMipMapCount : LongInt; | |
SomeData1 : array [0..11] of LongWord; | |
pfFlags : LongWord; | |
pfFourCC : LongWord; | |
pfRGBbpp : LongWord; | |
pfRMask : LongWord; | |
pfGMask : LongWord; | |
pfBMask : LongWord; | |
pfAMask : LongWord; | |
dwCaps1 : LongWord; | |
dwCaps2 : LongWord; | |
SomeData3 : array [0..2] of LongWord; | |
end; | |
const | |
FOURCC_DXT1 = $31545844; | |
FOURCC_DXT3 = $33545844; | |
FOURCC_DXT5 = $35545844; | |
FOURCC_R16F = $0000006F; | |
FOURCC_G16R16F = $00000070; | |
FOURCC_A16B16G16R16F = $00000071; | |
FOURCC_R32F = $00000072; | |
FOURCC_G32R32F = $00000073; | |
FOURCC_A32B32G32R32F = $00000074; | |
DDPF_ALPHAPIXELS = $01; | |
DDPF_ALPHA = $02; | |
DDPF_FOURCC = $04; | |
DDPF_RGB = $40; | |
DDPF_LUMINANCE = $020000; | |
DDSD_MIPMAPCOUNT = $020000; | |
DDSCAPS2_CUBEMAP = $0200; | |
LoadFormat : array [TLoadFormat] of record | |
Compressed : Boolean; | |
DivSize : Byte; | |
Bytes : Byte; | |
IFormat : TGLConst; | |
EFormat : TGLConst; | |
DataType : TGLConst; | |
end = ( | |
(Compressed: False; DivSize: 1; Bytes: 1; IFormat: GL_FALSE; EFormat: GL_FALSE; DataType: GL_FALSE), | |
(Compressed: True; DivSize: 4; Bytes: 8; IFormat: GL_COMPRESSED_RGB_S3TC_DXT1; EFormat: GL_FALSE; DataType: GL_FALSE), | |
(Compressed: True; DivSize: 4; Bytes: 8; IFormat: GL_COMPRESSED_RGBA_S3TC_DXT1; EFormat: GL_FALSE; DataType: GL_FALSE), | |
(Compressed: True; DivSize: 4; Bytes: 16; IFormat: GL_COMPRESSED_RGBA_S3TC_DXT3; EFormat: GL_FALSE; DataType: GL_FALSE), | |
(Compressed: True; DivSize: 4; Bytes: 16; IFormat: GL_COMPRESSED_RGBA_S3TC_DXT5; EFormat: GL_FALSE; DataType: GL_FALSE), | |
(Compressed: False; DivSize: 1; Bytes: 1; IFormat: GL_ALPHA8; EFormat: GL_ALPHA; DataType: GL_UNSIGNED_BYTE), | |
(Compressed: False; DivSize: 1; Bytes: 1; IFormat: GL_LUMINANCE8; EFormat: GL_LUMINANCE; DataType: GL_UNSIGNED_BYTE), | |
(Compressed: False; DivSize: 1; Bytes: 2; IFormat: GL_LUMINANCE8_ALPHA8; EFormat: GL_LUMINANCE_ALPHA; DataType: GL_UNSIGNED_BYTE), | |
(Compressed: False; DivSize: 1; Bytes: 4; IFormat: GL_RGBA8; EFormat: GL_BGRA; DataType: GL_UNSIGNED_BYTE), | |
(Compressed: False; DivSize: 1; Bytes: 3; IFormat: GL_RGB8; EFormat: GL_BGR; DataType: GL_UNSIGNED_BYTE), | |
(Compressed: False; DivSize: 1; Bytes: 2; IFormat: GL_RGB5_A1; EFormat: GL_BGRA; DataType: GL_UNSIGNED_SHORT_1_5_5_5_REV), | |
(Compressed: False; DivSize: 1; Bytes: 2; IFormat: GL_RGB5; EFormat: GL_RGB; DataType: GL_UNSIGNED_SHORT_5_6_5), | |
(Compressed: False; DivSize: 1; Bytes: 2; IFormat: GL_RGBA4; EFormat: GL_BGRA; DataType: GL_UNSIGNED_SHORT_4_4_4_4_REV), | |
(Compressed: False; DivSize: 1; Bytes: 2; IFormat: GL_R16F; EFormat: GL_RED; DataType: GL_HALF_FLOAT), | |
(Compressed: False; DivSize: 1; Bytes: 4; IFormat: GL_R32F; EFormat: GL_RED; DataType: GL_FLOAT), | |
(Compressed: False; DivSize: 1; Bytes: 4; IFormat: GL_RG16F; EFormat: GL_RG; DataType: GL_HALF_FLOAT), | |
(Compressed: False; DivSize: 1; Bytes: 8; IFormat: GL_RG32F; EFormat: GL_RG; DataType: GL_FLOAT), | |
(Compressed: False; DivSize: 1; Bytes: 8; IFormat: GL_RGBA16F; EFormat: GL_RGBA; DataType: GL_HALF_FLOAT), | |
(Compressed: False; DivSize: 1; Bytes: 16; IFormat: GL_RGBA32F; EFormat: GL_RGBA; DataType: GL_FLOAT) | |
); | |
var | |
Stream : TStream; | |
i, w, h : LongInt; | |
Data : Pointer; | |
LF : TLoadFormat; | |
Samples : LongInt; | |
st : TGLConst; | |
s : LongInt; | |
RMips : LongInt; | |
DDS : TDDS; | |
function GetLoadFormat(const DDS: TDDS): TLoadFormat; | |
begin | |
Result := lfNULL; | |
with DDS do | |
if pfFlags and DDPF_FOURCC = DDPF_FOURCC then | |
begin | |
case pfFourCC of | |
// Compressed | |
FOURCC_DXT1 : | |
if pfFlags xor DDPF_ALPHAPIXELS > 0 then | |
Result := lfDXT1a | |
else | |
Result := lfDXT1c; | |
FOURCC_DXT3 : Result := lfDXT3; | |
FOURCC_DXT5 : Result := lfDXT5; | |
// Float | |
FOURCC_R16F : Result := lfR16F; | |
FOURCC_G16R16F : Result := lfGR16F; | |
FOURCC_A16B16G16R16F : Result := lfBGRA16F; | |
FOURCC_R32F : Result := lfR32F; | |
FOURCC_G32R32F : Result := lfGR32F; | |
FOURCC_A32B32G32R32F : Result := lfBGRA32F; | |
end | |
end else | |
case pfRGBbpp of | |
8 : | |
if (pfFlags and DDPF_LUMINANCE > 0) and (pfRMask xor $FF = 0) then | |
Result := lfL8 | |
else | |
if (pfFlags and DDPF_ALPHA > 0) and (pfAMask xor $FF = 0) then | |
Result := lfA8; | |
16 : | |
if pfFlags and DDPF_ALPHAPIXELS > 0 then | |
begin | |
if (pfFlags and DDPF_LUMINANCE > 0) and (pfRMask xor $FF + pfAMask xor $FF00 = 0) then | |
Result := lfAL8 | |
else | |
if pfFlags and DDPF_RGB > 0 then | |
if pfRMask xor $0F00 + pfGMask xor $00F0 + pfBMask xor $0F + pfAMask xor $F000 = 0 then | |
Result := lfBGRA4 | |
else | |
if pfRMask xor $7C00 + pfGMask xor $03E0 + pfBMask xor $1F + pfAMask xor $8000 = 0 then | |
Result := lfBGR5A1; | |
end else | |
if pfFlags and DDPF_RGB > 0 then | |
if pfRMask xor $F800 + pfGMask xor $07E0 + pfBMask xor $1F = 0 then | |
Result := lfBGR565; | |
24 : | |
if pfRMask xor $FF0000 + pfGMask xor $FF00 + pfBMask xor $FF = 0 then | |
Result := lfBGR8; | |
32 : | |
if pfRMask xor $FF0000 + pfGMask xor $FF00 + pfBMask xor $FF + pfAMask xor $FF000000 = 0 then | |
Result := lfBGRA8; | |
end; | |
end; | |
begin | |
inherited Create(FileName); | |
Stream := TStream.Init(FileName); | |
if Stream = nil then | |
begin | |
FWidth := 1; | |
FHeight := 1; | |
Exit; | |
end; | |
Stream.Read(DDS, SizeOf(DDS)); | |
FWidth := DDS.dwWidth; | |
FHeight := DDS.dwHeight; | |
// Select OpenGL texture format | |
LF := GetLoadFormat(DDS); | |
if LF = lfNULL then | |
begin | |
LogError('Not supported format: "' + FileName + '"'); | |
Stream.Free; | |
Exit; | |
end; | |
with DDS, LoadFormat[LF] do | |
begin | |
if dwFlags and DDSD_MIPMAPCOUNT = 0 then | |
dwMipMapCount := 1; | |
RMips := dwMipMapCount; | |
for i := 0 to dwMipMapCount - 1 do | |
if Min(Width shr i, Height shr i) < 4 then | |
begin | |
RMips := i; | |
break; | |
end; | |
// 2D image | |
Sampler := GL_TEXTURE_2D; | |
Samples := 1; | |
// CubeMap image | |
if dwCaps2 and DDSCAPS2_CUBEMAP > 0 then | |
begin | |
Sampler := GL_TEXTURE_CUBE_MAP; | |
Samples := 6; | |
end; | |
// 3D image | |
///... | |
Data := GetMemory((FWidth div DivSize) * (FHeight div DivSize) * Bytes); | |
gl.GenTextures(1, @FID); | |
gl.BindTexture(Sampler, FID); | |
for s := 0 to Samples - 1 do | |
begin | |
case Sampler of | |
GL_TEXTURE_CUBE_MAP : | |
st := TGLConst(Ord(GL_TEXTURE_CUBE_MAP_POSITIVE_X) + s) | |
else | |
st := Sampler; | |
end; | |
for i := 0 to dwMipMapCount - 1 do | |
begin | |
w := FWidth shr i; | |
h := FHeight shr i; | |
dwSize := ((w div DivSize) * (h div DivSize) * Bytes); | |
if i >= RMips then | |
begin | |
Stream.Pos := Stream.Pos + dwSize; | |
continue; | |
end; | |
Stream.Read(Data^, dwSize); | |
if Compressed then | |
gl.CompressedTexImage2D(st, i, IFormat, w, h, 0, dwSize, Data) | |
else | |
gl.TexImage2D(st, i, IFormat, w, h, 0, EFormat, DataType, Data); | |
end; | |
end; | |
FreeMemory(Data); | |
FMipMap := dwMipMapCount > 1; | |
if FMipMap then | |
gl.TexParameteri(Sampler, GL_TEXTURE_MAX_LEVEL, TGLConst(RMips - 1)); | |
end; | |
Stream.Free; | |
Filter := tfAniso; | |
end; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment