From da66a6c9d78f9bdfc952171b228e2bc15e3b5d63 Mon Sep 17 00:00:00 2001 From: admin_d Date: Sun, 4 Oct 2026 17:46:01 +0500 Subject: [PATCH] Complete BigTask --- code/KM_Render_Mobile.pas | 215 ++++++++++ config/extra-paths.json | 3 +- .../kam_remake/src/render/KM_Render.pas | 395 ++++++++++++++++++ .../kam_remake/src/res/KM_ResSprites.pas | 3 +- 4 files changed, 613 insertions(+), 3 deletions(-) create mode 100644 code/KM_Render_Mobile.pas create mode 100644 port-source/kam_remake/src/render/KM_Render.pas diff --git a/code/KM_Render_Mobile.pas b/code/KM_Render_Mobile.pas new file mode 100644 index 0000000..bc5cbc6 --- /dev/null +++ b/code/KM_Render_Mobile.pas @@ -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. diff --git a/config/extra-paths.json b/config/extra-paths.json index fe92c8a..5983b47 100755 --- a/config/extra-paths.json +++ b/config/extra-paths.json @@ -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" diff --git a/port-source/kam_remake/src/render/KM_Render.pas b/port-source/kam_remake/src/render/KM_Render.pas new file mode 100644 index 0000000..27c1be8 --- /dev/null +++ b/port-source/kam_remake/src/render/KM_Render.pas @@ -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. diff --git a/port-source/kam_remake/src/res/KM_ResSprites.pas b/port-source/kam_remake/src/res/KM_ResSprites.pas index 9863c1a..28fcaed 100644 --- a/port-source/kam_remake/src/res/KM_ResSprites.pas +++ b/port-source/kam_remake/src/res/KM_ResSprites.pas @@ -269,8 +269,7 @@ function GetMaxAtlasSize: Integer; begin Result := MAX_GAME_ATLAS_SIZE; {$IFNDEF NO_OGL} - if gRender <> nil then - Result := Min(Result, TKMRender.MaxTextureSize); + Result := Min(Result, TKMRender.MaxTextureSize); {$ENDIF} end;