mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-08 08:04:08 +02:00
Display pin button in OpenGL renderer.
This commit is contained in:
parent
e299aa032d
commit
302cffba1c
10 changed files with 389 additions and 171 deletions
|
@ -1223,23 +1223,29 @@ groupCallLargeVideoCrossLine: CrossLineAnimation(groupCallMemberColoredCrossLine
|
||||||
GroupCallLargeVideo {
|
GroupCallLargeVideo {
|
||||||
shadowHeight: pixels;
|
shadowHeight: pixels;
|
||||||
namePosition: point;
|
namePosition: point;
|
||||||
|
pin: CrossLineAnimation;
|
||||||
pinPosition: point;
|
pinPosition: point;
|
||||||
pinPadding: margins;
|
pinPadding: margins;
|
||||||
pinTextPosition: point;
|
pinTextPosition: point;
|
||||||
iconPosition: point;
|
iconPosition: point;
|
||||||
}
|
}
|
||||||
|
|
||||||
groupCallLargeVideoWide: GroupCallLargeVideo {
|
groupCallLargeVideo: GroupCallLargeVideo {
|
||||||
shadowHeight: 40px;
|
shadowHeight: 40px;
|
||||||
namePosition: point(15px, 8px);
|
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);
|
pinPosition: point(18px, 18px);
|
||||||
pinPadding: margins(6px, 2px, 12px, 1px);
|
pinPadding: margins(6px, 2px, 12px, 1px);
|
||||||
pinTextPosition: point(1px, 3px);
|
pinTextPosition: point(1px, 3px);
|
||||||
iconPosition: point(10px, 5px);
|
iconPosition: point(10px, 5px);
|
||||||
}
|
}
|
||||||
groupCallLargeVideoNarrow: GroupCallLargeVideo(groupCallLargeVideoWide) {
|
|
||||||
pinPosition: point(-1px, -1px);
|
|
||||||
}
|
|
||||||
//groupCallLargeVideoListItem: PeerListItem(groupCallMembersListItem) {
|
//groupCallLargeVideoListItem: PeerListItem(groupCallMembersListItem) {
|
||||||
// nameFg: groupCallVideoTextFg;
|
// nameFg: groupCallVideoTextFg;
|
||||||
// nameFgChecked: groupCallVideoTextFg;
|
// nameFgChecked: groupCallVideoTextFg;
|
||||||
|
@ -1247,14 +1253,6 @@ groupCallLargeVideoNarrow: GroupCallLargeVideo(groupCallLargeVideoWide) {
|
||||||
// statusFgOver: groupCallVideoSubTextFg;
|
// statusFgOver: groupCallVideoSubTextFg;
|
||||||
// statusFgActive: 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;
|
groupCallVideoSmallSkip: 4px;
|
||||||
groupCallVideoLargeSkip: 6px;
|
groupCallVideoLargeSkip: 6px;
|
||||||
|
|
|
@ -41,8 +41,8 @@ Viewport::Viewport(not_null<QWidget*> parent, PanelMode mode)
|
||||||
|
|
||||||
Viewport::~Viewport() {
|
Viewport::~Viewport() {
|
||||||
for (const auto &tile : base::take(_tiles)) {
|
for (const auto &tile : base::take(_tiles)) {
|
||||||
if (const auto textures = tile->takeTextures()) {
|
if (auto textures = tile->takeTextures()) {
|
||||||
_freeTextures(textures);
|
_freeTextures(base::take(textures));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,6 +110,8 @@ private:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static constexpr auto kShadowMaxAlpha = 80;
|
||||||
|
|
||||||
void setup();
|
void setup();
|
||||||
[[nodiscard]] bool wide() const;
|
[[nodiscard]] bool wide() const;
|
||||||
|
|
||||||
|
|
|
@ -10,12 +10,34 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "calls/group/calls_group_viewport_tile.h"
|
#include "calls/group/calls_group_viewport_tile.h"
|
||||||
#include "webrtc/webrtc_video_track.h"
|
#include "webrtc/webrtc_video_track.h"
|
||||||
#include "media/view/media_view_pip.h"
|
#include "media/view/media_view_pip.h"
|
||||||
|
#include "styles/style_calls.h"
|
||||||
|
|
||||||
#include <QtGui/QOpenGLShader>
|
#include <QtGui/QOpenGLShader>
|
||||||
|
|
||||||
namespace Calls::Group {
|
namespace Calls::Group {
|
||||||
namespace {
|
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 {
|
struct ShaderPart {
|
||||||
QString header;
|
QString header;
|
||||||
QString body;
|
QString body;
|
||||||
|
@ -141,14 +163,23 @@ float roundedCorner() {
|
||||||
return {
|
return {
|
||||||
.header = R"(
|
.header = R"(
|
||||||
uniform vec4 frameBg;
|
uniform vec4 frameBg;
|
||||||
)",
|
uniform vec3 shadow; // fullHeight, shown, maxOpacity
|
||||||
.body = R"(
|
float insideTexture() {
|
||||||
vec2 textureHalf = vec2(0.5, 0.5);
|
vec2 textureHalf = vec2(0.5, 0.5);
|
||||||
vec2 fromTextureCenter = abs(v_texcoord - textureHalf);
|
vec2 fromTextureCenter = abs(v_texcoord - textureHalf);
|
||||||
vec2 fromTextureEdge = max(fromTextureCenter, textureHalf) - textureHalf;
|
vec2 fromTextureEdge = max(fromTextureCenter, textureHalf) - textureHalf;
|
||||||
float outsideCheck = dot(fromTextureEdge, fromTextureEdge);
|
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);
|
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(
|
void FillTriangles(
|
||||||
not_null<QOpenGLFunctions*> f,
|
QOpenGLFunctions &f,
|
||||||
gsl::span<const GLfloat> coords,
|
gsl::span<const GLfloat> coords,
|
||||||
not_null<QOpenGLBuffer*> buffer,
|
not_null<QOpenGLBuffer*> buffer,
|
||||||
not_null<QOpenGLShaderProgram*> program,
|
not_null<QOpenGLShaderProgram*> program,
|
||||||
|
@ -256,33 +287,78 @@ void FillTriangles(
|
||||||
buffer->bind();
|
buffer->bind();
|
||||||
buffer->allocate(coords.data(), coords.size() * sizeof(GLfloat));
|
buffer->allocate(coords.data(), coords.size() * sizeof(GLfloat));
|
||||||
|
|
||||||
f->glUseProgram(program->programId());
|
f.glUseProgram(program->programId());
|
||||||
program->setUniformValue("viewport", QSizeF(viewportWithFactor));
|
program->setUniformValue("viewport", QSizeF(viewportWithFactor));
|
||||||
program->setUniformValue("s_color", Uniform(color));
|
program->setUniformValue("s_color", Uniform(color));
|
||||||
|
|
||||||
GLint position = program->attributeLocation("position");
|
GLint position = program->attributeLocation("position");
|
||||||
f->glVertexAttribPointer(
|
f.glVertexAttribPointer(
|
||||||
position,
|
position,
|
||||||
2,
|
2,
|
||||||
GL_FLOAT,
|
GL_FLOAT,
|
||||||
GL_FALSE,
|
GL_FALSE,
|
||||||
2 * sizeof(GLfloat),
|
2 * sizeof(GLfloat),
|
||||||
nullptr);
|
nullptr);
|
||||||
f->glEnableVertexAttribArray(position);
|
f.glEnableVertexAttribArray(position);
|
||||||
|
|
||||||
if (additional) {
|
if (additional) {
|
||||||
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
|
} // namespace
|
||||||
|
|
||||||
Viewport::RendererGL::RendererGL(not_null<Viewport*> owner)
|
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) {
|
void Viewport::RendererGL::free(const Textures &textures) {
|
||||||
|
@ -291,11 +367,13 @@ void Viewport::RendererGL::free(const Textures &textures) {
|
||||||
|
|
||||||
void Viewport::RendererGL::init(
|
void Viewport::RendererGL::init(
|
||||||
not_null<QOpenGLWidget*> widget,
|
not_null<QOpenGLWidget*> widget,
|
||||||
not_null<QOpenGLFunctions*> f) {
|
QOpenGLFunctions &f) {
|
||||||
_factor = widget->devicePixelRatio();
|
_factor = widget->devicePixelRatio();
|
||||||
_frameBuffer.emplace();
|
_frameBuffer.emplace();
|
||||||
_frameBuffer->setUsagePattern(QOpenGLBuffer::DynamicDraw);
|
_frameBuffer->setUsagePattern(QOpenGLBuffer::DynamicDraw);
|
||||||
_frameBuffer->create();
|
_frameBuffer->create();
|
||||||
|
_frameBuffer->bind();
|
||||||
|
_frameBuffer->allocate(64 * sizeof(GLfloat));
|
||||||
_yuv420Program.emplace();
|
_yuv420Program.emplace();
|
||||||
_frameVertexShader = LinkProgram(
|
_frameVertexShader = LinkProgram(
|
||||||
&*_yuv420Program,
|
&*_yuv420Program,
|
||||||
|
@ -309,7 +387,6 @@ void Viewport::RendererGL::init(
|
||||||
FragmentRoundCorners(),
|
FragmentRoundCorners(),
|
||||||
})).vertex;
|
})).vertex;
|
||||||
|
|
||||||
|
|
||||||
_bgBuffer.emplace();
|
_bgBuffer.emplace();
|
||||||
_bgBuffer->setUsagePattern(QOpenGLBuffer::DynamicDraw);
|
_bgBuffer->setUsagePattern(QOpenGLBuffer::DynamicDraw);
|
||||||
_bgBuffer->create();
|
_bgBuffer->create();
|
||||||
|
@ -318,6 +395,14 @@ void Viewport::RendererGL::init(
|
||||||
&*_bgProgram,
|
&*_bgProgram,
|
||||||
VertexShader({ VertexViewportTransform() }),
|
VertexShader({ VertexViewportTransform() }),
|
||||||
FragmentShader({ FragmentStaticColor() }));
|
FragmentShader({ FragmentStaticColor() }));
|
||||||
|
|
||||||
|
_imageProgram.emplace();
|
||||||
|
LinkProgram(
|
||||||
|
&*_imageProgram,
|
||||||
|
_frameVertexShader,
|
||||||
|
FragmentShader({
|
||||||
|
FragmentSampleARGB32Texture(),
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Viewport::RendererGL::ensureARGB32Program() {
|
void Viewport::RendererGL::ensureARGB32Program() {
|
||||||
|
@ -336,34 +421,36 @@ void Viewport::RendererGL::ensureARGB32Program() {
|
||||||
|
|
||||||
void Viewport::RendererGL::deinit(
|
void Viewport::RendererGL::deinit(
|
||||||
not_null<QOpenGLWidget*> widget,
|
not_null<QOpenGLWidget*> widget,
|
||||||
not_null<QOpenGLFunctions*> f) {
|
QOpenGLFunctions &f) {
|
||||||
_frameBuffer = std::nullopt;
|
|
||||||
_bgBuffer = std::nullopt;
|
_bgBuffer = std::nullopt;
|
||||||
|
_frameBuffer = std::nullopt;
|
||||||
_frameVertexShader = nullptr;
|
_frameVertexShader = nullptr;
|
||||||
|
_bgProgram = std::nullopt;
|
||||||
|
_imageProgram = std::nullopt;
|
||||||
_argb32Program = std::nullopt;
|
_argb32Program = std::nullopt;
|
||||||
_yuv420Program = std::nullopt;
|
_yuv420Program = std::nullopt;
|
||||||
_bgProgram = std::nullopt;
|
|
||||||
for (const auto &tile : _owner->_tiles) {
|
for (const auto &tile : _owner->_tiles) {
|
||||||
if (const auto textures = tile->takeTextures()) {
|
if (const auto textures = tile->takeTextures()) {
|
||||||
free(textures);
|
free(textures);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
freeTextures(f);
|
freeTextures(f);
|
||||||
|
_pinButtons.destroy(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Viewport::RendererGL::resize(
|
void Viewport::RendererGL::resize(
|
||||||
not_null<QOpenGLWidget*> widget,
|
not_null<QOpenGLWidget*> widget,
|
||||||
not_null<QOpenGLFunctions*> f,
|
QOpenGLFunctions &f,
|
||||||
int w,
|
int w,
|
||||||
int h) {
|
int h) {
|
||||||
_factor = widget->devicePixelRatio();
|
_factor = widget->devicePixelRatio();
|
||||||
_viewport = QSize(w, h);
|
_viewport = QSize(w, h);
|
||||||
f->glViewport(0, 0, w * _factor, h * _factor);
|
f.glViewport(0, 0, w * _factor, h * _factor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Viewport::RendererGL::paint(
|
void Viewport::RendererGL::paint(
|
||||||
not_null<QOpenGLWidget*> widget,
|
not_null<QOpenGLWidget*> widget,
|
||||||
not_null<QOpenGLFunctions*> f) {
|
QOpenGLFunctions &f) {
|
||||||
_factor = widget->devicePixelRatio();
|
_factor = widget->devicePixelRatio();
|
||||||
fillBackground(f);
|
fillBackground(f);
|
||||||
for (const auto &tile : _owner->_tiles) {
|
for (const auto &tile : _owner->_tiles) {
|
||||||
|
@ -372,7 +459,7 @@ void Viewport::RendererGL::paint(
|
||||||
freeTextures(f);
|
freeTextures(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Viewport::RendererGL::fillBackground(not_null<QOpenGLFunctions*> f) {
|
void Viewport::RendererGL::fillBackground(QOpenGLFunctions &f) {
|
||||||
const auto radius = st::roundRadiusLarge;
|
const auto radius = st::roundRadiusLarge;
|
||||||
const auto radiuses = QMargins{ radius, radius, radius, radius };
|
const auto radiuses = QMargins{ radius, radius, radius, radius };
|
||||||
auto bg = QRegion(QRect(QPoint(), _viewport));
|
auto bg = QRegion(QRect(QPoint(), _viewport));
|
||||||
|
@ -398,7 +485,7 @@ void Viewport::RendererGL::fillBackground(not_null<QOpenGLFunctions*> f) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Viewport::RendererGL::paintTile(
|
void Viewport::RendererGL::paintTile(
|
||||||
not_null<QOpenGLFunctions*> f,
|
QOpenGLFunctions &f,
|
||||||
not_null<VideoTile*> tile) {
|
not_null<VideoTile*> tile) {
|
||||||
const auto track = tile->track();
|
const auto track = tile->track();
|
||||||
const auto data = track->frameWithInfo(false);
|
const auto data = track->frameWithInfo(false);
|
||||||
|
@ -406,11 +493,12 @@ void Viewport::RendererGL::paintTile(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto geometry = tileGeometry(tile);
|
const auto geometry = tile->geometry();
|
||||||
const auto x = geometry.x();
|
const auto flipped = flipRect(geometry);
|
||||||
const auto y = geometry.y();
|
const auto x = flipped.x();
|
||||||
const auto width = geometry.width();
|
const auto y = flipped.y();
|
||||||
const auto height = geometry.height();
|
const auto width = flipped.width();
|
||||||
|
const auto height = flipped.height();
|
||||||
const auto expand = !_owner->wide()/* && !tile->screencast()*/;
|
const auto expand = !_owner->wide()/* && !tile->screencast()*/;
|
||||||
const auto scaled = Media::View::FlipSizeByRotation(
|
const auto scaled = Media::View::FlipSizeByRotation(
|
||||||
data.yuv420->size,
|
data.yuv420->size,
|
||||||
|
@ -447,19 +535,64 @@ void Viewport::RendererGL::paintTile(
|
||||||
texCoord.begin() + (data.rotation / 90),
|
texCoord.begin() + (data.rotation / 90),
|
||||||
texCoord.end());
|
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[] = {
|
const GLfloat coords[] = {
|
||||||
x * _factor, y * _factor, texCoord[0][0], texCoord[0][1],
|
// Frame.
|
||||||
(x + width) * _factor, y * _factor, texCoord[1][0], texCoord[1][1],
|
x * _factor, y * _factor,
|
||||||
(x + width) * _factor, (y + height) * _factor, texCoord[2][0], texCoord[2][1],
|
texCoord[0][0], texCoord[0][1],
|
||||||
x * _factor, (y + height) * _factor, texCoord[3][0], texCoord[3][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);
|
tile->ensureTexturesCreated(f);
|
||||||
const auto &textures = tile->textures();
|
const auto &textures = tile->textures();
|
||||||
const auto upload = (textures.trackIndex != data.index);
|
const auto upload = (textures.trackIndex != data.index);
|
||||||
const auto uploadOne = [&](GLint internalformat, GLint format, QSize size, int stride, const void *data) {
|
const auto uploadOne = [&](
|
||||||
f->glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
|
GLint internalformat,
|
||||||
f->glTexImage2D(
|
GLint format,
|
||||||
|
QSize size,
|
||||||
|
int stride,
|
||||||
|
const void *data) {
|
||||||
|
f.glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
|
||||||
|
f.glTexImage2D(
|
||||||
GL_TEXTURE_2D,
|
GL_TEXTURE_2D,
|
||||||
0,
|
0,
|
||||||
internalformat,
|
internalformat,
|
||||||
|
@ -469,7 +602,7 @@ void Viewport::RendererGL::paintTile(
|
||||||
format,
|
format,
|
||||||
GL_UNSIGNED_BYTE,
|
GL_UNSIGNED_BYTE,
|
||||||
data);
|
data);
|
||||||
f->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
f.glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||||
};
|
};
|
||||||
if (upload) {
|
if (upload) {
|
||||||
textures.textureIndex = 1 - textures.textureIndex;
|
textures.textureIndex = 1 - textures.textureIndex;
|
||||||
|
@ -477,10 +610,9 @@ void Viewport::RendererGL::paintTile(
|
||||||
const auto rgba = (data.format == Webrtc::FrameFormat::ARGB32);
|
const auto rgba = (data.format == Webrtc::FrameFormat::ARGB32);
|
||||||
if (rgba) {
|
if (rgba) {
|
||||||
ensureARGB32Program();
|
ensureARGB32Program();
|
||||||
const auto texture = textures.values[textures.textureIndex];
|
f.glUseProgram(_argb32Program->programId());
|
||||||
f->glUseProgram(_argb32Program->programId());
|
f.glActiveTexture(GL_TEXTURE0);
|
||||||
f->glActiveTexture(GL_TEXTURE0);
|
textures.values.bind(f, textures.textureIndex);
|
||||||
f->glBindTexture(GL_TEXTURE_2D, texture);
|
|
||||||
if (upload) {
|
if (upload) {
|
||||||
const auto &image = data.original;
|
const auto &image = data.original;
|
||||||
const auto stride = image.bytesPerLine() / 4;
|
const auto stride = image.bytesPerLine() / 4;
|
||||||
|
@ -491,22 +623,19 @@ void Viewport::RendererGL::paintTile(
|
||||||
} else {
|
} else {
|
||||||
const auto yuv = data.yuv420;
|
const auto yuv = data.yuv420;
|
||||||
const auto otherSize = yuv->chromaSize;
|
const auto otherSize = yuv->chromaSize;
|
||||||
const auto textureY = textures.values[textures.textureIndex * 3 + 0];
|
f.glUseProgram(_yuv420Program->programId());
|
||||||
const auto textureU = textures.values[textures.textureIndex * 3 + 1];
|
f.glActiveTexture(GL_TEXTURE0);
|
||||||
const auto textureV = textures.values[textures.textureIndex * 3 + 2];
|
textures.values.bind(f, textures.textureIndex * 3 + 0);
|
||||||
f->glUseProgram(_yuv420Program->programId());
|
|
||||||
f->glActiveTexture(GL_TEXTURE0);
|
|
||||||
f->glBindTexture(GL_TEXTURE_2D, textureY);
|
|
||||||
if (upload) {
|
if (upload) {
|
||||||
uploadOne(GL_RED, GL_RED, yuv->size, yuv->y.stride, yuv->y.data);
|
uploadOne(GL_RED, GL_RED, yuv->size, yuv->y.stride, yuv->y.data);
|
||||||
}
|
}
|
||||||
f->glActiveTexture(GL_TEXTURE1);
|
f.glActiveTexture(GL_TEXTURE1);
|
||||||
f->glBindTexture(GL_TEXTURE_2D, textureU);
|
textures.values.bind(f, textures.textureIndex * 3 + 1);
|
||||||
if (upload) {
|
if (upload) {
|
||||||
uploadOne(GL_RED, GL_RED, otherSize, yuv->u.stride, yuv->u.data);
|
uploadOne(GL_RED, GL_RED, otherSize, yuv->u.stride, yuv->u.data);
|
||||||
}
|
}
|
||||||
f->glActiveTexture(GL_TEXTURE2);
|
f.glActiveTexture(GL_TEXTURE2);
|
||||||
f->glBindTexture(GL_TEXTURE_2D, textureV);
|
textures.values.bind(f, textures.textureIndex * 3 + 2);
|
||||||
if (upload) {
|
if (upload) {
|
||||||
uploadOne(GL_RED, GL_RED, otherSize, yuv->v.stride, yuv->v.data);
|
uploadOne(GL_RED, GL_RED, otherSize, yuv->v.stride, yuv->v.data);
|
||||||
}
|
}
|
||||||
|
@ -517,45 +646,61 @@ void Viewport::RendererGL::paintTile(
|
||||||
tile->track()->markFrameShown();
|
tile->track()->markFrameShown();
|
||||||
|
|
||||||
_frameBuffer->bind();
|
_frameBuffer->bind();
|
||||||
_frameBuffer->allocate(coords, sizeof(coords));
|
_frameBuffer->write(0, coords, sizeof(coords));
|
||||||
|
|
||||||
const auto program = rgba ? &*_argb32Program : &*_yuv420Program;
|
const auto program = rgba ? &*_argb32Program : &*_yuv420Program;
|
||||||
|
const auto uniformViewport = QSizeF(_viewport * _factor);
|
||||||
|
|
||||||
program->setUniformValue("viewport", QSizeF(_viewport * _factor));
|
program->setUniformValue("viewport", uniformViewport);
|
||||||
program->setUniformValue(
|
program->setUniformValue(
|
||||||
"frameBg",
|
"frameBg",
|
||||||
Uniform(st::groupCallMembersBg->c));
|
Uniform(st::groupCallMembersBg->c));
|
||||||
program->setUniformValue("roundRadius", radius * _factor);
|
program->setUniformValue("roundRadius", radius * _factor);
|
||||||
program->setUniformValue("roundRect", Uniform(geometry, _factor));
|
program->setUniformValue("roundRect", Uniform(flipped, _factor));
|
||||||
program->setUniformValue("roundBg", Uniform(st::groupCallBg->c));
|
program->setUniformValue("roundBg", Uniform(st::groupCallBg->c));
|
||||||
|
|
||||||
GLint position = program->attributeLocation("position");
|
const auto &st = st::groupCallLargeVideo;
|
||||||
f->glVertexAttribPointer(
|
const auto shown = _owner->_controlsShownRatio;
|
||||||
position,
|
const auto shadowHeight = st.shadowHeight * _factor;
|
||||||
2,
|
const auto shadowAlpha = kShadowMaxAlpha / 255.f;
|
||||||
GL_FLOAT,
|
program->setUniformValue(
|
||||||
GL_FALSE,
|
"shadow",
|
||||||
4 * sizeof(GLfloat),
|
QVector3D(shadowHeight, shown, shadowAlpha));
|
||||||
nullptr);
|
|
||||||
f->glEnableVertexAttribArray(position);
|
|
||||||
|
|
||||||
GLint texcoord = program->attributeLocation("texcoord");
|
FillTexturedRectangle(f, program);
|
||||||
f->glVertexAttribPointer(
|
|
||||||
texcoord,
|
|
||||||
2,
|
|
||||||
GL_FLOAT,
|
|
||||||
GL_FALSE,
|
|
||||||
4 * sizeof(GLfloat),
|
|
||||||
reinterpret_cast<const void*>(2 * sizeof(GLfloat)));
|
|
||||||
f->glEnableVertexAttribArray(texcoord);
|
|
||||||
|
|
||||||
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 {
|
QRect Viewport::RendererGL::tileGeometry(not_null<VideoTile*> tile) const {
|
||||||
const auto raster = tile->geometry();
|
const auto raster = tile->geometry();
|
||||||
|
return flipRect(tile->geometry());
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect Viewport::RendererGL::flipRect(const QRect &raster) const {
|
||||||
return {
|
return {
|
||||||
raster.x(),
|
raster.x(),
|
||||||
_viewport.height() - raster.y() - raster.height(),
|
_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) {
|
void Viewport::RendererGL::freeTextures(QOpenGLFunctions &f) {
|
||||||
for (const auto &textures : base::take(_texturesToFree)) {
|
for (auto &textures : base::take(_texturesToFree)) {
|
||||||
f->glDeleteTextures(textures.values.size(), textures.values.data());
|
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
|
} // namespace Calls::Group
|
||||||
|
|
|
@ -8,7 +8,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "calls/group/calls_group_viewport.h"
|
#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_surface.h"
|
||||||
|
#include "ui/gl/gl_image.h"
|
||||||
|
|
||||||
#include <QtGui/QOpenGLBuffer>
|
#include <QtGui/QOpenGLBuffer>
|
||||||
#include <QtGui/QOpenGLShaderProgram>
|
#include <QtGui/QOpenGLShaderProgram>
|
||||||
|
@ -23,30 +26,33 @@ public:
|
||||||
|
|
||||||
void init(
|
void init(
|
||||||
not_null<QOpenGLWidget*> widget,
|
not_null<QOpenGLWidget*> widget,
|
||||||
not_null<QOpenGLFunctions*> f) override;
|
QOpenGLFunctions &f) override;
|
||||||
|
|
||||||
void deinit(
|
void deinit(
|
||||||
not_null<QOpenGLWidget*> widget,
|
not_null<QOpenGLWidget*> widget,
|
||||||
not_null<QOpenGLFunctions*> f) override;
|
QOpenGLFunctions &f) override;
|
||||||
|
|
||||||
void resize(
|
void resize(
|
||||||
not_null<QOpenGLWidget*> widget,
|
not_null<QOpenGLWidget*> widget,
|
||||||
not_null<QOpenGLFunctions*> f,
|
QOpenGLFunctions &f,
|
||||||
int w,
|
int w,
|
||||||
int h) override;
|
int h) override;
|
||||||
|
|
||||||
void paint(
|
void paint(
|
||||||
not_null<QOpenGLWidget*> widget,
|
not_null<QOpenGLWidget*> widget,
|
||||||
not_null<QOpenGLFunctions*> f) override;
|
QOpenGLFunctions &f) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void fillBackground(not_null<QOpenGLFunctions*> f);
|
void fillBackground(QOpenGLFunctions &f);
|
||||||
void paintTile(
|
void paintTile(
|
||||||
not_null<QOpenGLFunctions*> f,
|
QOpenGLFunctions &f,
|
||||||
not_null<VideoTile*> tile);
|
not_null<VideoTile*> tile);
|
||||||
void freeTextures(not_null<QOpenGLFunctions*> f);
|
void freeTextures(QOpenGLFunctions &f);
|
||||||
[[nodiscard]] QRect tileGeometry(not_null<VideoTile*> tile) const;
|
[[nodiscard]] QRect tileGeometry(not_null<VideoTile*> tile) const;
|
||||||
|
[[nodiscard]] QRect flipRect(const QRect &raster) const;
|
||||||
|
|
||||||
void ensureARGB32Program();
|
void ensureARGB32Program();
|
||||||
|
void ensurePinImage();
|
||||||
|
|
||||||
const not_null<Viewport*> _owner;
|
const not_null<Viewport*> _owner;
|
||||||
|
|
||||||
|
@ -56,11 +62,20 @@ private:
|
||||||
std::optional<QOpenGLBuffer> _bgBuffer;
|
std::optional<QOpenGLBuffer> _bgBuffer;
|
||||||
std::optional<QOpenGLShaderProgram> _argb32Program;
|
std::optional<QOpenGLShaderProgram> _argb32Program;
|
||||||
std::optional<QOpenGLShaderProgram> _yuv420Program;
|
std::optional<QOpenGLShaderProgram> _yuv420Program;
|
||||||
|
std::optional<QOpenGLShaderProgram> _imageProgram;
|
||||||
std::optional<QOpenGLShaderProgram> _bgProgram;
|
std::optional<QOpenGLShaderProgram> _bgProgram;
|
||||||
QOpenGLShader *_frameVertexShader = nullptr;
|
QOpenGLShader *_frameVertexShader = nullptr;
|
||||||
|
|
||||||
|
Ui::GL::Image _pinButtons;
|
||||||
|
QRect _pinOn;
|
||||||
|
QRect _pinOff;
|
||||||
|
|
||||||
std::vector<GLfloat> _bgTriangles;
|
std::vector<GLfloat> _bgTriangles;
|
||||||
std::vector<Textures> _texturesToFree;
|
std::vector<Textures> _texturesToFree;
|
||||||
|
Ui::CrossLineAnimation _pinIcon;
|
||||||
|
Ui::RoundRect _pinBackground;
|
||||||
|
|
||||||
|
rpl::lifetime _lifetime;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -17,22 +17,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "styles/palette.h"
|
#include "styles/palette.h"
|
||||||
|
|
||||||
namespace Calls::Group {
|
namespace Calls::Group {
|
||||||
namespace {
|
|
||||||
|
|
||||||
constexpr auto kShadowMaxAlpha = 80;
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
Viewport::Renderer::Renderer(not_null<Viewport*> owner)
|
Viewport::Renderer::Renderer(not_null<Viewport*> owner)
|
||||||
: _owner(owner)
|
: _owner(owner)
|
||||||
, _pinIcon(st::groupCallLargeVideoPin)
|
, _pinIcon(st::groupCallLargeVideo.pin)
|
||||||
, _pinBackground(
|
, _pinBackground(
|
||||||
(st::groupCallLargeVideoWide.pinPadding.top()
|
(st::groupCallLargeVideo.pinPadding.top()
|
||||||
+ st::groupCallLargeVideoPin.icon.height()
|
+ st::groupCallLargeVideo.pin.icon.height()
|
||||||
+ st::groupCallLargeVideoWide.pinPadding.bottom()) / 2,
|
+ st::groupCallLargeVideo.pinPadding.bottom()) / 2,
|
||||||
st::radialBg)
|
st::radialBg) {
|
||||||
, _pinTextOn(st::semiboldTextStyle, tr::lng_pinned_unpin(tr::now))
|
|
||||||
, _pinTextOff(st::semiboldTextStyle, tr::lng_pinned_pin(tr::now)) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Viewport::Renderer::paintFallback(
|
void Viewport::Renderer::paintFallback(
|
||||||
|
@ -132,44 +125,29 @@ void Viewport::Renderer::paintTileControls(
|
||||||
// Pin.
|
// Pin.
|
||||||
const auto wide = _owner->wide();
|
const auto wide = _owner->wide();
|
||||||
if (wide) {
|
if (wide) {
|
||||||
const auto inner = tile->pinInner().translated(x, y);
|
const auto inner = tile->pinInner();
|
||||||
const auto pinned = tile->pinned();
|
VideoTile::PaintPinButton(
|
||||||
const auto &icon = st::groupCallLargeVideoPin.icon;
|
|
||||||
const auto &st = st::groupCallLargeVideoWide;
|
|
||||||
_pinBackground.paint(p, inner);
|
|
||||||
_pinIcon.paint(
|
|
||||||
p,
|
p,
|
||||||
inner.marginsRemoved(st.pinPadding).topLeft(),
|
tile->pinned(),
|
||||||
pinned ? 1. : 0.);
|
x + inner.x(),
|
||||||
p.setPen(st::groupCallVideoTextFg);
|
y + inner.y(),
|
||||||
const auto &text = (pinned ? _pinTextOn : _pinTextOff);
|
_owner->widget()->width(),
|
||||||
text.drawLeft(
|
&_pinBackground,
|
||||||
p,
|
&_pinIcon);
|
||||||
(inner.x()
|
|
||||||
+ st.pinPadding.left()
|
|
||||||
+ icon.width()
|
|
||||||
+ st.pinTextPosition.x()),
|
|
||||||
(inner.y()
|
|
||||||
+ st.pinPadding.top()
|
|
||||||
+ st.pinTextPosition.y()),
|
|
||||||
text.maxWidth(),
|
|
||||||
_owner->widget()->width());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &st = wide
|
|
||||||
? st::groupCallLargeVideoWide
|
|
||||||
: st::groupCallLargeVideoNarrow;
|
|
||||||
const auto fullShift = st.namePosition.y() + st::normalFont->height;
|
|
||||||
const auto shown = _owner->_controlsShownRatio;
|
const auto shown = _owner->_controlsShownRatio;
|
||||||
if (shown == 0.) {
|
if (shown == 0.) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto &st = st::groupCallLargeVideo;
|
||||||
|
const auto fullShift = st.namePosition.y() + st::normalFont->height;
|
||||||
const auto shift = anim::interpolate(fullShift, 0, shown);
|
const auto shift = anim::interpolate(fullShift, 0, shown);
|
||||||
auto &shadow = wide ? _shadowWide : _shadowNarrow;
|
|
||||||
// Shadow.
|
// Shadow.
|
||||||
if (shadow.isNull()) {
|
if (_shadow.isNull()) {
|
||||||
shadow = GenerateShadow(st.shadowHeight, 0, kShadowMaxAlpha);
|
_shadow = GenerateShadow(st.shadowHeight, 0, kShadowMaxAlpha);
|
||||||
}
|
}
|
||||||
const auto shadowRect = QRect(
|
const auto shadowRect = QRect(
|
||||||
x,
|
x,
|
||||||
|
@ -183,11 +161,11 @@ void Viewport::Renderer::paintTileControls(
|
||||||
const auto factor = style::DevicePixelRatio();
|
const auto factor = style::DevicePixelRatio();
|
||||||
p.drawImage(
|
p.drawImage(
|
||||||
shadowFill,
|
shadowFill,
|
||||||
shadow,
|
_shadow,
|
||||||
QRect(
|
QRect(
|
||||||
0,
|
0,
|
||||||
(shadowFill.y() - shadowRect.y()) * factor,
|
(shadowFill.y() - shadowRect.y()) * factor,
|
||||||
shadow.width(),
|
_shadow.width(),
|
||||||
shadowFill.height() * factor));
|
shadowFill.height() * factor));
|
||||||
const auto row = tile->row();
|
const auto row = tile->row();
|
||||||
row->lazyInitialize(st::groupCallMembersListItem);
|
row->lazyInitialize(st::groupCallMembersListItem);
|
||||||
|
|
|
@ -41,12 +41,9 @@ private:
|
||||||
|
|
||||||
const not_null<Viewport*> _owner;
|
const not_null<Viewport*> _owner;
|
||||||
|
|
||||||
QImage _shadowWide;
|
QImage _shadow;
|
||||||
QImage _shadowNarrow;
|
|
||||||
Ui::CrossLineAnimation _pinIcon;
|
Ui::CrossLineAnimation _pinIcon;
|
||||||
Ui::RoundRect _pinBackground;
|
Ui::RoundRect _pinBackground;
|
||||||
Ui::Text::String _pinTextOn;
|
|
||||||
Ui::Text::String _pinTextOff;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "webrtc/webrtc_video_track.h"
|
#include "webrtc/webrtc_video_track.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
|
#include "ui/round_rect.h"
|
||||||
|
#include "ui/effects/cross_line.h"
|
||||||
#include "styles/style_calls.h"
|
#include "styles/style_calls.h"
|
||||||
|
|
||||||
#include <QtGui/QOpenGLFunctions>
|
#include <QtGui/QOpenGLFunctions>
|
||||||
|
@ -43,7 +45,7 @@ QRect Viewport::VideoTile::pinOuter() const {
|
||||||
|
|
||||||
int Viewport::VideoTile::pinSlide() const {
|
int Viewport::VideoTile::pinSlide() const {
|
||||||
return anim::interpolate(
|
return anim::interpolate(
|
||||||
st::groupCallLargeVideoWide.pinPosition.y() + _pinInner.height(),
|
st::groupCallLargeVideo.pinPosition.y() + _pinInner.height(),
|
||||||
0,
|
0,
|
||||||
_pinShownAnimation.value(_pinShown ? 1. : 0.));
|
_pinShownAnimation.value(_pinShown ? 1. : 0.));
|
||||||
}
|
}
|
||||||
|
@ -73,12 +75,12 @@ bool Viewport::VideoTile::updateRequestedQuality(VideoQuality quality) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Viewport::VideoTile::updatePinnedGeometry() {
|
QSize Viewport::VideoTile::PinInnerSize(bool pinned) {
|
||||||
const auto &st = st::groupCallLargeVideoWide;
|
const auto &st = st::groupCallLargeVideo;
|
||||||
const auto &icon = st::groupCallLargeVideoPin.icon;
|
const auto &icon = st::groupCallLargeVideo.pin.icon;
|
||||||
const auto innerWidth = icon.width()
|
const auto innerWidth = icon.width()
|
||||||
+ st.pinTextPosition.x()
|
+ st.pinTextPosition.x()
|
||||||
+ st::semiboldFont->width(_pinned
|
+ st::semiboldFont->width(pinned
|
||||||
? tr::lng_pinned_unpin(tr::now)
|
? tr::lng_pinned_unpin(tr::now)
|
||||||
: tr::lng_pinned_pin(tr::now));
|
: tr::lng_pinned_pin(tr::now));
|
||||||
const auto innerHeight = icon.height();
|
const auto innerHeight = icon.height();
|
||||||
|
@ -88,13 +90,49 @@ void Viewport::VideoTile::updatePinnedGeometry() {
|
||||||
const auto buttonHeight = st.pinPadding.top()
|
const auto buttonHeight = st.pinPadding.top()
|
||||||
+ innerHeight
|
+ innerHeight
|
||||||
+ st.pinPadding.bottom();
|
+ st.pinPadding.bottom();
|
||||||
const auto fullWidth = st.pinPosition.x() * 2 + buttonWidth;
|
return { buttonWidth, buttonHeight };
|
||||||
const auto fullHeight = st.pinPosition.y() * 2 + buttonHeight;
|
}
|
||||||
_pinInner = QRect(
|
|
||||||
_geometry.width() - st.pinPosition.x() - buttonWidth,
|
void Viewport::VideoTile::PaintPinButton(
|
||||||
st.pinPosition.y(),
|
Painter &p,
|
||||||
buttonWidth,
|
bool pinned,
|
||||||
buttonHeight);
|
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(
|
_pinOuter = QRect(
|
||||||
_geometry.width() - fullWidth,
|
_geometry.width() - fullWidth,
|
||||||
0,
|
0,
|
||||||
|
@ -130,19 +168,8 @@ void Viewport::VideoTile::setup(rpl::producer<bool> pinned) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Viewport::VideoTile::ensureTexturesCreated(
|
void Viewport::VideoTile::ensureTexturesCreated(
|
||||||
not_null<QOpenGLFunctions*> f) {
|
QOpenGLFunctions &f) {
|
||||||
if (_textures) {
|
_textures.values.ensureCreated(f);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Viewport::Textures &Viewport::VideoTile::textures() const {
|
const Viewport::Textures &Viewport::VideoTile::textures() const {
|
||||||
|
|
|
@ -10,20 +10,25 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "calls/group/calls_group_viewport.h"
|
#include "calls/group/calls_group_viewport.h"
|
||||||
#include "calls/group/calls_group_call.h"
|
#include "calls/group/calls_group_call.h"
|
||||||
#include "ui/effects/animations.h"
|
#include "ui/effects/animations.h"
|
||||||
#include "ui/effects/cross_line.h"
|
#include "ui/gl/gl_image.h"
|
||||||
#include "ui/round_rect.h"
|
|
||||||
|
|
||||||
|
class Painter;
|
||||||
class QOpenGLFunctions;
|
class QOpenGLFunctions;
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class CrossLineAnimation;
|
||||||
|
class RoundRect;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Calls::Group {
|
namespace Calls::Group {
|
||||||
|
|
||||||
struct Viewport::Textures {
|
struct Viewport::Textures {
|
||||||
std::array<GLuint, 6> values = { { 0 } };
|
Ui::GL::Textures<6> values;
|
||||||
mutable int textureIndex = 0;
|
mutable int textureIndex = 0;
|
||||||
mutable int trackIndex = -1;
|
mutable int trackIndex = -1;
|
||||||
|
|
||||||
explicit operator bool() const {
|
explicit operator bool() const {
|
||||||
return (values[0] != 0);
|
return values.created();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -64,7 +69,7 @@ public:
|
||||||
void togglePinShown(bool shown);
|
void togglePinShown(bool shown);
|
||||||
bool updateRequestedQuality(VideoQuality quality);
|
bool updateRequestedQuality(VideoQuality quality);
|
||||||
|
|
||||||
void ensureTexturesCreated(not_null<QOpenGLFunctions*> f);
|
void ensureTexturesCreated(QOpenGLFunctions &f);
|
||||||
[[nodiscard]] const Textures &textures() const;
|
[[nodiscard]] const Textures &textures() const;
|
||||||
[[nodiscard]] Textures takeTextures();
|
[[nodiscard]] Textures takeTextures();
|
||||||
|
|
||||||
|
@ -72,6 +77,16 @@ public:
|
||||||
return _lifetime;
|
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:
|
private:
|
||||||
void setup(rpl::producer<bool> pinned);
|
void setup(rpl::producer<bool> pinned);
|
||||||
[[nodiscard]] int pinSlide() const;
|
[[nodiscard]] int pinSlide() const;
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit c9466116894715a2343f43a0b6aa22602d89262e
|
Subproject commit 2a26d4a91aca5f9850e5a3d7d5cd58ed0b74639a
|
Loading…
Add table
Reference in a new issue