This commit is contained in:
1 parent
3ac8f48445
commit
da66a6c9d7
4 files changed
+613
-3
No files matched your search
@@ -0,0 +1,215 @@
|
||||
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.
|
||||
Reference in new issue
Block a user