This commit is contained in:
1 parent
3ac8f48445
commit
da66a6c9d7
4 files changed
+612
-2
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.
|
||||
@@ -17,7 +17,8 @@
|
||||
"src/res/KM_ResTileset.pas",
|
||||
"src/res/KM_ResPalettes.pas",
|
||||
"src/res/KM_ResMapElements.pas",
|
||||
"src/res/KM_ResLocales.pas"
|
||||
"src/res/KM_ResLocales.pas",
|
||||
"src/render/KM_Render.pas"
|
||||
],
|
||||
"source_paths": [
|
||||
"code/resource"
|
||||
|
||||
@@ -0,0 +1,395 @@
|
||||
unit KM_Render;
|
||||
{$I KaM_Remake.inc}
|
||||
interface
|
||||
uses
|
||||
{$IFDEF WDC} Windows, {$ENDIF}
|
||||
{$IFDEF Unix} LCLIntf, LCLType, OpenGLContext, {$ENDIF}
|
||||
dglOpenGL,
|
||||
KM_RenderControl, KM_RenderQuery, KM_RenderTypes, KM_CommonTypes;
|
||||
|
||||
|
||||
const
|
||||
TEX_FORMAT_SIZE: array [TKMTexFormat] of Byte = (2, 4, 1);
|
||||
|
||||
type
|
||||
TKMRenderMode = (rm2D, rm3D);
|
||||
|
||||
//General OpenGL handling
|
||||
TKMRender = class
|
||||
private class var
|
||||
fMaxViewportDim: Cardinal; // Max Viewport Dimensions, which could be used for FBO render
|
||||
private
|
||||
// Flag, True when FBO is inited. We don't need to init FBO for every run, since its only used in SaveMapToImageFile feature
|
||||
fFBOInited: Boolean;
|
||||
// Off-screen buffer, example from https://stackoverflow.com/questions/12157646/how-to-render-offscreen-on-opengl
|
||||
fFBO: Cardinal;
|
||||
fRenderBuf: Cardinal;
|
||||
|
||||
fRenderControl: TKMRenderControl;
|
||||
fOpenGL_Vendor, fOpenGL_Renderer, fOpenGL_Version: UnicodeString;
|
||||
fScreenX, fScreenY: Word;
|
||||
fBlind: Boolean;
|
||||
fQuery: TKMRenderQuery;
|
||||
|
||||
procedure InitFBO;
|
||||
procedure SaveBufferToFile(aUseFBOBuffer: Boolean; var aWidth, aHeight: Integer; var aPixelData: TKMCardinalArray);
|
||||
function GetMaxFBOSize: Cardinal;
|
||||
public
|
||||
constructor Create(aRenderControl: TKMRenderControl; aScreenX, aScreenY: Integer; aVSync: Boolean);
|
||||
destructor Destroy; override;
|
||||
|
||||
procedure SetRenderMode(aRenderMode: TKMRenderMode); //Switch between 2D and 3D perspectives
|
||||
|
||||
class procedure GraphicsContextChanged(aAvailable: Boolean); static;
|
||||
class function TextureBackendReady: Boolean; static;
|
||||
class function GetMaxTexSize: Cardinal; static;
|
||||
class function GetMaxViewportDim: Cardinal; static;
|
||||
class function GenerateTextureCommon(aMinFilter, aMagFilter: TKMFilterType): Cardinal;
|
||||
class function GenTexture(DestX, DestY: Word; const Data: Pointer; Mode: TKMTexFormat; aMinFilter, aMagFilter: TKMFilterType): Cardinal;
|
||||
class procedure DeleteTexture(aTex: Cardinal);
|
||||
class procedure UpdateTexture(aTexture: Cardinal; DestX, DestY: Word; Mode: TKMTexFormat; const Data: Pointer);
|
||||
class procedure BindTexture(aTexId: Cardinal);
|
||||
class procedure InvalidateTextureBindingCache; static;
|
||||
|
||||
class property MaxTextureSize: Cardinal read GetMaxTexSize;
|
||||
class property MaxViewportDim: Cardinal read GetMaxViewportDim;
|
||||
|
||||
property MaxFBOSize: Cardinal read GetMaxFBOSize;
|
||||
property RendererVersion: UnicodeString read fOpenGL_Version;
|
||||
function IsOldGLVersion: Boolean;
|
||||
procedure Resize(aWidth, aHeight: Integer);
|
||||
|
||||
procedure ReadRenderedToScreenPixels(var aWidth, aHeight: Integer; var aPixelData: TKMCardinalArray);
|
||||
procedure ReadRenderedToFBOPixels(var aWidth, aHeight: Integer; var aPixelData: TKMCardinalArray);
|
||||
|
||||
property ScreenX: Word read fScreenX;
|
||||
property ScreenY: Word read fScreenY;
|
||||
property Blind: Boolean read fBlind;
|
||||
|
||||
property Query: TKMRenderQuery read fQuery;
|
||||
|
||||
procedure BeginFrame;
|
||||
procedure RenderBrightness(aValue: Byte);
|
||||
procedure EndFrame;
|
||||
end;
|
||||
|
||||
var
|
||||
gRender: TKMRender;
|
||||
|
||||
|
||||
implementation
|
||||
uses
|
||||
SysUtils, Math,
|
||||
KromOGLUtils, KromUtils,
|
||||
KM_Log, KM_Defaults, KM_IoPNG, KM_CommonClasses,
|
||||
KM_Render_Mobile;
|
||||
|
||||
const
|
||||
// We want to use off-screen FBO buffer to render full map to the file,
|
||||
// we are restricted with max file we are able to write via TBitmap or TJpegImage or TPNGImage atm
|
||||
// could check https://github.com/graphics32 package to solve this issue with saving ultra large images
|
||||
MAX_FBO_BUFFER_SIZE = CELL_SIZE_PX * (MAX_MAP_SIZE - 1); // (10200 = CELL_SIZE=40px)*255
|
||||
|
||||
{ TKMRender }
|
||||
constructor TKMRender.Create(aRenderControl: TKMRenderControl; aScreenX, aScreenY: Integer; aVSync: Boolean);
|
||||
begin
|
||||
inherited Create;
|
||||
|
||||
gLog.AddTime('Init Render started');
|
||||
|
||||
fFBOInited := False;
|
||||
fBlind := aRenderControl = nil;
|
||||
fRenderControl := aRenderControl;
|
||||
|
||||
if not fBlind then
|
||||
begin
|
||||
fQuery := TKMRenderQuery.Create;
|
||||
|
||||
fRenderControl.CreateRenderContext;
|
||||
|
||||
fMaxViewportDim := GetMaxViewportDim;
|
||||
gLog.AddTime('GL_MAX_VIEWPORT_DIM = ' + IntToStr(fMaxViewportDim));
|
||||
|
||||
glClearColor(0, 0, 0, 0); //Background
|
||||
glClearStencil(0);
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
glShadeModel(GL_SMOOTH); //Enables Smooth Color Shading
|
||||
glPolygonMode(GL_FRONT, GL_FILL);
|
||||
glEnable(GL_NORMALIZE);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //Set alpha mode
|
||||
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
|
||||
glEnable(GL_COLOR_MATERIAL); //Enable Materials
|
||||
glEnable(GL_TEXTURE_2D); // Enable Texture Mapping
|
||||
glDisable(GL_LIGHTING); //We don't need it
|
||||
//glEnable(GL_CULL_FACE);
|
||||
//glCullFace(GL_FRONT);
|
||||
|
||||
fOpenGL_Vendor := UnicodeString(glGetString(GL_VENDOR)); gLog.AddNoTime('OpenGL Vendor: ' + fOpenGL_Vendor);
|
||||
fOpenGL_Renderer := UnicodeString(glGetString(GL_RENDERER)); gLog.AddNoTime('OpenGL Renderer: ' + fOpenGL_Renderer);
|
||||
fOpenGL_Version := UnicodeString(glGetString(GL_VERSION)); gLog.AddNoTime('OpenGL Version: ' + fOpenGL_Version);
|
||||
|
||||
SetupVSync(aVSync);
|
||||
|
||||
Resize(aScreenX, aScreenY);
|
||||
end;
|
||||
gLog.AddTime('Init Render Done');
|
||||
end;
|
||||
|
||||
|
||||
destructor TKMRender.Destroy;
|
||||
begin
|
||||
if not fBlind then
|
||||
begin
|
||||
fRenderControl.DestroyRenderContext;
|
||||
fQuery.Free;
|
||||
|
||||
if fFBOInited then
|
||||
begin
|
||||
glDeleteFramebuffers(1,@fFBO);
|
||||
glDeleteRenderbuffers(1,@fRenderBuf);
|
||||
end;
|
||||
end;
|
||||
|
||||
inherited;
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMRender.InitFBO;
|
||||
begin
|
||||
if fFBOInited then Exit;
|
||||
|
||||
fFBOInited := True;
|
||||
|
||||
glGenFramebuffers(1, @fFBO);
|
||||
glGenRenderbuffers(1, @fRenderBuf);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, fRenderBuf);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, GetMaxFBOSize, GetMaxFBOSize);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fFBO);
|
||||
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, fRenderBuf);
|
||||
end;
|
||||
|
||||
|
||||
//We have to use this method EVERY time we want to bind texture. Otherwise collisions could happen
|
||||
//
|
||||
//Do not bind same texture again, it can drastically change render performance
|
||||
//F.e. on an average Map (Cube 256x256) when full map is shown in viewport
|
||||
//there are only ~10k new texture binds, when all other ~30k binds can be skipped
|
||||
class procedure TKMRender.BindTexture(aTexId: Cardinal);
|
||||
begin
|
||||
KMRenderMobileBindTexture(aTexId);
|
||||
end;
|
||||
|
||||
|
||||
class procedure TKMRender.InvalidateTextureBindingCache;
|
||||
begin
|
||||
KMRenderMobileInvalidateTextureBindingCache;
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMRender.Resize(aWidth, aHeight: Integer);
|
||||
begin
|
||||
if fBlind then Exit;
|
||||
|
||||
fScreenX := max(aWidth, 1);
|
||||
fScreenY := max(aHeight, 1);
|
||||
glViewport(0, 0, fScreenX, fScreenY);
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMRender.SetRenderMode(aRenderMode: TKMRenderMode);
|
||||
begin
|
||||
if fBlind then Exit;
|
||||
|
||||
glMatrixMode(GL_PROJECTION); //Change Matrix Mode to Projection
|
||||
glLoadIdentity; //Reset View
|
||||
|
||||
//In 2D mode we use Z-test to clip terrain shadows behind mountains
|
||||
//1 unit for each tile strip. 512 means we can handle up to 512x512 maps
|
||||
case aRenderMode of
|
||||
rm2D: glOrtho(0, fScreenX, fScreenY, 0, -100, 100);
|
||||
rm3D: gluPerspective(80, -fScreenX/fScreenY, 0.1, 5000);
|
||||
end;
|
||||
glMatrixMode(GL_MODELVIEW); //Return to the modelview matrix
|
||||
glLoadIdentity; //Reset View
|
||||
end;
|
||||
|
||||
|
||||
class function TKMRender.GenerateTextureCommon(aMinFilter, aMagFilter: TKMFilterType): Cardinal;
|
||||
begin
|
||||
Result := KMRenderMobileCreateTexture(aMinFilter, aMagFilter);
|
||||
end;
|
||||
|
||||
|
||||
//Generate texture out of TCardinalArray
|
||||
class function TKMRender.GenTexture(DestX, DestY: Word; const Data: Pointer; Mode: TKMTexFormat; aMinFilter, aMagFilter: TKMFilterType): Cardinal;
|
||||
var
|
||||
texture: Cardinal;
|
||||
begin
|
||||
texture := GenerateTextureCommon(aMinFilter, aMagFilter);
|
||||
try
|
||||
UpdateTexture(texture, DestX, DestY, Mode, Data);
|
||||
Result := texture;
|
||||
except
|
||||
DeleteTexture(texture);
|
||||
raise;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
class procedure TKMRender.DeleteTexture(aTex: Cardinal);
|
||||
begin
|
||||
KMRenderMobileDeleteTexture(aTex);
|
||||
end;
|
||||
|
||||
|
||||
function TKMRender.GetMaxFBOSize: Cardinal;
|
||||
begin
|
||||
Result := Min(fMaxViewportDim, MAX_FBO_BUFFER_SIZE);
|
||||
end;
|
||||
|
||||
|
||||
class procedure TKMRender.GraphicsContextChanged(aAvailable: Boolean);
|
||||
begin
|
||||
if aAvailable then
|
||||
KMRenderMobileInitializeCurrentContext
|
||||
else
|
||||
KMRenderMobileInvalidateCurrentContext;
|
||||
end;
|
||||
|
||||
|
||||
class function TKMRender.TextureBackendReady: Boolean;
|
||||
begin
|
||||
Result := KMRenderMobileTextureBackendReady;
|
||||
end;
|
||||
|
||||
|
||||
class function TKMRender.GetMaxTexSize: Cardinal;
|
||||
begin
|
||||
Result := KMRenderMobileMaxTextureSize;
|
||||
end;
|
||||
|
||||
|
||||
class function TKMRender.GetMaxViewportDim: Cardinal;
|
||||
begin
|
||||
if fMaxViewportDim > 0 then Exit(fMaxViewportDim);
|
||||
|
||||
//Get max supported dimensions for viewport (used in off-screen render, FBO)
|
||||
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, @fMaxViewportDim);
|
||||
Result := fMaxViewportDim;
|
||||
end;
|
||||
|
||||
|
||||
//Update texture with TCardinalArray
|
||||
class procedure TKMRender.UpdateTexture(aTexture: Cardinal; DestX, DestY: Word; Mode: TKMTexFormat; const Data: Pointer);
|
||||
begin
|
||||
KMRenderMobileUpdateTexture(aTexture, DestX, DestY, Mode, Data);
|
||||
end;
|
||||
|
||||
|
||||
//1.4 is considered to be our minimal requirement
|
||||
function TKMRender.IsOldGLVersion: Boolean;
|
||||
begin
|
||||
Result := not fBlind and not GL_VERSION_1_4;
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMRender.ReadRenderedToScreenPixels(var aWidth, aHeight: Integer; var aPixelData: TKMCardinalArray);
|
||||
begin
|
||||
SaveBufferToFile(False, aWidth, aHeight, aPixelData);
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMRender.ReadRenderedToFBOPixels(var aWidth, aHeight: Integer; var aPixelData: TKMCardinalArray);
|
||||
begin
|
||||
SaveBufferToFile(True, aWidth, aHeight, aPixelData);
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMRender.SaveBufferToFile(aUseFBOBuffer: Boolean; var aWidth, aHeight: Integer; var aPixelData: TKMCardinalArray);
|
||||
{$IFDEF WDC}
|
||||
var
|
||||
I, K: Integer;
|
||||
{$ENDIF}
|
||||
begin
|
||||
{$IFDEF WDC}
|
||||
aWidth := ScreenX;
|
||||
aHeight := ScreenY;
|
||||
|
||||
if aUseFBOBuffer then
|
||||
begin
|
||||
// Read from offscreen buffer
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
||||
// Bind to FBO framebuffer
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fFBO);
|
||||
end
|
||||
else
|
||||
// Read from onscreen buffer
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
|
||||
SetLength(aPixelData, aWidth * aHeight + 1);
|
||||
glReadPixels(0, 0, aWidth, aHeight, GL_BGRA, GL_UNSIGNED_BYTE, @aPixelData[0]);
|
||||
|
||||
if aUseFBOBuffer then
|
||||
// Return to onscreen rendering:
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
|
||||
//Mirror verticaly
|
||||
for i := 0 to (aHeight div 2) - 1 do
|
||||
for K := 0 to aWidth - 1 do
|
||||
SwapInt(aPixelData[i * aWidth + K], aPixelData[((aHeight - 1) - i) * aWidth + K]);
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMRender.BeginFrame;
|
||||
begin
|
||||
if fBlind then Exit;
|
||||
|
||||
if SAVE_MAP_TO_FBO_RENDER then
|
||||
begin
|
||||
if not fFBOInited then
|
||||
// Init once
|
||||
InitFBO // glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fFBO) is called while initialization
|
||||
else
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fFBO);
|
||||
end;
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT or GL_STENCIL_BUFFER_BIT);
|
||||
SetRenderMode(rm2D);
|
||||
|
||||
//RC.Activate for OSX
|
||||
end;
|
||||
|
||||
|
||||
//Render highlight overlay to make whole picture look brighter (more saturated)
|
||||
procedure TKMRender.RenderBrightness(aValue: Byte);
|
||||
begin
|
||||
if fBlind then Exit;
|
||||
|
||||
//There will be no change to image anyway
|
||||
if aValue = 0 then Exit;
|
||||
|
||||
BindTexture(0); // We have to reset texture to default (0), because it could be bind to any other texture (atlas)
|
||||
|
||||
glLoadIdentity;
|
||||
glBlendFunc(GL_DST_COLOR, GL_ONE);
|
||||
glColor4f(aValue/20, aValue/20, aValue/20, aValue/20);
|
||||
glBegin(GL_QUADS);
|
||||
glkRect(0, 0, ScreenX, ScreenY);
|
||||
glEnd;
|
||||
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
end;
|
||||
|
||||
|
||||
procedure TKMRender.EndFrame;
|
||||
begin
|
||||
if fBlind then Exit;
|
||||
|
||||
glFinish;
|
||||
fRenderControl.SwapBuffers;
|
||||
end;
|
||||
|
||||
|
||||
end.
|
||||
@@ -269,7 +269,6 @@ function GetMaxAtlasSize: Integer;
|
||||
begin
|
||||
Result := MAX_GAME_ATLAS_SIZE;
|
||||
{$IFNDEF NO_OGL}
|
||||
if gRender <> nil then
|
||||
Result := Min(Result, TKMRender.MaxTextureSize);
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
Reference in new issue
Block a user