Add green outline to speaking video tiles.

This commit is contained in:
John Preston 2021-05-28 21:05:28 +04:00
parent b906b2f625
commit ddf81c949b
5 changed files with 74 additions and 42 deletions

View file

@ -1212,7 +1212,7 @@ groupCallNarrowIconSkip: 15px;
// fg: groupCallVideoTextFg; // fg: groupCallVideoTextFg;
// icon: icon {{ "calls/voice_mute_mini", groupCallVideoTextFg }}; // icon: icon {{ "calls/voice_mute_mini", groupCallVideoTextFg }};
//} //}
groupCallOutline: 2px;
groupCallLargeVideoCrossLine: CrossLineAnimation(groupCallMemberColoredCrossLine) { groupCallLargeVideoCrossLine: CrossLineAnimation(groupCallMemberColoredCrossLine) {
fg: groupCallVideoTextFg; fg: groupCallVideoTextFg;
icon: icon {{ "calls/video_over_mute", groupCallVideoTextFg }}; icon: icon {{ "calls/video_over_mute", groupCallVideoTextFg }};

View file

@ -241,11 +241,13 @@ void Viewport::RendererGL::paint(
not_null<QOpenGLWidget*> widget, not_null<QOpenGLWidget*> widget,
QOpenGLFunctions &f) { QOpenGLFunctions &f) {
_factor = widget->devicePixelRatio(); _factor = widget->devicePixelRatio();
validateNames(); validateDatas();
fillBackground(f); fillBackground(f);
auto index = 0; auto index = 0;
for (const auto &tile : _owner->_tiles) { for (const auto &tile : _owner->_tiles) {
paintTile(f, tile.get(), _nameData[_nameDataIndices[index++]]); auto &data = _tileData[_tileDataIndices[index++]];
validateOutlineAnimation(tile.get(), data);
paintTile(f, tile.get(), data);
} }
freeTextures(f); freeTextures(f);
} }
@ -278,7 +280,7 @@ void Viewport::RendererGL::fillBackground(QOpenGLFunctions &f) {
void Viewport::RendererGL::paintTile( void Viewport::RendererGL::paintTile(
QOpenGLFunctions &f, QOpenGLFunctions &f,
not_null<VideoTile*> tile, not_null<VideoTile*> tile,
const NameData &nameData) { const TileData &tileData) {
const auto track = tile->track(); const auto track = tile->track();
const auto data = track->frameWithInfo(false); const auto data = track->frameWithInfo(false);
if (data.format == Webrtc::FrameFormat::None) { if (data.format == Webrtc::FrameFormat::None) {
@ -369,8 +371,8 @@ void Viewport::RendererGL::paintTile(
- st::semiboldFont->height - st::semiboldFont->height
+ nameShift)); + nameShift));
const auto name = _names.texturedRect( const auto name = _names.texturedRect(
QRect(namePosition, nameData.rect.size() / cIntRetinaFactor()), QRect(namePosition, tileData.nameRect.size() / cIntRetinaFactor()),
nameData.rect, tileData.nameRect,
geometry); geometry);
const auto nameRect = transformRect(name.geometry); const auto nameRect = transformRect(name.geometry);
@ -499,9 +501,17 @@ void Viewport::RendererGL::paintTile(
program->setUniformValue( program->setUniformValue(
"frameBg", "frameBg",
Uniform(st::groupCallMembersBg->c)); Uniform(st::groupCallMembersBg->c));
program->setUniformValue("roundRadius", radius * _factor); const auto outline = tileData.outlined.value(tileData.outline ? 1. : 0.);
program->setUniformValue("radiusOutline", QVector2D(
radius * _factor,
(outline > 0) ? (st::groupCallOutline * _factor) : 0.f));
program->setUniformValue("roundRect", Uniform(rect)); program->setUniformValue("roundRect", Uniform(rect));
program->setUniformValue("roundBg", Uniform(st::groupCallBg->c)); program->setUniformValue("roundBg", Uniform(st::groupCallBg->c));
program->setUniformValue("outlineFg", QVector4D(
st::groupCallMemberActiveIcon->c.redF(),
st::groupCallMemberActiveIcon->c.greenF(),
st::groupCallMemberActiveIcon->c.blueF(),
st::groupCallMemberActiveIcon->c.alphaF() * outline));
const auto shadowHeight = st.shadowHeight * _factor; const auto shadowHeight = st.shadowHeight * _factor;
const auto shadowAlpha = kShadowMaxAlpha / 255.f; const auto shadowAlpha = kShadowMaxAlpha / 255.f;
@ -635,7 +645,7 @@ void Viewport::RendererGL::ensureButtonsImage() {
_buttons.setImage(std::move(image)); _buttons.setImage(std::move(image));
} }
void Viewport::RendererGL::validateNames() { void Viewport::RendererGL::validateDatas() {
const auto &tiles = _owner->_tiles; const auto &tiles = _owner->_tiles;
const auto &st = st::groupCallLargeVideo; const auto &st = st::groupCallLargeVideo;
const auto count = int(tiles.size()); const auto count = int(tiles.size());
@ -647,10 +657,10 @@ void Viewport::RendererGL::validateNames() {
}; };
auto requests = std::vector<Request>(); auto requests = std::vector<Request>();
auto available = _names.image().width(); auto available = _names.image().width();
for (auto &data : _nameData) { for (auto &data : _tileData) {
data.stale = true; data.stale = true;
} }
_nameDataIndices.resize(count); _tileDataIndices.resize(count);
const auto nameWidth = [&](int i) { const auto nameWidth = [&](int i) {
const auto row = tiles[i]->row(); const auto row = tiles[i]->row();
const auto hasWidth = tiles[i]->geometry().width() const auto hasWidth = tiles[i]->geometry().width()
@ -669,60 +679,60 @@ void Viewport::RendererGL::validateNames() {
available = width; available = width;
} }
const auto peer = tiles[i]->row()->peer(); const auto peer = tiles[i]->row()->peer();
const auto j = ranges::find(_nameData, peer, &NameData::peer); const auto j = ranges::find(_tileData, peer, &TileData::peer);
if (j != end(_nameData)) { if (j != end(_tileData)) {
j->stale = false; j->stale = false;
const auto index = (j - begin(_nameData)); const auto index = (j - begin(_tileData));
_nameDataIndices[i] = index; _tileDataIndices[i] = index;
if (peer->nameVersion != j->nameVersion if (peer->nameVersion != j->nameVersion
|| width != j->rect.width()) { || width != j->nameRect.width()) {
const auto nameTop = index * nameHeight; const auto nameTop = index * nameHeight;
j->rect = QRect(0, nameTop, width, nameHeight); j->nameRect = QRect(0, nameTop, width, nameHeight);
requests.push_back({ .index = i, .updating = true }); requests.push_back({ .index = i, .updating = true });
} }
} else { } else {
_nameDataIndices[i] = -1; _tileDataIndices[i] = -1;
requests.push_back({ .index = i, .updating = false }); requests.push_back({ .index = i, .updating = false });
} }
} }
if (requests.empty()) { if (requests.empty()) {
return; return;
} }
auto maybeStaleAfter = begin(_nameData); auto maybeStaleAfter = begin(_tileData);
auto maybeStaleEnd = end(_nameData); auto maybeStaleEnd = end(_tileData);
for (auto &request : requests) { for (auto &request : requests) {
const auto i = request.index; const auto i = request.index;
if (_nameDataIndices[i] >= 0) { if (_tileDataIndices[i] >= 0) {
continue; continue;
} }
const auto peer = tiles[i]->row()->peer(); const auto peer = tiles[i]->row()->peer();
auto index = int(_nameData.size()); auto index = int(_tileData.size());
maybeStaleAfter = ranges::find( maybeStaleAfter = ranges::find(
maybeStaleAfter, maybeStaleAfter,
maybeStaleEnd, maybeStaleEnd,
true, true,
&NameData::stale); &TileData::stale);
if (maybeStaleAfter != maybeStaleEnd) { if (maybeStaleAfter != maybeStaleEnd) {
index = (maybeStaleAfter - begin(_nameData)); index = (maybeStaleAfter - begin(_tileData));
maybeStaleAfter->peer = peer; maybeStaleAfter->peer = peer;
maybeStaleAfter->stale = false; maybeStaleAfter->stale = false;
request.updating = true; request.updating = true;
} else { } else {
// This invalidates maybeStale*, but they're already equal. // This invalidates maybeStale*, but they're already equal.
_nameData.push_back({ .peer = peer }); _tileData.push_back({ .peer = peer });
} }
_nameData[index].nameVersion = peer->nameVersion; _tileData[index].nameVersion = peer->nameVersion;
_nameData[index].rect = QRect( _tileData[index].nameRect = QRect(
0, 0,
index * nameHeight, index * nameHeight,
nameWidth(i), nameWidth(i),
nameHeight); nameHeight);
_nameDataIndices[i] = index; _tileDataIndices[i] = index;
} }
auto image = _names.takeImage(); auto image = _names.takeImage();
const auto imageSize = QSize( const auto imageSize = QSize(
available * factor, available * factor,
_nameData.size() * nameHeight); _tileData.size() * nameHeight);
const auto allocate = (image.size() != imageSize); const auto allocate = (image.size() != imageSize);
auto paintToImage = allocate auto paintToImage = allocate
? QImage(imageSize, QImage::Format_ARGB32_Premultiplied) ? QImage(imageSize, QImage::Format_ARGB32_Premultiplied)
@ -757,14 +767,14 @@ void Viewport::RendererGL::validateNames() {
p.setPen(st::groupCallVideoTextFg); p.setPen(st::groupCallVideoTextFg);
for (const auto &request : requests) { for (const auto &request : requests) {
const auto i = request.index; const auto i = request.index;
const auto index = _nameDataIndices[i]; const auto index = _tileDataIndices[i];
const auto &data = _nameData[_nameDataIndices[i]]; const auto &data = _tileData[_tileDataIndices[i]];
const auto row = tiles[i]->row(); const auto row = tiles[i]->row();
if (request.updating) { if (request.updating) {
p.setCompositionMode(QPainter::CompositionMode_Source); p.setCompositionMode(QPainter::CompositionMode_Source);
p.fillRect( p.fillRect(
0, 0,
data.rect.y() / factor, data.nameRect.y() / factor,
paintToImage.width() / factor, paintToImage.width() / factor,
nameHeight / factor, nameHeight / factor,
Qt::transparent); Qt::transparent);
@ -773,12 +783,27 @@ void Viewport::RendererGL::validateNames() {
row->name().drawLeftElided( row->name().drawLeftElided(
p, p,
0, 0,
data.rect.y() / factor, data.nameRect.y() / factor,
data.rect.width() / factor, data.nameRect.width() / factor,
paintToImage.width() / factor); paintToImage.width() / factor);
} }
} }
_names.setImage(std::move(paintToImage)); _names.setImage(std::move(paintToImage));
} }
void Viewport::RendererGL::validateOutlineAnimation(
not_null<VideoTile*> tile,
TileData &data) {
const auto outline = tile->row()->speaking();
if (data.outline == outline) {
return;
}
data.outline = outline;
data.outlined.start(
[=] { _owner->widget()->update(); },
outline ? 0. : 1.,
outline ? 1. : 0.,
st::fadeWrapDuration);
}
} // namespace Calls::Group } // namespace Calls::Group

View file

@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "calls/group/calls_group_viewport.h" #include "calls/group/calls_group_viewport.h"
#include "ui/round_rect.h" #include "ui/round_rect.h"
#include "ui/effects/animations.h"
#include "ui/effects/cross_line.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 "ui/gl/gl_image.h"
@ -43,24 +44,30 @@ public:
QOpenGLFunctions &f) override; QOpenGLFunctions &f) override;
private: private:
struct NameData { struct TileData {
not_null<PeerData*> peer; not_null<PeerData*> peer;
Ui::Animations::Simple outlined;
QRect nameRect;
int nameVersion = 0; int nameVersion = 0;
QRect rect;
bool stale = false; bool stale = false;
bool outline = false;
}; };
void fillBackground(QOpenGLFunctions &f); void fillBackground(QOpenGLFunctions &f);
void paintTile( void paintTile(
QOpenGLFunctions &f, QOpenGLFunctions &f,
not_null<VideoTile*> tile, not_null<VideoTile*> tile,
const NameData &nameData); const TileData &nameData);
void freeTextures(QOpenGLFunctions &f); void freeTextures(QOpenGLFunctions &f);
[[nodiscard]] Ui::GL::Rect transformRect(const QRect &raster) const; [[nodiscard]] Ui::GL::Rect transformRect(const QRect &raster) const;
[[nodiscard]] Ui::GL::Rect transformRect(const Ui::GL::Rect &raster) const; [[nodiscard]] Ui::GL::Rect transformRect(
const Ui::GL::Rect &raster) const;
void ensureARGB32Program(); void ensureARGB32Program();
void ensureButtonsImage(); void ensureButtonsImage();
void validateNames(); void validateDatas();
void validateOutlineAnimation(
not_null<VideoTile*> tile,
TileData &data);
const not_null<Viewport*> _owner; const not_null<Viewport*> _owner;
@ -81,8 +88,8 @@ private:
QRect _muteOff; QRect _muteOff;
Ui::GL::Image _names; Ui::GL::Image _names;
std::vector<NameData> _nameData; std::vector<TileData> _tileData;
std::vector<int> _nameDataIndices; std::vector<int> _tileDataIndices;
std::vector<GLfloat> _bgTriangles; std::vector<GLfloat> _bgTriangles;
std::vector<Textures> _texturesToFree; std::vector<Textures> _texturesToFree;

View file

@ -105,7 +105,7 @@ public:
std::optional<Participant> now; std::optional<Participant> now;
}; };
static constexpr auto kSoundStatusKeptFor = crl::time(350); static constexpr auto kSoundStatusKeptFor = crl::time(1350);
[[nodiscard]] auto participants() const [[nodiscard]] auto participants() const
-> const std::vector<Participant> &; -> const std::vector<Participant> &;

@ -1 +1 @@
Subproject commit f475fe28e47af4408bc96ba63e63f599c02538ca Subproject commit 5389de6b96f241d992eb93e515e4aefaaf4d86f9