Display pin button in OpenGL renderer.

This commit is contained in:
John Preston 2021-05-25 12:08:06 +04:00
parent e299aa032d
commit 302cffba1c
10 changed files with 389 additions and 171 deletions

View file

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

View file

@ -41,8 +41,8 @@ Viewport::Viewport(not_null<QWidget*> 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));
}
}
}

View file

@ -110,6 +110,8 @@ private:
}
};
static constexpr auto kShadowMaxAlpha = 80;
void setup();
[[nodiscard]] bool wide() const;

View file

@ -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 <QtGui/QOpenGLShader>
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<QOpenGLFunctions*> f,
QOpenGLFunctions &f,
gsl::span<const GLfloat> coords,
not_null<QOpenGLBuffer*> buffer,
not_null<QOpenGLShaderProgram*> 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<QOpenGLShaderProgram*> program,
int skipVertices = 0) {
const auto shift = [&](int elements) {
return reinterpret_cast<const void*>(
(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<Viewport*> 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<QOpenGLWidget*> widget,
not_null<QOpenGLFunctions*> 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<QOpenGLWidget*> widget,
not_null<QOpenGLFunctions*> 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<QOpenGLWidget*> widget,
not_null<QOpenGLFunctions*> 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<QOpenGLWidget*> widget,
not_null<QOpenGLFunctions*> 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<QOpenGLFunctions*> 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<QOpenGLFunctions*> f) {
}
void Viewport::RendererGL::paintTile(
not_null<QOpenGLFunctions*> f,
QOpenGLFunctions &f,
not_null<VideoTile*> 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<const void*>(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<VideoTile*> 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<VideoTile*> tile) const {
};
}
void Viewport::RendererGL::freeTextures(not_null<QOpenGLFunctions*> 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

View file

@ -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 <QtGui/QOpenGLBuffer>
#include <QtGui/QOpenGLShaderProgram>
@ -23,30 +26,33 @@ public:
void init(
not_null<QOpenGLWidget*> widget,
not_null<QOpenGLFunctions*> f) override;
QOpenGLFunctions &f) override;
void deinit(
not_null<QOpenGLWidget*> widget,
not_null<QOpenGLFunctions*> f) override;
QOpenGLFunctions &f) override;
void resize(
not_null<QOpenGLWidget*> widget,
not_null<QOpenGLFunctions*> f,
QOpenGLFunctions &f,
int w,
int h) override;
void paint(
not_null<QOpenGLWidget*> widget,
not_null<QOpenGLFunctions*> f) override;
QOpenGLFunctions &f) override;
private:
void fillBackground(not_null<QOpenGLFunctions*> f);
void fillBackground(QOpenGLFunctions &f);
void paintTile(
not_null<QOpenGLFunctions*> f,
QOpenGLFunctions &f,
not_null<VideoTile*> tile);
void freeTextures(not_null<QOpenGLFunctions*> f);
void freeTextures(QOpenGLFunctions &f);
[[nodiscard]] QRect tileGeometry(not_null<VideoTile*> tile) const;
[[nodiscard]] QRect flipRect(const QRect &raster) const;
void ensureARGB32Program();
void ensurePinImage();
const not_null<Viewport*> _owner;
@ -56,11 +62,20 @@ private:
std::optional<QOpenGLBuffer> _bgBuffer;
std::optional<QOpenGLShaderProgram> _argb32Program;
std::optional<QOpenGLShaderProgram> _yuv420Program;
std::optional<QOpenGLShaderProgram> _imageProgram;
std::optional<QOpenGLShaderProgram> _bgProgram;
QOpenGLShader *_frameVertexShader = nullptr;
Ui::GL::Image _pinButtons;
QRect _pinOn;
QRect _pinOff;
std::vector<GLfloat> _bgTriangles;
std::vector<Textures> _texturesToFree;
Ui::CrossLineAnimation _pinIcon;
Ui::RoundRect _pinBackground;
rpl::lifetime _lifetime;
};

View file

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

View file

@ -41,12 +41,9 @@ private:
const not_null<Viewport*> _owner;
QImage _shadowWide;
QImage _shadowNarrow;
QImage _shadow;
Ui::CrossLineAnimation _pinIcon;
Ui::RoundRect _pinBackground;
Ui::Text::String _pinTextOn;
Ui::Text::String _pinTextOff;
};

View file

@ -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 <QtGui/QOpenGLFunctions>
@ -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<Ui::RoundRect*> background,
not_null<Ui::CrossLineAnimation*> 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<bool> pinned) {
}
void Viewport::VideoTile::ensureTexturesCreated(
not_null<QOpenGLFunctions*> 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 {

View file

@ -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<GLuint, 6> 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<QOpenGLFunctions*> 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<Ui::RoundRect*> background,
not_null<Ui::CrossLineAnimation*> icon);
private:
void setup(rpl::producer<bool> pinned);
[[nodiscard]] int pinSlide() const;

@ -1 +1 @@
Subproject commit c9466116894715a2343f43a0b6aa22602d89262e
Subproject commit 2a26d4a91aca5f9850e5a3d7d5cd58ed0b74639a