Files
kam-mobile/code/KM_Render_Mobile.pas
T
admin_d da66a6c9d7
Sync changed files to Google Drive / sync (push) Successful in 39s
Complete BigTask
2026-10-04 17:46:01 +05:00

216 lines
7.5 KiB
ObjectPascal

unit KM_Render_Mobile;
interface
uses
KM_RenderTypes;
procedure KMRenderMobileInvalidateCurrentContext;
procedure KMRenderMobileInitializeCurrentContext;
function KMRenderMobileTextureBackendReady: Boolean;
function KMRenderMobileMaxTextureSize: Cardinal;
procedure KMRenderMobileBindTexture(aTexId: Cardinal);
function KMRenderMobileCreateTexture(aMinFilter, aMagFilter: TKMFilterType): Cardinal;
procedure KMRenderMobileDeleteTexture(aTexId: Cardinal);
procedure KMRenderMobileUpdateTexture(aTexture: Cardinal; aWidth, aHeight: Word; aMode: TKMTexFormat; const aData: Pointer);
procedure KMRenderMobileInvalidateTextureBindingCache;
implementation
uses
SysUtils, CastleGLUtils, CastleGLES;
var
gTextureBackendReady: Boolean;
gTextureBindingKnown: Boolean;
gCachedTextureId: Cardinal;
procedure RequireTextureBackendReady;
begin
if not gTextureBackendReady then
raise Exception.Create('Texture backend is not ready');
end;
procedure KMRenderMobileInvalidateCurrentContext;
begin
gTextureBackendReady := False;
KMRenderMobileInvalidateTextureBindingCache;
end;
procedure KMRenderMobileInitializeCurrentContext;
begin
gTextureBackendReady := False;
try
KMRenderMobileInvalidateTextureBindingCache;
if (GLFeatures = nil) or (GLFeatures.MaxTextureSize = 0) then
raise Exception.Create('Texture backend initialization failed');
if not (Assigned(glGenTextures)
and Assigned(glBindTexture)
and Assigned(glDeleteTextures)
and Assigned(glTexParameteri)
and Assigned(glTexImage2D)
and Assigned(glGetIntegerv)
and Assigned(glPixelStorei)) then
raise Exception.Create('Texture backend initialization failed');
gTextureBackendReady := True;
except
gTextureBackendReady := False;
raise;
end;
end;
procedure KMRenderMobileBindTexture(aTexId: Cardinal);
begin
RequireTextureBackendReady;
if gTextureBindingKnown and (gCachedTextureId = aTexId) then Exit;
CastleGLES.glBindTexture(CastleGLES.GL_TEXTURE_2D, CastleGLES.GLuint(aTexId));
gCachedTextureId := aTexId;
gTextureBindingKnown := True;
end;
function IsPowerOfTwo(aValue: Cardinal): Boolean;
begin
Result := (aValue <> 0) and ((aValue and (aValue - 1)) = 0);
end;
procedure KMRenderMobileUpdateTexture(aTexture: Cardinal; aWidth, aHeight: Word; aMode: TKMTexFormat; const aData: Pointer);
var
alphaData: array of Byte;
pixelCount, I: Cardinal;
unpackAlignment: CastleGLES.GLint;
restoreUnpackAlignment: Boolean;
begin
RequireTextureBackendReady;
if (aTexture = 0) or (aWidth = 0) or (aHeight = 0)
or not IsPowerOfTwo(aWidth) or not IsPowerOfTwo(aHeight)
or (aData = nil) then
raise Exception.Create('Invalid texture upload parameters');
if aMode = tfAlpha8 then
begin
pixelCount := Cardinal(aWidth) * Cardinal(aHeight);
SetLength(alphaData, pixelCount);
for I := 0 to pixelCount - 1 do
alphaData[I] := Byte((PCardinal(aData)[I] shr 24) and $FF);
end;
CastleGLES.glGetIntegerv(CastleGLES.GL_UNPACK_ALIGNMENT, @unpackAlignment);
restoreUnpackAlignment := unpackAlignment <> 1;
if restoreUnpackAlignment then
CastleGLES.glPixelStorei(CastleGLES.GL_UNPACK_ALIGNMENT, 1);
try
KMRenderMobileBindTexture(aTexture);
try
case aMode of
tfRGB5A1:
begin
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_SWIZZLE_R, CastleGLES.GL_RED);
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_SWIZZLE_G, CastleGLES.GL_GREEN);
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_SWIZZLE_B, CastleGLES.GL_BLUE);
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_SWIZZLE_A, CastleGLES.GL_ALPHA);
CastleGLES.glTexImage2D(CastleGLES.GL_TEXTURE_2D, 0, CastleGLES.GL_RGB5_A1, aWidth, aHeight, 0, CastleGLES.GL_RGBA, CastleGLES.GL_UNSIGNED_BYTE, aData);
end;
tfRGBA8:
begin
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_SWIZZLE_R, CastleGLES.GL_RED);
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_SWIZZLE_G, CastleGLES.GL_GREEN);
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_SWIZZLE_B, CastleGLES.GL_BLUE);
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_SWIZZLE_A, CastleGLES.GL_ALPHA);
CastleGLES.glTexImage2D(CastleGLES.GL_TEXTURE_2D, 0, CastleGLES.GL_RGBA8, aWidth, aHeight, 0, CastleGLES.GL_RGBA, CastleGLES.GL_UNSIGNED_BYTE, aData);
end;
tfAlpha8:
begin
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_SWIZZLE_R, CastleGLES.GL_ONE);
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_SWIZZLE_G, CastleGLES.GL_ONE);
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_SWIZZLE_B, CastleGLES.GL_ONE);
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_SWIZZLE_A, CastleGLES.GL_RED);
CastleGLES.glTexImage2D(CastleGLES.GL_TEXTURE_2D, 0, CastleGLES.GL_R8, aWidth, aHeight, 0, CastleGLES.GL_RED, CastleGLES.GL_UNSIGNED_BYTE, @alphaData[0]);
end;
end;
finally
KMRenderMobileBindTexture(0);
end;
finally
if restoreUnpackAlignment then
CastleGLES.glPixelStorei(CastleGLES.GL_UNPACK_ALIGNMENT, unpackAlignment);
end;
end;
function TextureFilter(aFilter: TKMFilterType): CastleGLES.GLint;
begin
case aFilter of
ftNearest: Result := CastleGLES.GL_NEAREST;
ftLinear: Result := CastleGLES.GL_LINEAR;
end;
end;
function KMRenderMobileCreateTexture(aMinFilter, aMagFilter: TKMFilterType): Cardinal;
var
texture: CastleGLES.GLuint;
begin
RequireTextureBackendReady;
texture := 0;
CastleGLES.glGenTextures(1, @texture);
if texture = 0 then
raise Exception.Create('Texture generation failed');
try
KMRenderMobileBindTexture(Cardinal(texture));
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_MIN_FILTER, TextureFilter(aMinFilter));
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_MAG_FILTER, TextureFilter(aMagFilter));
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_WRAP_S, CastleGLES.GL_CLAMP_TO_EDGE);
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_WRAP_T, CastleGLES.GL_CLAMP_TO_EDGE);
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_MAX_LEVEL, 0);
Result := Cardinal(texture);
except
KMRenderMobileDeleteTexture(Cardinal(texture));
raise;
end;
end;
procedure KMRenderMobileDeleteTexture(aTexId: Cardinal);
var
texture: CastleGLES.GLuint;
begin
RequireTextureBackendReady;
if aTexId = 0 then Exit;
texture := CastleGLES.GLuint(aTexId);
CastleGLES.glDeleteTextures(1, @texture);
if gTextureBindingKnown and (gCachedTextureId = aTexId) then
gCachedTextureId := 0;
end;
procedure KMRenderMobileInvalidateTextureBindingCache;
begin
gTextureBindingKnown := False;
end;
function KMRenderMobileTextureBackendReady: Boolean;
begin
Result := gTextureBackendReady;
end;
function KMRenderMobileMaxTextureSize: Cardinal;
begin
RequireTextureBackendReady;
if GLFeatures = nil then
raise Exception.Create('Texture backend feature state is unavailable');
Result := GLFeatures.MaxTextureSize;
if Result = 0 then
raise Exception.Create('Texture backend maximum texture size is unavailable');
end;
end.