diff --git a/data/shaders/applytransparency.frag b/data/shaders/applytransparency.frag index 630a89d1f7..a3ba23910b 100644 --- a/data/shaders/applytransparency.frag +++ b/data/shaders/applytransparency.frag @@ -17,7 +17,7 @@ void main() uint transparent = texture(uTransparentTex, fTextureCoordinate).r; float transparentDepth = texture(uTransparentDepth, fTextureCoordinate).r; - if (transparentDepth > opaqueDepth) + if (opaqueDepth <= transparentDepth) { transparent = 0u; } diff --git a/data/shaders/drawline.vert b/data/shaders/drawline.vert index bd71788f74..2faf19dc2a 100644 --- a/data/shaders/drawline.vert +++ b/data/shaders/drawline.vert @@ -18,9 +18,8 @@ void main() { vec2 pos = clamp(vVertMat * vBounds, vClip.xy, vClip.zw); - // Transform screen coordinates to viewport - pos.x = (pos.x * (2.0 / uScreenSize.x)) - 1.0; - pos.y = (pos.y * (2.0 / uScreenSize.y)) - 1.0; + // Transform screen coordinates to viewport coordinates + pos = (pos * (2.0 / uScreenSize)) - 1.0; pos.y *= -1; float depth = 1.0 - (vDepth + 1) * DEPTH_INCREMENT; diff --git a/data/shaders/drawrect.frag b/data/shaders/drawrect.frag index cf4a8265a8..495c5326e3 100644 --- a/data/shaders/drawrect.frag +++ b/data/shaders/drawrect.frag @@ -8,6 +8,9 @@ const int FLAG_CROSS_HATCH = (1 << 4); uniform usampler2DArray uTexture; uniform usampler2DRect uPaletteTex; +uniform sampler2D uPeelingTex; +uniform bool uPeeling; + flat in int fFlags; flat in uint fColour; in vec3 fTexColour; @@ -15,11 +18,21 @@ in vec3 fTexMask; flat in vec3 fPalettes; in vec2 fPosition; +in vec3 fPeelPos; out uint oColour; void main() { + if (uPeeling) + { + float peel = texture(uPeelingTex, fPeelPos.xy).r; + if (peel == 0.0 || fPeelPos.z >= peel) + { + discard; + } + } + uint texel; if ((fFlags & FLAG_NO_TEXTURE) == 0) { diff --git a/data/shaders/drawrect.vert b/data/shaders/drawrect.vert index 25c3daf7cd..b752f364dc 100644 --- a/data/shaders/drawrect.vert +++ b/data/shaders/drawrect.vert @@ -20,6 +20,7 @@ in mat4x2 vVertMat; in vec2 vVertVec; out vec2 fPosition; +out vec3 fPeelPos; flat out int fFlags; flat out uint fColour; out vec3 fTexColour; @@ -36,15 +37,17 @@ void main() fPosition = pos; - // Transform screen coordinates to viewport - pos.x = (pos.x * (2.0 / uScreenSize.x)) - 1.0; - pos.y = (pos.y * (2.0 / uScreenSize.y)) - 1.0; - pos.y *= -1; + // Transform screen coordinates to texture coordinates float depth = 1.0 - (vDepth + 1) * DEPTH_INCREMENT; + pos = pos / uScreenSize; + pos.y = pos.y * -1.0 + 1.0; + fPeelPos = vec3(pos, depth * 0.5 + 0.5); fFlags = vFlags; fColour = vColour; fPalettes = vec3(vPalettes); + // Transform texture coordinates to viewport coordinates + pos = pos * 2.0 - 1.0; gl_Position = vec4(pos, depth, 1.0); } diff --git a/src/openrct2-ui/drawing/engines/opengl/ApplyTransparencyShader.cpp b/src/openrct2-ui/drawing/engines/opengl/ApplyTransparencyShader.cpp index a945c8ac58..eef4b38eff 100644 --- a/src/openrct2-ui/drawing/engines/opengl/ApplyTransparencyShader.cpp +++ b/src/openrct2-ui/drawing/engines/opengl/ApplyTransparencyShader.cpp @@ -75,7 +75,9 @@ void ApplyTransparencyShader::GetLocations() vTextureCoordinate = GetAttributeLocation("vTextureCoordinate"); } -void ApplyTransparencyShader::SetTextures(GLuint opaqueTex, GLuint opaqueDepth, GLuint transparentTex, GLuint transparentDepth, GLuint paletteTex) +void ApplyTransparencyShader::SetTextures(GLuint opaqueTex, GLuint opaqueDepth, + GLuint transparentTex, GLuint transparentDepth, + GLuint paletteTex) { OpenGLAPI::SetTexture(0, GL_TEXTURE_2D, opaqueTex); OpenGLAPI::SetTexture(1, GL_TEXTURE_2D, opaqueDepth); diff --git a/src/openrct2-ui/drawing/engines/opengl/ApplyTransparencyShader.h b/src/openrct2-ui/drawing/engines/opengl/ApplyTransparencyShader.h index c98f248f6d..7603dbd1c9 100644 --- a/src/openrct2-ui/drawing/engines/opengl/ApplyTransparencyShader.h +++ b/src/openrct2-ui/drawing/engines/opengl/ApplyTransparencyShader.h @@ -38,7 +38,9 @@ public: ApplyTransparencyShader(); ~ApplyTransparencyShader() override; - void SetTextures(GLuint opaqueTex, GLuint opaqueDepth, GLuint transparentTex, GLuint transparentDepth, GLuint paletteTex); + void SetTextures(GLuint opaqueTex, GLuint opaqueDepth, + GLuint transparentTex, GLuint transparentDepth, + GLuint paletteTex); void Draw(); private: diff --git a/src/openrct2-ui/drawing/engines/opengl/DrawCommands.h b/src/openrct2-ui/drawing/engines/opengl/DrawCommands.h index fbbdac29b8..004a70d687 100644 --- a/src/openrct2-ui/drawing/engines/opengl/DrawCommands.h +++ b/src/openrct2-ui/drawing/engines/opengl/DrawCommands.h @@ -50,6 +50,14 @@ public: } return _instances[_numInstances++]; } + T& insert(const T &value) + { + if (_numInstances + 1 > _instances.size()) + { + _instances.resize((_numInstances + 1) << 1); + } + return _instances[_numInstances++] = value; + } size_t size() const { return _numInstances; @@ -62,6 +70,14 @@ public: { return _instances.at(idx); } + typename std::vector::iterator begin() + { + return _instances.begin(); + } + typename std::vector::iterator end() + { + return _instances.begin() + _numInstances; + } }; struct DrawLineCommand diff --git a/src/openrct2-ui/drawing/engines/opengl/DrawRectShader.cpp b/src/openrct2-ui/drawing/engines/opengl/DrawRectShader.cpp index 80d60819c6..226d70eb9f 100644 --- a/src/openrct2-ui/drawing/engines/opengl/DrawRectShader.cpp +++ b/src/openrct2-ui/drawing/engines/opengl/DrawRectShader.cpp @@ -94,6 +94,9 @@ DrawRectShader::DrawRectShader() : OpenGLShaderProgram("drawrect") Use(); glUniform1i(uTexture, 0); glUniform1i(uPaletteTex, 1); + + glUniform1i(uPeelingTex, 2); + glUniform1i(uPeeling, 0); } DrawRectShader::~DrawRectShader() @@ -109,6 +112,9 @@ void DrawRectShader::GetLocations() uTexture = GetUniformLocation("uTexture"); uPaletteTex = GetUniformLocation("uPaletteTex"); + uPeelingTex = GetUniformLocation("uPeelingTex"); + uPeeling = GetUniformLocation("uPeeling"); + vClip = GetAttributeLocation("vClip"); vTexColourAtlas = GetAttributeLocation("vTexColourAtlas"); vTexColourBounds = GetAttributeLocation("vTexColourBounds"); @@ -129,14 +135,31 @@ void DrawRectShader::SetScreenSize(sint32 width, sint32 height) glUniform2i(uScreenSize, width, height); } -void DrawRectShader::DrawInstances(const RectCommandBatch& instances) +void DrawRectShader::EnablePeeling(GLuint peelingTex) +{ + OpenGLAPI::SetTexture(2, GL_TEXTURE_2D, peelingTex); + glUniform1i(uPeeling, 1); +} + +void DrawRectShader::DisablePeeling() +{ + glUniform1i(uPeeling, 0); +} + +void DrawRectShader::SetInstances(const RectCommandBatch &instances) { glBindVertexArray(_vao); glBindBuffer(GL_ARRAY_BUFFER, _vboInstances); glBufferData(GL_ARRAY_BUFFER, sizeof(DrawRectCommand) * instances.size(), instances.data(), GL_STREAM_DRAW); - glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, (GLsizei)instances.size()); + _instanceCount = (GLsizei)instances.size(); +} + +void DrawRectShader::DrawInstances() +{ + glBindVertexArray(_vao); + glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, _instanceCount); } #endif /* DISABLE_OPENGL */ diff --git a/src/openrct2-ui/drawing/engines/opengl/DrawRectShader.h b/src/openrct2-ui/drawing/engines/opengl/DrawRectShader.h index 756852a18e..01cfb9d3d6 100644 --- a/src/openrct2-ui/drawing/engines/opengl/DrawRectShader.h +++ b/src/openrct2-ui/drawing/engines/opengl/DrawRectShader.h @@ -29,6 +29,9 @@ private: GLuint uTexture; GLuint uPaletteTex; + GLuint uPeelingTex; + GLuint uPeeling; + GLuint vVertMat; GLuint vVertVec; @@ -47,12 +50,18 @@ private: GLuint _vboInstances; GLuint _vao; + GLsizei _instanceCount; + public: DrawRectShader(); ~DrawRectShader() override; void SetScreenSize(sint32 width, sint32 height); - void DrawInstances(const RectCommandBatch& instances); + void EnablePeeling(GLuint peelingTex); + void DisablePeeling(); + + void SetInstances(const RectCommandBatch& instances); + void DrawInstances(); private: void GetLocations(); diff --git a/src/openrct2-ui/drawing/engines/opengl/OpenGLAPI.h b/src/openrct2-ui/drawing/engines/opengl/OpenGLAPI.h index a328abd5d9..3e96f9fb9a 100644 --- a/src/openrct2-ui/drawing/engines/opengl/OpenGLAPI.h +++ b/src/openrct2-ui/drawing/engines/opengl/OpenGLAPI.h @@ -29,6 +29,7 @@ #define glClearColor __static__glClearColor #define glCullFace __static__glCullFace #define glDeleteTextures __static__glDeleteTextures +#define glDepthFunc __static__glDepthFunc #define glDisable __static__glDisable #define glDrawArrays __static__glDrawArrays #define glEnable __static__glEnable @@ -60,6 +61,7 @@ #undef glClearColor #undef glCullFace #undef glDeleteTextures +#undef glDepthFunc #undef glDisable #undef glDrawArrays #undef glEnable @@ -84,6 +86,7 @@ typedef void (APIENTRYP PFNGLCLEARPROC )(GLbitfield mask); typedef void (APIENTRYP PFNGLCLEARCOLORPROC )(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); typedef void (APIENTRYP PFNGLCULLFACEPROC )(GLenum mode); typedef void (APIENTRYP PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint *textures); +typedef void (APIENTRYP PFNGLDEPTHFUNCPROC )(GLenum func); typedef void (APIENTRYP PFNGLDISABLEPROC )(GLenum cap); typedef void (APIENTRYP PFNGLDRAWARRAYSPROC )(GLenum mode, GLint first, GLsizei count); typedef void (APIENTRYP PFNGLENABLEPROC )(GLenum cap); diff --git a/src/openrct2-ui/drawing/engines/opengl/OpenGLAPIProc.h b/src/openrct2-ui/drawing/engines/opengl/OpenGLAPIProc.h index 0831c39abb..8f6321f23a 100644 --- a/src/openrct2-ui/drawing/engines/opengl/OpenGLAPIProc.h +++ b/src/openrct2-ui/drawing/engines/opengl/OpenGLAPIProc.h @@ -27,6 +27,7 @@ OPENGL_PROC(PFNGLCLEARPROC, glClear) OPENGL_PROC(PFNGLCLEARCOLORPROC, glClearColor) OPENGL_PROC(PFNGLCULLFACEPROC, glCullFace) OPENGL_PROC(PFNGLDELETETEXTURESPROC, glDeleteTextures) +OPENGL_PROC(PFNGLDEPTHFUNCPROC, glDepthFunc) OPENGL_PROC(PFNGLDISABLEPROC, glDisable) OPENGL_PROC(PFNGLDRAWARRAYSPROC, glDrawArrays) OPENGL_PROC(PFNGLENABLEPROC, glEnable) diff --git a/src/openrct2-ui/drawing/engines/opengl/OpenGLDrawingEngine.cpp b/src/openrct2-ui/drawing/engines/opengl/OpenGLDrawingEngine.cpp index 66785b336c..7ba4b15f3c 100644 --- a/src/openrct2-ui/drawing/engines/opengl/OpenGLDrawingEngine.cpp +++ b/src/openrct2-ui/drawing/engines/opengl/OpenGLDrawingEngine.cpp @@ -16,6 +16,8 @@ #ifndef DISABLE_OPENGL +#include +#include #include #include #include @@ -97,7 +99,6 @@ public: IDrawingEngine * GetEngine() override; TextureCache * GetTextureCache() const { return _textureCache; } - SwapFramebuffer * GetSwapFramebuffer() const { return _swapFramebuffer; } const OpenGLFramebuffer & GetFinalFramebuffer() const { return _swapFramebuffer->GetFinalFramebuffer(); } void Initialise(); @@ -116,10 +117,12 @@ public: void FlushCommandBuffers(); - void FlushLines(LineCommandBatch &batch); - void FlushRectangles(RectCommandBatch &batch); + void FlushLines(); + void FlushRectangles(); + void HandleTransparency(); void SetDPI(rct_drawpixelinfo * dpi); + sint32 MaxTransparencyDepth(); }; class OpenGLDrawingEngine : public IDrawingEngine @@ -810,35 +813,75 @@ void OpenGLDrawingContext::DrawGlyph(uint32 image, sint32 x, sint32 y, uint8 * p void OpenGLDrawingContext::FlushCommandBuffers() { glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + _swapFramebuffer->BindOpaque(); - FlushLines(_commandBuffers.lines); - FlushRectangles(_commandBuffers.rects); - _swapFramebuffer->BindTransparent(); - FlushRectangles(_commandBuffers.transparent); - _swapFramebuffer->ApplyTransparency(*_applyTransparencyShader, _textureCache->GetPaletteTexture()); + _drawRectShader->Use(); + _drawRectShader->DisablePeeling(); + + FlushLines(); + FlushRectangles(); + + HandleTransparency(); } -void OpenGLDrawingContext::FlushLines(LineCommandBatch &batch) +void OpenGLDrawingContext::FlushLines() { - if (batch.size() == 0) return; + if (_commandBuffers.lines.size() == 0) return; _drawLineShader->Use(); - _drawLineShader->DrawInstances(batch); + _drawLineShader->DrawInstances(_commandBuffers.lines); - batch.clear(); + _commandBuffers.lines.clear(); } -void OpenGLDrawingContext::FlushRectangles(RectCommandBatch &batch) +void OpenGLDrawingContext::FlushRectangles() { - if (batch.size() == 0) return; + if (_commandBuffers.rects.size() == 0) return; OpenGLAPI::SetTexture(0, GL_TEXTURE_2D_ARRAY, _textureCache->GetAtlasesTexture()); OpenGLAPI::SetTexture(1, GL_TEXTURE_RECTANGLE, _textureCache->GetPaletteTexture()); _drawRectShader->Use(); - _drawRectShader->DrawInstances(batch); + _drawRectShader->SetInstances(_commandBuffers.rects); + _drawRectShader->DrawInstances(); - batch.clear(); + _commandBuffers.rects.clear(); +} + +void OpenGLDrawingContext::HandleTransparency() +{ + if (_commandBuffers.transparent.empty()) + { + return; + } + + _drawRectShader->Use(); + _drawRectShader->SetInstances(_commandBuffers.transparent); + + sint32 max_depth = MaxTransparencyDepth(); + for (sint32 i=0; i < max_depth; ++i) + { + _swapFramebuffer->BindTransparent(); + + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_GREATER); + _drawRectShader->Use(); + + if (i > 0) + { + _drawRectShader->EnablePeeling(_swapFramebuffer->GetBackDepthTexture()); + } + + OpenGLAPI::SetTexture(0, GL_TEXTURE_2D_ARRAY, _textureCache->GetAtlasesTexture()); + OpenGLAPI::SetTexture(1, GL_TEXTURE_RECTANGLE, _textureCache->GetPaletteTexture()); + + _drawRectShader->Use(); + _drawRectShader->DrawInstances(); + _swapFramebuffer->ApplyTransparency(*_applyTransparencyShader, _textureCache->GetPaletteTexture()); + } + + _commandBuffers.transparent.clear(); } void OpenGLDrawingContext::SetDPI(rct_drawpixelinfo * dpi) @@ -862,4 +905,142 @@ void OpenGLDrawingContext::SetDPI(rct_drawpixelinfo * dpi) _dpi = dpi; } +sint32 OpenGLDrawingContext::MaxTransparencyDepth() +{ + sint32 max_depth = 1; + + struct xdata + { + sint32 xposition; + bool begin; + sint32 top, bottom; + }; + std::vector x_sweep; + x_sweep.reserve(_commandBuffers.transparent.size() * 2); + for (DrawRectCommand &command : _commandBuffers.transparent) + { + sint32 left = std::min(std::max(command.bounds.x, command.clip.x), command.clip.z); + sint32 top = std::min(std::max(command.bounds.y, command.clip.y), command.clip.w); + sint32 right = std::min(std::max(command.bounds.z, command.clip.x), command.clip.z); + sint32 bottom = std::min(std::max(command.bounds.w, command.clip.y), command.clip.w); + + assert(left <= right); + assert(top <= bottom); + if (left == right) continue; + if (top == bottom) continue; + + x_sweep.push_back({left, true, top, bottom}); + x_sweep.push_back({right, false, top, bottom}); + } + std::sort(x_sweep.begin(), x_sweep.end(), [](const xdata &a, const xdata &b) -> bool { + if (a.xposition != b.xposition) return a.xposition < b.xposition; + else return !a.begin && b.begin; + }); + + struct ydata + { + sint32 count, depth; + }; + std::map y_intersect; + for (const xdata &x : x_sweep) + { + assert(y_intersect.size() == 0 || y_intersect.begin()->second.depth == 0); + if (x.begin) + { + auto top_in = y_intersect.insert({x.top, {1, 0}}); + auto top_it = top_in.first; + if (top_in.second) + { + auto top_next = std::next(top_it); + if (top_next != y_intersect.end()) + { + top_it->second.depth = top_next->second.depth; + } + } + else + { + assert(top_it->second.count > 0); + ++top_it->second.count; + } + + auto bottom_in = y_intersect.insert({x.bottom, {1, 1}}); + auto bottom_it = bottom_in.first; + if (bottom_in.second) + { + auto bottom_next = std::next(bottom_it); + if (bottom_next != y_intersect.end()) + { + bottom_it->second.depth = bottom_next->second.depth + 1; + } + } + else + { + assert(bottom_it->second.count > 0); + ++bottom_it->second.count; + max_depth = std::max(max_depth, ++bottom_it->second.depth); + } + + for (auto it = std::next(top_it); it != bottom_it; ++it) + { + max_depth = std::max(max_depth, ++it->second.depth); + } + } + else + { + auto top_it = y_intersect.find(x.top); + assert(top_it != y_intersect.end()); + assert(top_it->second.count > 0); + auto bottom_it = y_intersect.find(x.bottom); + assert(bottom_it != y_intersect.end()); + assert(bottom_it->second.count > 0); + +#ifndef NDEBUG + if (top_it->second.count == 1) + { + auto top_next = std::next(top_it); + assert(top_next == y_intersect.end() ? + top_it->second.depth == 0 : + top_it->second.depth == top_next->second.depth - 1); + } + + if (bottom_it->second.count == 1) + { + auto bottom_next = std::next(bottom_it); + assert(bottom_next == y_intersect.end() ? + bottom_it->second.depth == 1 : + bottom_it->second.depth == bottom_next->second.depth + 1); + } +#endif /* NDEBUG */ + + for (auto it = std::next(top_it); it != bottom_it; ++it) + { + assert(it->second.depth > 0); + --it->second.depth; + } + + if (top_it->second.count == 1) + { + y_intersect.erase(top_it); + } + else + { + --top_it->second.count; + } + + if (bottom_it->second.count == 1) + { + y_intersect.erase(bottom_it); + } + else + { + assert(bottom_it->second.depth > 0); + --bottom_it->second.count; + --bottom_it->second.depth; + } + } + } + + return max_depth; +} + #endif /* DISABLE_OPENGL */ diff --git a/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.cpp b/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.cpp index d3f925b37d..d8ea63c452 100644 --- a/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.cpp +++ b/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.cpp @@ -44,12 +44,7 @@ OpenGLFramebuffer::OpenGLFramebuffer(sint32 width, sint32 height, bool depth) if (depth) { - glGenTextures(1, &_depth); - glBindTexture(GL_TEXTURE_2D, _depth); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); + _depth = CreateDepthTexture(width, height); } else { @@ -93,7 +88,9 @@ void OpenGLFramebuffer::GetPixels(rct_drawpixelinfo &dpi) const assert(dpi.width == _width && dpi.height == _height); uint8 * pixels = Memory::Allocate(_width * _height); - glReadPixels(0, 0, _width, _height, GL_RED_INTEGER, GL_UNSIGNED_BYTE, pixels); + glBindTexture(GL_TEXTURE_2D, _texture); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glGetTexImage(GL_TEXTURE_2D, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, pixels); // Flip pixels vertically on copy uint8 * src = pixels + ((_height - 1) * _width); @@ -107,4 +104,37 @@ void OpenGLFramebuffer::GetPixels(rct_drawpixelinfo &dpi) const Memory::Free(pixels); } +void OpenGLFramebuffer::SwapColourBuffer(OpenGLFramebuffer &other) +{ + std::swap(_texture, other._texture); + + glBindFramebuffer(GL_FRAMEBUFFER, _id); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, other._id); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, other._texture, 0); +} + +GLuint OpenGLFramebuffer::SwapDepthTexture(GLuint depth) +{ + std::swap(_depth, depth); + + glBindFramebuffer(GL_FRAMEBUFFER, _id); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _depth, 0); + + return depth; +} + +GLuint OpenGLFramebuffer::CreateDepthTexture(sint32 width, sint32 height) +{ + GLuint depth; + glGenTextures(1, &depth); + glBindTexture(GL_TEXTURE_2D, depth); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); + return depth; +} + #endif /* DISABLE_OPENGL */ diff --git a/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.h b/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.h index ebb8ed7a86..6bf4d18bb2 100644 --- a/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.h +++ b/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.h @@ -38,6 +38,9 @@ public: OpenGLFramebuffer(sint32 width, sint32 height, bool depth = true); ~OpenGLFramebuffer(); + OpenGLFramebuffer(const OpenGLFramebuffer &) = delete; + OpenGLFramebuffer &operator=(const OpenGLFramebuffer &) = delete; + GLuint GetWidth() const { return _width; } GLuint GetHeight() const { return _height; } GLuint GetTexture() const { return _texture; } @@ -47,4 +50,9 @@ public: void BindDraw() const; void BindRead() const; void GetPixels(rct_drawpixelinfo &dpi) const; + + void SwapColourBuffer(OpenGLFramebuffer &other); + GLuint SwapDepthTexture(GLuint depth); + + static GLuint CreateDepthTexture(sint32 width, sint32 height); }; diff --git a/src/openrct2-ui/drawing/engines/opengl/SwapFramebuffer.cpp b/src/openrct2-ui/drawing/engines/opengl/SwapFramebuffer.cpp index 84aa2cd788..39a82302bb 100644 --- a/src/openrct2-ui/drawing/engines/opengl/SwapFramebuffer.cpp +++ b/src/openrct2-ui/drawing/engines/opengl/SwapFramebuffer.cpp @@ -20,24 +20,21 @@ #include "OpenGLFramebuffer.h" #include "SwapFramebuffer.h" +constexpr GLfloat depthValue[1] = { 1.0f }; +constexpr GLfloat depthValueTransparent[1] = { 0.0f }; +constexpr GLuint indexValue[4] = { 0, 0, 0, 0 }; + SwapFramebuffer::SwapFramebuffer(sint32 width, sint32 height) : _opaqueFramebuffer(width, height), _transparentFramebuffer(width, height), -_finalFramebuffer(width, height, false) -{ } - -void SwapFramebuffer::BindOpaque() -{ - _opaqueFramebuffer.Bind(); -} - -void SwapFramebuffer::BindTransparent() +_mixFramebuffer(width, height, false), _backDepth(OpenGLFramebuffer::CreateDepthTexture(width, height)) { _transparentFramebuffer.Bind(); + glClearBufferfv(GL_DEPTH, 0, depthValueTransparent); } void SwapFramebuffer::ApplyTransparency(ApplyTransparencyShader &shader, GLuint paletteTex) { - _finalFramebuffer.Bind(); + _mixFramebuffer.Bind(); glDisable(GL_DEPTH_TEST); shader.Use(); shader.SetTextures( @@ -49,21 +46,22 @@ void SwapFramebuffer::ApplyTransparency(ApplyTransparencyShader &shader, GLuint ); shader.Draw(); + _backDepth = _transparentFramebuffer.SwapDepthTexture(_backDepth); + + // Clear transparency buffers + _transparentFramebuffer.Bind(); + glClearBufferuiv(GL_COLOR, 0, indexValue); + glClearBufferfv(GL_DEPTH, 0, depthValueTransparent); + + _opaqueFramebuffer.SwapColourBuffer(_mixFramebuffer); //Change binding to guaruntee no undefined behavior _opaqueFramebuffer.Bind(); } void SwapFramebuffer::Clear() { - static const GLfloat depthValue[1] = { 1.0f }; - static const GLuint indexValue[4] = { 0, 0, 0, 0 }; - _opaqueFramebuffer.Bind(); glClearBufferfv(GL_DEPTH, 0, depthValue); - - _transparentFramebuffer.Bind(); - glClearBufferuiv(GL_COLOR, 0, indexValue); - glClearBufferfv(GL_DEPTH, 0, depthValue); } #endif /* DISABLE_OPENGL */ diff --git a/src/openrct2-ui/drawing/engines/opengl/SwapFramebuffer.h b/src/openrct2-ui/drawing/engines/opengl/SwapFramebuffer.h index eaad8c165e..fc1c2dc3c2 100644 --- a/src/openrct2-ui/drawing/engines/opengl/SwapFramebuffer.h +++ b/src/openrct2-ui/drawing/engines/opengl/SwapFramebuffer.h @@ -36,18 +36,17 @@ class SwapFramebuffer final private: OpenGLFramebuffer _opaqueFramebuffer; OpenGLFramebuffer _transparentFramebuffer; - OpenGLFramebuffer _finalFramebuffer; + OpenGLFramebuffer _mixFramebuffer; + GLuint _backDepth; public: SwapFramebuffer(sint32 width, sint32 height); - const OpenGLFramebuffer &GetOpaqueFramebuffer() const { return _opaqueFramebuffer; } - const OpenGLFramebuffer &GetTransparentFramebuffer() const { return _transparentFramebuffer; } - const OpenGLFramebuffer &GetFinalFramebuffer() const { return _finalFramebuffer; } - GLuint GetFinalTexture() const { return _finalFramebuffer.GetTexture(); } + const OpenGLFramebuffer &GetFinalFramebuffer() const { return _opaqueFramebuffer; } + GLuint GetBackDepthTexture() const { return _backDepth; } + void BindOpaque() { _opaqueFramebuffer.Bind(); } + void BindTransparent() { _transparentFramebuffer.Bind(); } - void BindOpaque(); - void BindTransparent(); void ApplyTransparency(ApplyTransparencyShader &shader, GLuint paletteTex); void Clear(); };