Manual rounding support in OpenGL media viewer.

This commit is contained in:
John Preston 2023-02-17 12:11:32 +04:00
parent b9e0c60adf
commit 24a1208b9a
7 changed files with 117 additions and 2 deletions

View file

@ -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<OverlayWidget*> 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<const char*>(
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<const void*>(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;

View file

@ -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<QOpenGLShaderProgram> _nv12Program;
std::optional<QOpenGLShaderProgram> _fillProgram;
std::optional<QOpenGLShaderProgram> _controlsProgram;
std::optional<QOpenGLShaderProgram> _roundedCornersProgram;
Ui::GL::Textures<4> _textures;
QSize _rgbaSize;
QSize _lumaSize;

View file

@ -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

View file

@ -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);

View file

@ -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;
};

View file

@ -3692,6 +3692,9 @@ void OverlayWidget::paint(not_null<Renderer*> renderer) {
}
}
checkGroupThumbsAnimation();
if (const auto radius = _window->manualRoundingRadius()) {
renderer->paintRoundedCorners(radius);
}
}
void OverlayWidget::checkGroupThumbsAnimation() {

@ -1 +1 @@
Subproject commit eb4d44ecd37815dc9465ec46b86f94191531b0c7
Subproject commit 3b69ec499ccc7f4208a6413fbeb6f5ebe84f3f55