diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp index 4541c3746..130184e61 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp @@ -46,6 +46,31 @@ uniform float transparentSize; }; } +[[nodiscard]] ShaderPart FragmentRoundedCorners() { + return { + .header = R"( +uniform vec4 roundRect; +uniform float roundRadius; + +float roundedCorner() { + vec2 rectHalf = roundRect.zw / 2.; + vec2 rectCenter = roundRect.xy + rectHalf; + vec2 fromRectCenter = abs(gl_FragCoord.xy - rectCenter); + vec2 vectorRadius = vec2(roundRadius + 0.5, roundRadius + 0.5); + vec2 fromCenterWithRadius = fromRectCenter + vectorRadius; + vec2 fromRoundingCenter = max(fromCenterWithRadius, rectHalf) + - rectHalf; + float rounded = length(fromRoundingCenter) - roundRadius; + + return 1. - smoothstep(0., 1., rounded); +} +)", + .body = R"( + result = vec4(roundedCorner()); +)", + }; +} + } // namespace OverlayWidget::RendererGL::RendererGL(not_null owner) @@ -69,7 +94,10 @@ void OverlayWidget::RendererGL::init( constexpr auto kQuadVertices = kQuads * 4; constexpr auto kQuadValues = kQuadVertices * 4; constexpr auto kControlsValues = kControlsCount * kControlValues; - constexpr auto kValues = kQuadValues + kControlsValues; + constexpr auto kRoundingQuads = 4; + constexpr auto kRoundingVertices = kRoundingQuads * 6; + constexpr auto kRoundingValues = kRoundingVertices * 2; + constexpr auto kValues = kQuadValues + kControlsValues + kRoundingValues; _contentBuffer.emplace(); _contentBuffer->setUsagePattern(QOpenGLBuffer::DynamicDraw); @@ -130,6 +158,12 @@ void OverlayWidget::RendererGL::init( FragmentGlobalOpacity(), })); + _roundedCornersProgram.emplace(); + LinkProgram( + &*_roundedCornersProgram, + VertexShader({ VertexViewportTransform() }), + FragmentShader({ FragmentRoundedCorners() })); + const auto renderer = reinterpret_cast( f.glGetString(GL_RENDERER)); CrashReports::SetAnnotation( @@ -598,6 +632,76 @@ void OverlayWidget::RendererGL::paintGroupThumbs( }, kGroupThumbsOffset, true); } +void OverlayWidget::RendererGL::paintRoundedCorners(int radius) { + const auto topLeft = transformRect(QRect(0, 0, radius, radius)); + const auto topRight = transformRect( + QRect(_viewport.width() - radius, 0, radius, radius)); + const auto bottomRight = transformRect(QRect( + _viewport.width() - radius, + _viewport.height() - radius, + radius, + radius)); + const auto bottomLeft = transformRect( + QRect(0, _viewport.height() - radius, radius, radius)); + const GLfloat coords[] = { + topLeft.left(), topLeft.top(), + topLeft.right(), topLeft.top(), + topLeft.right(), topLeft.bottom(), + topLeft.right(), topLeft.bottom(), + topLeft.left(), topLeft.bottom(), + topLeft.left(), topLeft.top(), + + topRight.left(), topRight.top(), + topRight.right(), topRight.top(), + topRight.right(), topRight.bottom(), + topRight.right(), topRight.bottom(), + topRight.left(), topRight.bottom(), + topRight.left(), topRight.top(), + + bottomRight.left(), bottomRight.top(), + bottomRight.right(), bottomRight.top(), + bottomRight.right(), bottomRight.bottom(), + bottomRight.right(), bottomRight.bottom(), + bottomRight.left(), bottomRight.bottom(), + bottomRight.left(), bottomRight.top(), + + bottomLeft.left(), bottomLeft.top(), + bottomLeft.right(), bottomLeft.top(), + bottomLeft.right(), bottomLeft.bottom(), + bottomLeft.right(), bottomLeft.bottom(), + bottomLeft.left(), bottomLeft.bottom(), + bottomLeft.left(), bottomLeft.top(), + }; + const auto offset = kControlsOffset + + (kControlsCount * kControlValues) / 4; + const auto byteOffset = offset * 4 * sizeof(GLfloat); + _contentBuffer->write(byteOffset, coords, sizeof(coords)); + _roundedCornersProgram->bind(); + _roundedCornersProgram->setUniformValue("viewport", _uniformViewport); + const auto roundRect = transformRect(QRect(QPoint(), _viewport)); + _roundedCornersProgram->setUniformValue("roundRect", Uniform(roundRect)); + _roundedCornersProgram->setUniformValue( + "roundRadius", + GLfloat(radius * _factor)); + + _f->glEnable(GL_BLEND); + _f->glBlendFunc(GL_ZERO, GL_SRC_ALPHA); + + GLint position = _roundedCornersProgram->attributeLocation("position"); + _f->glVertexAttribPointer( + position, + 2, + GL_FLOAT, + GL_FALSE, + 2 * sizeof(GLfloat), + reinterpret_cast(byteOffset)); + _f->glEnableVertexAttribArray(position); + + _f->glDrawArrays(GL_TRIANGLES, 0, base::array_size(coords) / 2); + + _f->glDisableVertexAttribArray(position); +} + void OverlayWidget::RendererGL::invalidate() { _trackFrameIndex = -1; _streamedIndex = -1; diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_opengl.h b/Telegram/SourceFiles/media/view/media_view_overlay_opengl.h index f996e4880..f143e712c 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_opengl.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_opengl.h @@ -68,6 +68,7 @@ private: void paintFooter(QRect outer, float64 opacity) override; void paintCaption(QRect outer, float64 opacity) override; void paintGroupThumbs(QRect outer, float64 opacity) override; + void paintRoundedCorners(int radius) override; void invalidate(); @@ -110,6 +111,7 @@ private: std::optional _nv12Program; std::optional _fillProgram; std::optional _controlsProgram; + std::optional _roundedCornersProgram; Ui::GL::Textures<4> _textures; QSize _rgbaSize; QSize _lumaSize; diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_raster.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_raster.cpp index 7a0cc3952..3755be032 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_raster.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_raster.cpp @@ -190,4 +190,8 @@ void OverlayWidget::RendererSW::paintGroupThumbs( } } +void OverlayWidget::RendererSW::paintRoundedCorners(int radius) { + // The RpWindow rounding overlay will do the job. +} + } // namespace Media::View diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_raster.h b/Telegram/SourceFiles/media/view/media_view_overlay_raster.h index 365eb1c42..7e91f660b 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_raster.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_raster.h @@ -50,6 +50,7 @@ private: void paintFooter(QRect outer, float64 opacity) override; void paintCaption(QRect outer, float64 opacity) override; void paintGroupThumbs(QRect outer, float64 opacity) override; + void paintRoundedCorners(int radius) override; [[nodiscard]] static QRect TransformRect(QRectF geometry, int rotation); diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_renderer.h b/Telegram/SourceFiles/media/view/media_view_overlay_renderer.h index 6b58abdcc..2ecbccf27 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_renderer.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_renderer.h @@ -38,6 +38,7 @@ public: virtual void paintFooter(QRect outer, float64 opacity) = 0; virtual void paintCaption(QRect outer, float64 opacity) = 0; virtual void paintGroupThumbs(QRect outer, float64 opacity) = 0; + virtual void paintRoundedCorners(int radius) = 0; }; diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index e0a8c35a1..b86bcfc7c 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -3692,6 +3692,9 @@ void OverlayWidget::paint(not_null renderer) { } } checkGroupThumbsAnimation(); + if (const auto radius = _window->manualRoundingRadius()) { + renderer->paintRoundedCorners(radius); + } } void OverlayWidget::checkGroupThumbsAnimation() { diff --git a/Telegram/lib_ui b/Telegram/lib_ui index eb4d44ecd..3b69ec499 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit eb4d44ecd37815dc9465ec46b86f94191531b0c7 +Subproject commit 3b69ec499ccc7f4208a6413fbeb6f5ebe84f3f55