From 302cffba1c6310d77b7d7fe58de7e8a712588540 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 25 May 2021 12:08:06 +0400 Subject: [PATCH] Display pin button in OpenGL renderer. --- Telegram/SourceFiles/calls/calls.style | 22 +- .../calls/group/calls_group_viewport.cpp | 4 +- .../calls/group/calls_group_viewport.h | 2 + .../group/calls_group_viewport_opengl.cpp | 332 ++++++++++++++---- .../calls/group/calls_group_viewport_opengl.h | 29 +- .../group/calls_group_viewport_raster.cpp | 62 ++-- .../calls/group/calls_group_viewport_raster.h | 5 +- .../calls/group/calls_group_viewport_tile.cpp | 77 ++-- .../calls/group/calls_group_viewport_tile.h | 25 +- Telegram/lib_ui | 2 +- 10 files changed, 389 insertions(+), 171 deletions(-) diff --git a/Telegram/SourceFiles/calls/calls.style b/Telegram/SourceFiles/calls/calls.style index 21d3da9fc3..5f525b01a2 100644 --- a/Telegram/SourceFiles/calls/calls.style +++ b/Telegram/SourceFiles/calls/calls.style @@ -1223,23 +1223,29 @@ groupCallLargeVideoCrossLine: CrossLineAnimation(groupCallMemberColoredCrossLine GroupCallLargeVideo { shadowHeight: pixels; namePosition: point; + pin: CrossLineAnimation; pinPosition: point; pinPadding: margins; pinTextPosition: point; iconPosition: point; } -groupCallLargeVideoWide: GroupCallLargeVideo { +groupCallLargeVideo: GroupCallLargeVideo { shadowHeight: 40px; namePosition: point(15px, 8px); + pin: CrossLineAnimation { + fg: groupCallVideoTextFg; + icon: icon {{ "calls/video_over_pin", groupCallVideoTextFg }}; + startPosition: point(7px, 4px); + endPosition: point(17px, 14px); + stroke: 3px; + strokeDenominator: 2; + } pinPosition: point(18px, 18px); pinPadding: margins(6px, 2px, 12px, 1px); pinTextPosition: point(1px, 3px); iconPosition: point(10px, 5px); } -groupCallLargeVideoNarrow: GroupCallLargeVideo(groupCallLargeVideoWide) { - pinPosition: point(-1px, -1px); -} //groupCallLargeVideoListItem: PeerListItem(groupCallMembersListItem) { // nameFg: groupCallVideoTextFg; // nameFgChecked: groupCallVideoTextFg; @@ -1247,14 +1253,6 @@ groupCallLargeVideoNarrow: GroupCallLargeVideo(groupCallLargeVideoWide) { // statusFgOver: groupCallVideoSubTextFg; // statusFgActive: groupCallVideoSubTextFg; //} -groupCallLargeVideoPin: CrossLineAnimation { - fg: groupCallVideoTextFg; - icon: icon {{ "calls/video_over_pin", groupCallVideoTextFg }}; - startPosition: point(7px, 4px); - endPosition: point(17px, 14px); - stroke: 3px; - strokeDenominator: 2; -} groupCallVideoSmallSkip: 4px; groupCallVideoLargeSkip: 6px; diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport.cpp b/Telegram/SourceFiles/calls/group/calls_group_viewport.cpp index 70efbfc9df..92815a4384 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_viewport.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_viewport.cpp @@ -41,8 +41,8 @@ Viewport::Viewport(not_null parent, PanelMode mode) Viewport::~Viewport() { for (const auto &tile : base::take(_tiles)) { - if (const auto textures = tile->takeTextures()) { - _freeTextures(textures); + if (auto textures = tile->takeTextures()) { + _freeTextures(base::take(textures)); } } } diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport.h b/Telegram/SourceFiles/calls/group/calls_group_viewport.h index b1974040f0..1c021c1cd8 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_viewport.h +++ b/Telegram/SourceFiles/calls/group/calls_group_viewport.h @@ -110,6 +110,8 @@ private: } }; + static constexpr auto kShadowMaxAlpha = 80; + void setup(); [[nodiscard]] bool wide() const; diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp b/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp index 92aa4d2dac..6bd122cfb4 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp @@ -10,12 +10,34 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "calls/group/calls_group_viewport_tile.h" #include "webrtc/webrtc_video_track.h" #include "media/view/media_view_pip.h" +#include "styles/style_calls.h" #include namespace Calls::Group { namespace { +struct FloatRect { + FloatRect(QRect rect) + : x(rect.x()) + , y(rect.y()) + , width(rect.width()) + , height(rect.height()) { + } + + FloatRect(QRectF rect) + : x(rect.x()) + , y(rect.y()) + , width(rect.width()) + , height(rect.height()) { + } + + float x = 0; + float y = 0; + float width = 0; + float height = 0; +}; + struct ShaderPart { QString header; QString body; @@ -141,14 +163,23 @@ float roundedCorner() { return { .header = R"( uniform vec4 frameBg; -)", - .body = R"( +uniform vec3 shadow; // fullHeight, shown, maxOpacity +float insideTexture() { vec2 textureHalf = vec2(0.5, 0.5); vec2 fromTextureCenter = abs(v_texcoord - textureHalf); vec2 fromTextureEdge = max(fromTextureCenter, textureHalf) - textureHalf; float outsideCheck = dot(fromTextureEdge, fromTextureEdge); - float inside = step(outsideCheck, 0); + return step(outsideCheck, 0); +} +)", + .body = R"( + float inside = insideTexture(); result = result * inside + frameBg * (1. - inside); + + float shadowCoord = gl_FragCoord.y - roundRect.y; + float shadowValue = max(1. - (shadowCoord / shadow.x), 0.); + float shadowShown = shadowValue * shadow.y * shadow.z; + result = vec4(result.rgb * (1. - shadowShown), result.a); )", }; } @@ -241,7 +272,7 @@ void FillRectVertices(GLfloat *coords, QRect rect, GLfloat factor) { } void FillTriangles( - not_null f, + QOpenGLFunctions &f, gsl::span coords, not_null buffer, not_null program, @@ -256,33 +287,78 @@ void FillTriangles( buffer->bind(); buffer->allocate(coords.data(), coords.size() * sizeof(GLfloat)); - f->glUseProgram(program->programId()); + f.glUseProgram(program->programId()); program->setUniformValue("viewport", QSizeF(viewportWithFactor)); program->setUniformValue("s_color", Uniform(color)); GLint position = program->attributeLocation("position"); - f->glVertexAttribPointer( + f.glVertexAttribPointer( position, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), nullptr); - f->glEnableVertexAttribArray(position); + f.glEnableVertexAttribArray(position); if (additional) { additional(); } - f->glDrawArrays(GL_TRIANGLES, 0, coords.size() / 2); + f.glDrawArrays(GL_TRIANGLES, 0, coords.size() / 2); - f->glDisableVertexAttribArray(position); + f.glDisableVertexAttribArray(position); +} + +void FillTexturedRectangle( + QOpenGLFunctions &f, + not_null program, + int skipVertices = 0) { + const auto shift = [&](int elements) { + return reinterpret_cast( + (skipVertices * 4 + elements) * sizeof(GLfloat)); + }; + GLint position = program->attributeLocation("position"); + f.glVertexAttribPointer( + position, + 2, + GL_FLOAT, + GL_FALSE, + 4 * sizeof(GLfloat), + shift(0)); + f.glEnableVertexAttribArray(position); + + GLint texcoord = program->attributeLocation("texcoord"); + f.glVertexAttribPointer( + texcoord, + 2, + GL_FLOAT, + GL_FALSE, + 4 * sizeof(GLfloat), + shift(2)); + f.glEnableVertexAttribArray(texcoord); + + f.glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + f.glDisableVertexAttribArray(position); + f.glDisableVertexAttribArray(texcoord); } } // namespace Viewport::RendererGL::RendererGL(not_null owner) -: _owner(owner) { +: _owner(owner) +, _pinIcon(st::groupCallLargeVideo.pin) +, _pinBackground( + (st::groupCallLargeVideo.pinPadding.top() + + st::groupCallLargeVideo.pin.icon.height() + + st::groupCallLargeVideo.pinPadding.bottom()) / 2, + st::radialBg) { + + style::PaletteChanged( + ) | rpl::start_with_next([=] { + _pinButtons.invalidate(); + }, _lifetime); } void Viewport::RendererGL::free(const Textures &textures) { @@ -291,11 +367,13 @@ void Viewport::RendererGL::free(const Textures &textures) { void Viewport::RendererGL::init( not_null widget, - not_null f) { + QOpenGLFunctions &f) { _factor = widget->devicePixelRatio(); _frameBuffer.emplace(); _frameBuffer->setUsagePattern(QOpenGLBuffer::DynamicDraw); _frameBuffer->create(); + _frameBuffer->bind(); + _frameBuffer->allocate(64 * sizeof(GLfloat)); _yuv420Program.emplace(); _frameVertexShader = LinkProgram( &*_yuv420Program, @@ -309,7 +387,6 @@ void Viewport::RendererGL::init( FragmentRoundCorners(), })).vertex; - _bgBuffer.emplace(); _bgBuffer->setUsagePattern(QOpenGLBuffer::DynamicDraw); _bgBuffer->create(); @@ -318,6 +395,14 @@ void Viewport::RendererGL::init( &*_bgProgram, VertexShader({ VertexViewportTransform() }), FragmentShader({ FragmentStaticColor() })); + + _imageProgram.emplace(); + LinkProgram( + &*_imageProgram, + _frameVertexShader, + FragmentShader({ + FragmentSampleARGB32Texture(), + })); } void Viewport::RendererGL::ensureARGB32Program() { @@ -336,34 +421,36 @@ void Viewport::RendererGL::ensureARGB32Program() { void Viewport::RendererGL::deinit( not_null widget, - not_null f) { - _frameBuffer = std::nullopt; + QOpenGLFunctions &f) { _bgBuffer = std::nullopt; + _frameBuffer = std::nullopt; _frameVertexShader = nullptr; + _bgProgram = std::nullopt; + _imageProgram = std::nullopt; _argb32Program = std::nullopt; _yuv420Program = std::nullopt; - _bgProgram = std::nullopt; for (const auto &tile : _owner->_tiles) { if (const auto textures = tile->takeTextures()) { free(textures); } } freeTextures(f); + _pinButtons.destroy(f); } void Viewport::RendererGL::resize( not_null widget, - not_null f, + QOpenGLFunctions &f, int w, int h) { _factor = widget->devicePixelRatio(); _viewport = QSize(w, h); - f->glViewport(0, 0, w * _factor, h * _factor); + f.glViewport(0, 0, w * _factor, h * _factor); } void Viewport::RendererGL::paint( not_null widget, - not_null f) { + QOpenGLFunctions &f) { _factor = widget->devicePixelRatio(); fillBackground(f); for (const auto &tile : _owner->_tiles) { @@ -372,7 +459,7 @@ void Viewport::RendererGL::paint( freeTextures(f); } -void Viewport::RendererGL::fillBackground(not_null f) { +void Viewport::RendererGL::fillBackground(QOpenGLFunctions &f) { const auto radius = st::roundRadiusLarge; const auto radiuses = QMargins{ radius, radius, radius, radius }; auto bg = QRegion(QRect(QPoint(), _viewport)); @@ -398,7 +485,7 @@ void Viewport::RendererGL::fillBackground(not_null f) { } void Viewport::RendererGL::paintTile( - not_null f, + QOpenGLFunctions &f, not_null tile) { const auto track = tile->track(); const auto data = track->frameWithInfo(false); @@ -406,11 +493,12 @@ void Viewport::RendererGL::paintTile( return; } - const auto geometry = tileGeometry(tile); - const auto x = geometry.x(); - const auto y = geometry.y(); - const auto width = geometry.width(); - const auto height = geometry.height(); + const auto geometry = tile->geometry(); + const auto flipped = flipRect(geometry); + const auto x = flipped.x(); + const auto y = flipped.y(); + const auto width = flipped.width(); + const auto height = flipped.height(); const auto expand = !_owner->wide()/* && !tile->screencast()*/; const auto scaled = Media::View::FlipSizeByRotation( data.yuv420->size, @@ -447,19 +535,64 @@ void Viewport::RendererGL::paintTile( texCoord.begin() + (data.rotation / 90), texCoord.end()); } + + ensurePinImage(); + const auto pinRasterRect = tile->pinInner().translated( + geometry.topLeft()); + const auto pinVisibleRect = pinRasterRect.intersected(geometry); + const auto pin = FloatRect(flipRect(pinVisibleRect)); + const auto pinTextureRect = tile->pinned() ? _pinOn : _pinOff; + const auto pinUseTextureRect = QRect( + pinTextureRect.x(), + pinTextureRect.y() + pinVisibleRect.y() - pinRasterRect.y(), + pinTextureRect.width(), + pinVisibleRect.height()); + const auto pinImageDimensions = _pinButtons.image().size(); + const auto pinTexture = FloatRect(QRectF( + pinUseTextureRect.x() / float(pinImageDimensions.width()), + pinUseTextureRect.y() / float(pinImageDimensions.height()), + pinUseTextureRect.width() / float(pinImageDimensions.width()), + pinUseTextureRect.height() / float(pinImageDimensions.height()))); + const GLfloat coords[] = { - x * _factor, y * _factor, texCoord[0][0], texCoord[0][1], - (x + width) * _factor, y * _factor, texCoord[1][0], texCoord[1][1], - (x + width) * _factor, (y + height) * _factor, texCoord[2][0], texCoord[2][1], - x * _factor, (y + height) * _factor, texCoord[3][0], texCoord[3][1], + // Frame. + x * _factor, y * _factor, + texCoord[0][0], texCoord[0][1], + + (x + width) * _factor, y * _factor, + texCoord[1][0], texCoord[1][1], + + (x + width) * _factor, (y + height) * _factor, + texCoord[2][0], texCoord[2][1], + + x * _factor, (y + height) * _factor, + texCoord[3][0], texCoord[3][1], + + // Pin button. + pin.x * _factor, pin.y * _factor, + pinTexture.x, pinTexture.y + pinTexture.height, + + (pin.x + pin.width) * _factor, pin.y * _factor, + pinTexture.x + pinTexture.width, pinTexture.y + pinTexture.height, + + (pin.x + pin.width) * _factor, (pin.y + pin.height) * _factor, + pinTexture.x + pinTexture.width, pinTexture.y, + + pin.x * _factor, (pin.y + pin.height) * _factor, + pinTexture.x, pinTexture.y, }; tile->ensureTexturesCreated(f); const auto &textures = tile->textures(); const auto upload = (textures.trackIndex != data.index); - const auto uploadOne = [&](GLint internalformat, GLint format, QSize size, int stride, const void *data) { - f->glPixelStorei(GL_UNPACK_ROW_LENGTH, stride); - f->glTexImage2D( + const auto uploadOne = [&]( + GLint internalformat, + GLint format, + QSize size, + int stride, + const void *data) { + f.glPixelStorei(GL_UNPACK_ROW_LENGTH, stride); + f.glTexImage2D( GL_TEXTURE_2D, 0, internalformat, @@ -469,7 +602,7 @@ void Viewport::RendererGL::paintTile( format, GL_UNSIGNED_BYTE, data); - f->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + f.glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); }; if (upload) { textures.textureIndex = 1 - textures.textureIndex; @@ -477,10 +610,9 @@ void Viewport::RendererGL::paintTile( const auto rgba = (data.format == Webrtc::FrameFormat::ARGB32); if (rgba) { ensureARGB32Program(); - const auto texture = textures.values[textures.textureIndex]; - f->glUseProgram(_argb32Program->programId()); - f->glActiveTexture(GL_TEXTURE0); - f->glBindTexture(GL_TEXTURE_2D, texture); + f.glUseProgram(_argb32Program->programId()); + f.glActiveTexture(GL_TEXTURE0); + textures.values.bind(f, textures.textureIndex); if (upload) { const auto &image = data.original; const auto stride = image.bytesPerLine() / 4; @@ -491,22 +623,19 @@ void Viewport::RendererGL::paintTile( } else { const auto yuv = data.yuv420; const auto otherSize = yuv->chromaSize; - const auto textureY = textures.values[textures.textureIndex * 3 + 0]; - const auto textureU = textures.values[textures.textureIndex * 3 + 1]; - const auto textureV = textures.values[textures.textureIndex * 3 + 2]; - f->glUseProgram(_yuv420Program->programId()); - f->glActiveTexture(GL_TEXTURE0); - f->glBindTexture(GL_TEXTURE_2D, textureY); + f.glUseProgram(_yuv420Program->programId()); + f.glActiveTexture(GL_TEXTURE0); + textures.values.bind(f, textures.textureIndex * 3 + 0); if (upload) { uploadOne(GL_RED, GL_RED, yuv->size, yuv->y.stride, yuv->y.data); } - f->glActiveTexture(GL_TEXTURE1); - f->glBindTexture(GL_TEXTURE_2D, textureU); + f.glActiveTexture(GL_TEXTURE1); + textures.values.bind(f, textures.textureIndex * 3 + 1); if (upload) { uploadOne(GL_RED, GL_RED, otherSize, yuv->u.stride, yuv->u.data); } - f->glActiveTexture(GL_TEXTURE2); - f->glBindTexture(GL_TEXTURE_2D, textureV); + f.glActiveTexture(GL_TEXTURE2); + textures.values.bind(f, textures.textureIndex * 3 + 2); if (upload) { uploadOne(GL_RED, GL_RED, otherSize, yuv->v.stride, yuv->v.data); } @@ -517,45 +646,61 @@ void Viewport::RendererGL::paintTile( tile->track()->markFrameShown(); _frameBuffer->bind(); - _frameBuffer->allocate(coords, sizeof(coords)); + _frameBuffer->write(0, coords, sizeof(coords)); const auto program = rgba ? &*_argb32Program : &*_yuv420Program; + const auto uniformViewport = QSizeF(_viewport * _factor); - program->setUniformValue("viewport", QSizeF(_viewport * _factor)); + program->setUniformValue("viewport", uniformViewport); program->setUniformValue( "frameBg", Uniform(st::groupCallMembersBg->c)); program->setUniformValue("roundRadius", radius * _factor); - program->setUniformValue("roundRect", Uniform(geometry, _factor)); + program->setUniformValue("roundRect", Uniform(flipped, _factor)); program->setUniformValue("roundBg", Uniform(st::groupCallBg->c)); - GLint position = program->attributeLocation("position"); - f->glVertexAttribPointer( - position, - 2, - GL_FLOAT, - GL_FALSE, - 4 * sizeof(GLfloat), - nullptr); - f->glEnableVertexAttribArray(position); + const auto &st = st::groupCallLargeVideo; + const auto shown = _owner->_controlsShownRatio; + const auto shadowHeight = st.shadowHeight * _factor; + const auto shadowAlpha = kShadowMaxAlpha / 255.f; + program->setUniformValue( + "shadow", + QVector3D(shadowHeight, shown, shadowAlpha)); - GLint texcoord = program->attributeLocation("texcoord"); - f->glVertexAttribPointer( - texcoord, - 2, - GL_FLOAT, - GL_FALSE, - 4 * sizeof(GLfloat), - reinterpret_cast(2 * sizeof(GLfloat))); - f->glEnableVertexAttribArray(texcoord); + FillTexturedRectangle(f, program); - f->glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + const auto pinVisible = _owner->wide() + && (pinRasterRect.y() + pinRasterRect.height() > y); + if (shown == 0. && !pinVisible) { + return; + } - f->glDisableVertexAttribArray(position); + f.glEnable(GL_BLEND); + f.glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + const auto guard = gsl::finally([&] { + f.glDisable(GL_BLEND); + }); + + f.glUseProgram(_imageProgram->programId()); + if (pinVisible) { + f.glActiveTexture(GL_TEXTURE0); + _pinButtons.bind(f); + _imageProgram->setUniformValue("viewport", uniformViewport); + _imageProgram->setUniformValue("s_texture", GLint(0)); + FillTexturedRectangle(f, &*_imageProgram, 4); + } + + if (shown == 0.) { + return; + } } QRect Viewport::RendererGL::tileGeometry(not_null tile) const { const auto raster = tile->geometry(); + return flipRect(tile->geometry()); +} + +QRect Viewport::RendererGL::flipRect(const QRect &raster) const { return { raster.x(), _viewport.height() - raster.y() - raster.height(), @@ -564,10 +709,51 @@ QRect Viewport::RendererGL::tileGeometry(not_null tile) const { }; } -void Viewport::RendererGL::freeTextures(not_null f) { - for (const auto &textures : base::take(_texturesToFree)) { - f->glDeleteTextures(textures.values.size(), textures.values.data()); +void Viewport::RendererGL::freeTextures(QOpenGLFunctions &f) { + for (auto &textures : base::take(_texturesToFree)) { + textures.values.destroy(f); } } +void Viewport::RendererGL::ensurePinImage() { + if (_pinButtons) { + return; + } + const auto pinOnSize = VideoTile::PinInnerSize(true); + const auto pinOffSize = VideoTile::PinInnerSize(false); + const auto fullSize = QSize( + std::max(pinOnSize.width(), pinOffSize.width()), + pinOnSize.height() + pinOffSize.height()); + const auto imageSize = fullSize * cIntRetinaFactor(); + auto image = _pinButtons.takeImage(); + if (image.size() != imageSize) { + image = QImage(imageSize, QImage::Format_ARGB32_Premultiplied); + } + image.fill(Qt::transparent); + image.setDevicePixelRatio(cRetinaFactor()); + { + auto p = Painter(&image); + auto hq = PainterHighQualityEnabler(p); + _pinOn = QRect(QPoint(), pinOnSize); + VideoTile::PaintPinButton( + p, + true, + 0, + 0, + fullSize.width(), + &_pinBackground, + &_pinIcon); + _pinOff = QRect(QPoint(0, pinOnSize.height()), pinOffSize); + VideoTile::PaintPinButton( + p, + false, + 0, + pinOnSize.height(), + fullSize.width(), + &_pinBackground, + &_pinIcon); + } + _pinButtons.setImage(std::move(image)); +} + } // namespace Calls::Group diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.h b/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.h index 1b01969337..ec321ddc40 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.h +++ b/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.h @@ -8,7 +8,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "calls/group/calls_group_viewport.h" +#include "ui/round_rect.h" +#include "ui/effects/cross_line.h" #include "ui/gl/gl_surface.h" +#include "ui/gl/gl_image.h" #include #include @@ -23,30 +26,33 @@ public: void init( not_null widget, - not_null f) override; + QOpenGLFunctions &f) override; void deinit( not_null widget, - not_null f) override; + QOpenGLFunctions &f) override; void resize( not_null widget, - not_null f, + QOpenGLFunctions &f, int w, int h) override; void paint( not_null widget, - not_null f) override; + QOpenGLFunctions &f) override; private: - void fillBackground(not_null f); + void fillBackground(QOpenGLFunctions &f); void paintTile( - not_null f, + QOpenGLFunctions &f, not_null tile); - void freeTextures(not_null f); + void freeTextures(QOpenGLFunctions &f); [[nodiscard]] QRect tileGeometry(not_null tile) const; + [[nodiscard]] QRect flipRect(const QRect &raster) const; + void ensureARGB32Program(); + void ensurePinImage(); const not_null _owner; @@ -56,11 +62,20 @@ private: std::optional _bgBuffer; std::optional _argb32Program; std::optional _yuv420Program; + std::optional _imageProgram; std::optional _bgProgram; QOpenGLShader *_frameVertexShader = nullptr; + Ui::GL::Image _pinButtons; + QRect _pinOn; + QRect _pinOff; + std::vector _bgTriangles; std::vector _texturesToFree; + Ui::CrossLineAnimation _pinIcon; + Ui::RoundRect _pinBackground; + + rpl::lifetime _lifetime; }; diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport_raster.cpp b/Telegram/SourceFiles/calls/group/calls_group_viewport_raster.cpp index 0983da839e..8860bcadc4 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_viewport_raster.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_viewport_raster.cpp @@ -17,22 +17,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/palette.h" namespace Calls::Group { -namespace { - -constexpr auto kShadowMaxAlpha = 80; - -} // namespace Viewport::Renderer::Renderer(not_null owner) : _owner(owner) -, _pinIcon(st::groupCallLargeVideoPin) +, _pinIcon(st::groupCallLargeVideo.pin) , _pinBackground( - (st::groupCallLargeVideoWide.pinPadding.top() - + st::groupCallLargeVideoPin.icon.height() - + st::groupCallLargeVideoWide.pinPadding.bottom()) / 2, - st::radialBg) -, _pinTextOn(st::semiboldTextStyle, tr::lng_pinned_unpin(tr::now)) -, _pinTextOff(st::semiboldTextStyle, tr::lng_pinned_pin(tr::now)) { + (st::groupCallLargeVideo.pinPadding.top() + + st::groupCallLargeVideo.pin.icon.height() + + st::groupCallLargeVideo.pinPadding.bottom()) / 2, + st::radialBg) { } void Viewport::Renderer::paintFallback( @@ -132,44 +125,29 @@ void Viewport::Renderer::paintTileControls( // Pin. const auto wide = _owner->wide(); if (wide) { - const auto inner = tile->pinInner().translated(x, y); - const auto pinned = tile->pinned(); - const auto &icon = st::groupCallLargeVideoPin.icon; - const auto &st = st::groupCallLargeVideoWide; - _pinBackground.paint(p, inner); - _pinIcon.paint( + const auto inner = tile->pinInner(); + VideoTile::PaintPinButton( p, - inner.marginsRemoved(st.pinPadding).topLeft(), - pinned ? 1. : 0.); - p.setPen(st::groupCallVideoTextFg); - const auto &text = (pinned ? _pinTextOn : _pinTextOff); - text.drawLeft( - p, - (inner.x() - + st.pinPadding.left() - + icon.width() - + st.pinTextPosition.x()), - (inner.y() - + st.pinPadding.top() - + st.pinTextPosition.y()), - text.maxWidth(), - _owner->widget()->width()); + tile->pinned(), + x + inner.x(), + y + inner.y(), + _owner->widget()->width(), + &_pinBackground, + &_pinIcon); } - const auto &st = wide - ? st::groupCallLargeVideoWide - : st::groupCallLargeVideoNarrow; - const auto fullShift = st.namePosition.y() + st::normalFont->height; const auto shown = _owner->_controlsShownRatio; if (shown == 0.) { return; } + const auto &st = st::groupCallLargeVideo; + const auto fullShift = st.namePosition.y() + st::normalFont->height; const auto shift = anim::interpolate(fullShift, 0, shown); - auto &shadow = wide ? _shadowWide : _shadowNarrow; + // Shadow. - if (shadow.isNull()) { - shadow = GenerateShadow(st.shadowHeight, 0, kShadowMaxAlpha); + if (_shadow.isNull()) { + _shadow = GenerateShadow(st.shadowHeight, 0, kShadowMaxAlpha); } const auto shadowRect = QRect( x, @@ -183,11 +161,11 @@ void Viewport::Renderer::paintTileControls( const auto factor = style::DevicePixelRatio(); p.drawImage( shadowFill, - shadow, + _shadow, QRect( 0, (shadowFill.y() - shadowRect.y()) * factor, - shadow.width(), + _shadow.width(), shadowFill.height() * factor)); const auto row = tile->row(); row->lazyInitialize(st::groupCallMembersListItem); diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport_raster.h b/Telegram/SourceFiles/calls/group/calls_group_viewport_raster.h index 6a8f35ae5c..2066eef567 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_viewport_raster.h +++ b/Telegram/SourceFiles/calls/group/calls_group_viewport_raster.h @@ -41,12 +41,9 @@ private: const not_null _owner; - QImage _shadowWide; - QImage _shadowNarrow; + QImage _shadow; Ui::CrossLineAnimation _pinIcon; Ui::RoundRect _pinBackground; - Ui::Text::String _pinTextOn; - Ui::Text::String _pinTextOff; }; diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport_tile.cpp b/Telegram/SourceFiles/calls/group/calls_group_viewport_tile.cpp index 4a84959233..fa32418e70 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_viewport_tile.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_viewport_tile.cpp @@ -9,6 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "webrtc/webrtc_video_track.h" #include "lang/lang_keys.h" +#include "ui/round_rect.h" +#include "ui/effects/cross_line.h" #include "styles/style_calls.h" #include @@ -43,7 +45,7 @@ QRect Viewport::VideoTile::pinOuter() const { int Viewport::VideoTile::pinSlide() const { return anim::interpolate( - st::groupCallLargeVideoWide.pinPosition.y() + _pinInner.height(), + st::groupCallLargeVideo.pinPosition.y() + _pinInner.height(), 0, _pinShownAnimation.value(_pinShown ? 1. : 0.)); } @@ -73,12 +75,12 @@ bool Viewport::VideoTile::updateRequestedQuality(VideoQuality quality) { return true; } -void Viewport::VideoTile::updatePinnedGeometry() { - const auto &st = st::groupCallLargeVideoWide; - const auto &icon = st::groupCallLargeVideoPin.icon; +QSize Viewport::VideoTile::PinInnerSize(bool pinned) { + const auto &st = st::groupCallLargeVideo; + const auto &icon = st::groupCallLargeVideo.pin.icon; const auto innerWidth = icon.width() + st.pinTextPosition.x() - + st::semiboldFont->width(_pinned + + st::semiboldFont->width(pinned ? tr::lng_pinned_unpin(tr::now) : tr::lng_pinned_pin(tr::now)); const auto innerHeight = icon.height(); @@ -88,13 +90,49 @@ void Viewport::VideoTile::updatePinnedGeometry() { const auto buttonHeight = st.pinPadding.top() + innerHeight + st.pinPadding.bottom(); - const auto fullWidth = st.pinPosition.x() * 2 + buttonWidth; - const auto fullHeight = st.pinPosition.y() * 2 + buttonHeight; - _pinInner = QRect( - _geometry.width() - st.pinPosition.x() - buttonWidth, - st.pinPosition.y(), - buttonWidth, - buttonHeight); + return { buttonWidth, buttonHeight }; +} + +void Viewport::VideoTile::PaintPinButton( + Painter &p, + bool pinned, + int x, + int y, + int outerWidth, + not_null background, + not_null icon) { + const auto &st = st::groupCallLargeVideo; + const auto rect = QRect(QPoint(x, y), PinInnerSize(pinned)); + background->paint(p, rect); + icon->paint( + p, + rect.marginsRemoved(st.pinPadding).topLeft(), + pinned ? 1. : 0.); + p.setPen(st::groupCallVideoTextFg); + p.setFont(st::semiboldFont); + p.drawTextLeft( + (x + + st.pinPadding.left() + + st::groupCallLargeVideo.pin.icon.width() + + st.pinTextPosition.x()), + (y + + st.pinPadding.top() + + st.pinTextPosition.y()), + outerWidth, + (pinned + ? tr::lng_pinned_unpin(tr::now) + : tr::lng_pinned_pin(tr::now))); + +} + +void Viewport::VideoTile::updatePinnedGeometry() { + const auto &st = st::groupCallLargeVideo; + const auto buttonSize = PinInnerSize(_pinned); + const auto fullWidth = st.pinPosition.x() * 2 + buttonSize.width(); + const auto fullHeight = st.pinPosition.y() * 2 + buttonSize.height(); + _pinInner = QRect(QPoint(), buttonSize).translated( + _geometry.width() - st.pinPosition.x() - buttonSize.width(), + st.pinPosition.y()); _pinOuter = QRect( _geometry.width() - fullWidth, 0, @@ -130,19 +168,8 @@ void Viewport::VideoTile::setup(rpl::producer pinned) { } void Viewport::VideoTile::ensureTexturesCreated( - not_null f) { - if (_textures) { - return; - } - f->glGenTextures(_textures.values.size(), _textures.values.data()); - for (const auto texture : _textures.values) { - f->glBindTexture(GL_TEXTURE_2D, texture); - const auto clamp = GL_CLAMP_TO_EDGE; - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, clamp); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, clamp); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } + QOpenGLFunctions &f) { + _textures.values.ensureCreated(f); } const Viewport::Textures &Viewport::VideoTile::textures() const { diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport_tile.h b/Telegram/SourceFiles/calls/group/calls_group_viewport_tile.h index 7393cae171..4920ea87b6 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_viewport_tile.h +++ b/Telegram/SourceFiles/calls/group/calls_group_viewport_tile.h @@ -10,20 +10,25 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "calls/group/calls_group_viewport.h" #include "calls/group/calls_group_call.h" #include "ui/effects/animations.h" -#include "ui/effects/cross_line.h" -#include "ui/round_rect.h" +#include "ui/gl/gl_image.h" +class Painter; class QOpenGLFunctions; +namespace Ui { +class CrossLineAnimation; +class RoundRect; +} // namespace Ui + namespace Calls::Group { struct Viewport::Textures { - std::array values = { { 0 } }; + Ui::GL::Textures<6> values; mutable int textureIndex = 0; mutable int trackIndex = -1; explicit operator bool() const { - return (values[0] != 0); + return values.created(); } }; @@ -64,7 +69,7 @@ public: void togglePinShown(bool shown); bool updateRequestedQuality(VideoQuality quality); - void ensureTexturesCreated(not_null f); + void ensureTexturesCreated(QOpenGLFunctions &f); [[nodiscard]] const Textures &textures() const; [[nodiscard]] Textures takeTextures(); @@ -72,6 +77,16 @@ public: return _lifetime; } + [[nodiscard]] static QSize PinInnerSize(bool pinned); + static void PaintPinButton( + Painter &p, + bool pinned, + int x, + int y, + int outerWidth, + not_null background, + not_null icon); + private: void setup(rpl::producer pinned); [[nodiscard]] int pinSlide() const; diff --git a/Telegram/lib_ui b/Telegram/lib_ui index c946611689..2a26d4a91a 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit c9466116894715a2343f43a0b6aa22602d89262e +Subproject commit 2a26d4a91aca5f9850e5a3d7d5cd58ed0b74639a