index 504b3fb0cb07af035fbaff8068c022066bab9d87..e53a3ef263fdd9033c454fe49b70b929c0f74685 100644 (file)
+{$MODE DELPHI}
unit e_textures;
{ This unit provides interface to load 24-bit and 32-bit uncompressed images
uses
GL, GLExt, SysUtils, e_log;
+type
+ GLTexture = record
+ id: GLuint;
+ width, height: Word; // real
+ glwidth, glheight: Word; // powerof2
+ u, v: Single; // usually 1.0
+ end;
+
var
- fUseMipmaps: Boolean = False;
+ e_DummyTextures: Boolean = False;
TEXTUREFILTER: Integer = GL_NEAREST;
-function CreateTexture( Width, Height, Format: Word; pData: Pointer ): Integer;
-
+function CreateTexture(var tex: GLTexture; Width, Height, aFormat: Word; pData: Pointer ): Boolean;
+
// Standard set of images loading functions
-function LoadTexture( Filename: String; var Texture: GLuint;
+function LoadTexture( Filename: String; var Texture: GLTexture;
var pWidth, pHeight: Word; Fmt: PWord = nil ): Boolean;
-function LoadTextureEx( Filename: String; var Texture: GLuint;
+function LoadTextureEx( Filename: String; var Texture: GLTexture;
fX, fY, fWidth, fHeight: Word; Fmt: PWord = nil ): Boolean;
-function LoadTextureMem( pData: Pointer; var Texture: GLuint;
+function LoadTextureMem( pData: Pointer; var Texture: GLTexture;
var pWidth, pHeight: Word; Fmt: PWord = nil ): Boolean;
-function LoadTextureMemEx( pData: Pointer; var Texture: GLuint;
+function LoadTextureMemEx( pData: Pointer; var Texture: GLTexture;
fX, fY, fWidth, fHeight: Word; Fmt: PWord = nil ): Boolean;
implementation
-uses BinEditor;
+uses BinEditor, g_options;
+
+
+function AlignP2 (n: Word): Word;
+begin
+ Dec(n);
+ n := n or (n shr 1);
+ n := n or (n shr 2);
+ n := n or (n shr 4);
+ n := n or (n shr 8);
+ n := n or (n shr 16);
+ Inc(n);
+ Result := n;
+end;
+
type
TTGAHeader = packed record
end;
// This is auxiliary function that creates OpenGL texture from raw image data
-function CreateTexture( Width, Height, Format: Word; pData: Pointer ): Integer;
+function CreateTexture (var tex: GLTexture; Width, Height, aFormat: Word; pData: Pointer): Boolean;
var
Texture: GLuint;
begin
- glGenTextures( 1, @Texture );
- glBindTexture( GL_TEXTURE_2D, Texture );
+ tex.width := Width;
+ tex.height := Height;
+ if glLegacyNPOT then
+ begin
+ tex.glwidth := AlignP2(Width);
+ tex.glheight := AlignP2(Height);
+ end
+ else
+ begin
+ tex.glwidth := Width;
+ tex.glheight := Height;
+ end;
+ tex.u := 1;
+ tex.v := 1;
+ if tex.glwidth <> tex.width then tex.u := (tex.width+0.0)/(tex.glwidth+0.0);
+ if tex.glheight <> tex.height then tex.v := (tex.height+0.0)/(tex.glheight+0.0);
- {Texture blends with object background}
- glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
- {Texture does NOT blend with object background}
- // glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
+ if (tex.glwidth <> tex.width) or (tex.glheight <> tex.height) then
+ begin
+ e_WriteLog(Format('NPOT: orig is %ux%u; gl is %ux%u; u=%f; v=%f', [Width, Height, tex.glwidth, tex.glheight, tex.u, tex.v]), MSG_NOTIFY);
+ end;
+
+ if e_DummyTextures then
+ begin
+ tex.id := GLuint(-1);
+ Result := True;
+ Exit;
+ end;
+
+ glGenTextures(1, @Texture);
+ tex.id := Texture;
+ glBindTexture(GL_TEXTURE_2D, Texture);
+
+ // texture blends with object background
+ glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ // texture does NOT blend with object background
+ //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
{
Select a filtering type.
}
// for GL_TEXTURE_MAG_FILTER only first two can be used
- glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TEXTUREFILTER );
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TEXTUREFILTER);
// for GL_TEXTURE_MIN_FILTER all of the above can be used
- glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TEXTUREFILTER );
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TEXTUREFILTER);
- if Format = GL_RGBA then
+ // create empty texture
+ if aFormat = GL_RGBA then
begin
- glTexImage2D( GL_TEXTURE_2D, 0, 4, Width, Height,
- 0, GL_RGBA, GL_UNSIGNED_BYTE, pData );
- end else
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.glwidth, tex.glheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, pData);
+ end
+ else
begin
- glTexImage2D( GL_TEXTURE_2D, 0, 3, Width, Height,
- 0, GL_RGB, GL_UNSIGNED_BYTE, pData );
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex.glwidth, tex.glheight, 0, GL_RGB, GL_UNSIGNED_BYTE, nil);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, Width, Height, GL_RGB, GL_UNSIGNED_BYTE, pData);
end;
-
+
+ // the following is ok too
+ //bindTexture(0);
+ //glTextureSubImage2D(tid, 0, 0, 0, img.width, img.height, GL_RGBA, GL_UNSIGNED_BYTE, img.imageData.bytes.ptr);
+
+ {
+ if (tex.glwidth = tex.glwidth) and (tex.glheight = tex.height) then
+ // easy case
+ if aFormat = GL_RGBA then
+ begin
+ glTexImage2D(GL_TEXTURE_2D, 0, 4, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pData);
+ end
+ else
+ begin
+ glTexImage2D(GL_TEXTURE_2D, 0, 3, Width, Height, 0, GL_RGB, GL_UNSIGNED_BYTE, pData);
+ end;
+ end
+ }
+
glBindTexture(GL_TEXTURE_2D, 0);
- Result := Texture;
+ Result := true;
end;
-function LoadTextureMem( pData: Pointer; var Texture: GLuint;
+function LoadTextureMem( pData: Pointer; var Texture: GLTexture;
var pWidth, pHeight: Word; Fmt: PWord = nil ): Boolean;
var
TGAHeader: TTGAHeader;
Exit;
end;
+ if (TGAHeader.ImageInfo and $c0) <> 0 then
+ begin
+ e_WriteLog('Error loading texture: interleaved TGA', MSG_WARNING);
+ Exit;
+ end;
+
Width := TGAHeader.Width[0] + TGAHeader.Width[1] * 256;
Height := TGAHeader.Height[0] + TGAHeader.Height[1] * 256;
BPP := TGAHeader.BPP;
Back^ := Temp;
end;
+ //if (TGAHeader.ImageInfo and $20) <> 0 then UpsideDown(Image, Width, Height);
+
if ( BPP = 24 ) then
TFmt := GL_RGB
else
TFmt := GL_RGBA;
-
- Texture := CreateTexture( Width, Height, TFmt, Image );
+
+ CreateTexture(Texture, Width, Height, TFmt, Image );
FreeMem( Image );
-
+
if Fmt <> nil then Fmt^ := TFmt;
pWidth := Width;
Result := True;
end;
-function LoadTextureMemEx( pData: Pointer; var Texture: GLuint;
+function LoadTextureMemEx( pData: Pointer; var Texture: GLTexture;
fX, fY, fWidth, fHeight: Word; Fmt: PWord = nil ): Boolean;
var
TGAHeader: TTGAHeader;
Exit;
end;
+ if (TGAHeader.ImageInfo and $c0) <> 0 then
+ begin
+ e_WriteLog('Error loading texture: interleaved TGA', MSG_WARNING);
+ Exit;
+ end;
+
Width := TGAHeader.Width[0] + TGAHeader.Width[1] * 256;
Height := TGAHeader.Height[0] + TGAHeader.Height[1] * 256;
BPP := TGAHeader.BPP;
for i := 0 to fHeight-1 do
CopyMemory( PByte(image) + a*i, Base + b*i, a );
+ //if (TGAHeader.ImageInfo and $20) <> 0 then UpsideDown(Image, Width, Height);
+
if ( BPP = 24 ) then
TFmt := GL_RGB
else
TFmt := GL_RGBA;
-
- Texture := CreateTexture( fWidth, fHeight, TFmt, Image );
+
+ CreateTexture(Texture, fWidth, fHeight, TFmt, Image );
FreeMem( Image );
FreeMem( Image2 );
-
+
if Fmt <> nil then Fmt^ := TFmt;
Result := True;
end;
-function LoadTexture( Filename: String; var Texture: GLuint;
+function LoadTexture( Filename: String; var Texture: GLTexture;
var pWidth, pHeight: Word; Fmt: PWord = nil ): Boolean;
var
TGAHeader: TTGAHeader;
TFmt := GL_RGB
else
TFmt := GL_RGBA;
-
- Texture := CreateTexture( Width, Height, TFmt, Image );
+
+ CreateTexture(Texture, Width, Height, TFmt, Image );
FreeMem( Image );
-
+
if Fmt <> nil then Fmt^ := TFmt;
pWidth := Width;
Result := True;
end;
-function LoadTextureEx( Filename: String; var Texture: GLuint;
+function LoadTextureEx( Filename: String; var Texture: GLTexture;
fX, fY, fWidth, fHeight: Word; Fmt: PWord = nil ): Boolean;
var
TGAHeader: TTGAHeader;
BPP: Byte;
Base: PByte;
TFmt: Word;
-
+
begin
Result := False;
else
TFmt := GL_RGBA;
- Texture := CreateTexture( fWidth, fHeight, TFmt, Image );
+ CreateTexture(Texture, fWidth, fHeight, TFmt, Image );
FreeMem( Image );
FreeMem( Image2 );
end;
end.
-