From c6a3fcdca0e2ff000eb7c3c5fa7b6ddea54cffaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= <5415177+ZehMatt@users.noreply.github.com> Date: Sat, 5 Apr 2025 16:16:48 +0300 Subject: [PATCH] Implement support for viewport shifting --- .../drawing/engines/opengl/OpenGLAPI.h | 5 ++ .../drawing/engines/opengl/OpenGLAPIProc.h | 1 + .../engines/opengl/OpenGLDrawingEngine.cpp | 53 ++++++++++++++++++- .../engines/opengl/OpenGLFramebuffer.cpp | 23 ++++++++ .../engines/opengl/OpenGLFramebuffer.h | 1 + .../drawing/engines/opengl/SwapFramebuffer.h | 4 ++ 6 files changed, 85 insertions(+), 2 deletions(-) diff --git a/src/openrct2-ui/drawing/engines/opengl/OpenGLAPI.h b/src/openrct2-ui/drawing/engines/opengl/OpenGLAPI.h index 7b3753d453..c6b9554393 100644 --- a/src/openrct2-ui/drawing/engines/opengl/OpenGLAPI.h +++ b/src/openrct2-ui/drawing/engines/opengl/OpenGLAPI.h @@ -38,6 +38,7 @@ #define glTexImage3D __static__glTexImage3D #define glGetIntegerv __static__glGetIntegerv #define glGetTexImage __static__glGetTexImage + #define glTexSubImage2D __static__glTexSubImage2D #endif @@ -74,6 +75,7 @@ #undef glTexImage3D #undef glGetIntegerv #undef glGetTexImage + #undef glTexSubImage2D // 1.1 function signatures using PFNGLBEGINPROC = void(APIENTRYP)(GLenum mode); @@ -106,6 +108,9 @@ using PFNGLTEXIMAGE3DPROC = void(APIENTRYP)( GLenum type, const GLvoid* data); using PFNGLGETINTERGERVPROC = void(APIENTRYP)(GLenum pname, GLint* data); using PFNGLGETTEXIMAGEPROC = void(APIENTRYP)(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* img); +using PFNGLTEXSUBIMAGE2D = void(APIENTRYP)( + GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, + const GLvoid* pixels); #define OPENGL_PROC(TYPE, PROC) extern TYPE PROC; #include "OpenGLAPIProc.h" diff --git a/src/openrct2-ui/drawing/engines/opengl/OpenGLAPIProc.h b/src/openrct2-ui/drawing/engines/opengl/OpenGLAPIProc.h index 80a228904e..8cd6bd925d 100644 --- a/src/openrct2-ui/drawing/engines/opengl/OpenGLAPIProc.h +++ b/src/openrct2-ui/drawing/engines/opengl/OpenGLAPIProc.h @@ -102,3 +102,4 @@ extern "C" void glDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, G extern "C" void glVertexAttribDivisor(GLuint index, GLuint divisor); #endif OPENGL_PROC(PFNGLBLENDFUNCSEPARATEPROC, glBlendFuncSeparate) +OPENGL_PROC(PFNGLTEXSUBIMAGE2D, glTexSubImage2D) diff --git a/src/openrct2-ui/drawing/engines/opengl/OpenGLDrawingEngine.cpp b/src/openrct2-ui/drawing/engines/opengl/OpenGLDrawingEngine.cpp index 2db7b21d8f..6ab230c533 100644 --- a/src/openrct2-ui/drawing/engines/opengl/OpenGLDrawingEngine.cpp +++ b/src/openrct2-ui/drawing/engines/opengl/OpenGLDrawingEngine.cpp @@ -94,11 +94,17 @@ public: { return _textureCache.get(); } + const OpenGLFramebuffer& GetFinalFramebuffer() const { return _swapFramebuffer->GetFinalFramebuffer(); } + OpenGLFramebuffer& GetFinalFramebuffer() + { + return _swapFramebuffer->GetFinalFramebuffer(); + } + void Initialise(); void Resize(int32_t width, int32_t height); void ResetPalette(); @@ -371,7 +377,50 @@ public: void CopyRect(int32_t x, int32_t y, int32_t width, int32_t height, int32_t dx, int32_t dy) override { - // Not applicable for this engine + if (dx == 0 && dy == 0) + return; + + _drawingContext->FlushCommandBuffers(); + + OpenGLFramebuffer& framebuffer = _drawingContext->GetFinalFramebuffer(); + framebuffer.Bind(); + framebuffer.GetPixels(_bitsDPI); + + // Originally 0x00683359 + // Adjust for move off screen + // NOTE: when zooming, there can be x, y, dx, dy combinations that go off the + // screen; hence the checks. This code should ultimately not be called when + // zooming because this function is specific to updating the screen on move + int32_t lmargin = std::min(x - dx, 0); + int32_t rmargin = std::min(static_cast(_width) - (x - dx + width), 0); + int32_t tmargin = std::min(y - dy, 0); + int32_t bmargin = std::min(static_cast(_height) - (y - dy + height), 0); + x -= lmargin; + y -= tmargin; + width += lmargin + rmargin; + height += tmargin + bmargin; + + int32_t stride = _bitsDPI.LineStride(); + uint8_t* to = _bitsDPI.bits + y * stride + x; + uint8_t* from = _bitsDPI.bits + (y - dy) * stride + x - dx; + + if (dy > 0) + { + // If positive dy, reverse directions + to += (height - 1) * stride; + from += (height - 1) * stride; + stride = -stride; + } + + // Move bytes + for (int32_t i = 0; i < height; i++) + { + memmove(to, from, width); + to += stride; + from += stride; + } + + framebuffer.SetPixels(_bitsDPI); } IDrawingContext* GetDrawingContext() override @@ -386,7 +435,7 @@ public: DrawingEngineFlags GetFlags() override { - return {}; + return DrawingEngineFlag::dirtyOptimisations; } void InvalidateImage(uint32_t image) override diff --git a/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.cpp b/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.cpp index b9f86f0654..08c8701790 100644 --- a/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.cpp +++ b/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.cpp @@ -150,4 +150,27 @@ GLuint OpenGLFramebuffer::CreateDepthTexture(int32_t width, int32_t height) return depth; } + void OpenGLFramebuffer::SetPixels(const DrawPixelInfo& dpi) +{ + assert(dpi.width == _width && dpi.height == _height); + + auto pixels = std::make_unique(_width * _height); + // Flip pixels vertically on copy + uint8_t* dst = pixels.get() + ((_height - 1) * _width); + uint8_t* src = dpi.bits; + for (int32_t y = 0; y < _height; y++) + { + std::copy_n(src, _width, dst); + src += dpi.width + dpi.pitch; + dst -= _width; + } + + glBindTexture(GL_TEXTURE_2D, _texture); + CheckGLError(); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + CheckGLError(); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, _width, _height, GL_RED_INTEGER, GL_UNSIGNED_BYTE, pixels.get()); + CheckGLError(); +} + #endif /* DISABLE_OPENGL */ diff --git a/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.h b/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.h index d5d6813a71..67cc132614 100644 --- a/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.h +++ b/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.h @@ -59,6 +59,7 @@ namespace OpenRCT2::Ui void SwapColourBuffer(OpenGLFramebuffer& other); GLuint SwapDepthTexture(GLuint depth); void Copy(OpenGLFramebuffer& src, GLenum filter); + void SetPixels(const DrawPixelInfo& dpi); static GLuint CreateDepthTexture(int32_t width, int32_t height); }; diff --git a/src/openrct2-ui/drawing/engines/opengl/SwapFramebuffer.h b/src/openrct2-ui/drawing/engines/opengl/SwapFramebuffer.h index 3bc3ae2248..2eae356ff4 100644 --- a/src/openrct2-ui/drawing/engines/opengl/SwapFramebuffer.h +++ b/src/openrct2-ui/drawing/engines/opengl/SwapFramebuffer.h @@ -39,6 +39,10 @@ namespace OpenRCT2::Ui { return _opaqueFramebuffer; } + OpenGLFramebuffer& GetFinalFramebuffer() + { + return _opaqueFramebuffer; + } GLuint GetBackDepthTexture() const { return _backDepth;