mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-19 15:47:11 +02:00
Render media viewer icons in RendererGL.
This commit is contained in:
parent
38a0eb3b52
commit
2801bd99b8
7 changed files with 190 additions and 23 deletions
|
@ -10,20 +10,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/gl/gl_shader.h"
|
||||
#include "media/streaming/media_streaming_common.h"
|
||||
#include "base/platform/base_platform_info.h"
|
||||
#include "styles/style_media_view.h"
|
||||
|
||||
namespace Media::View {
|
||||
namespace {
|
||||
|
||||
using namespace Ui::GL;
|
||||
|
||||
constexpr auto kQuads = 8;
|
||||
constexpr auto kQuadVertices = kQuads * 4;
|
||||
constexpr auto kQuadValues = kQuadVertices * 4;
|
||||
constexpr auto kControls = 6;
|
||||
constexpr auto kControlValues = 2 * 4 + 4 * 4;
|
||||
constexpr auto kControlsValues = kControls * kControlValues;
|
||||
constexpr auto kValues = kQuadValues + kControlsValues;
|
||||
|
||||
constexpr auto kRadialLoadingOffset = 4;
|
||||
constexpr auto kThemePreviewOffset = kRadialLoadingOffset + 4;
|
||||
constexpr auto kDocumentBubbleOffset = kThemePreviewOffset + 4;
|
||||
|
@ -31,6 +24,8 @@ constexpr auto kSaveMsgOffset = kDocumentBubbleOffset + 4;
|
|||
constexpr auto kFooterOffset = kSaveMsgOffset + 4;
|
||||
constexpr auto kCaptionOffset = kFooterOffset + 4;
|
||||
constexpr auto kGroupThumbsOffset = kCaptionOffset + 4;
|
||||
constexpr auto kControlsOffset = kGroupThumbsOffset + 4;
|
||||
constexpr auto kControlValues = 2 * 4 + 4 * 4;
|
||||
|
||||
[[nodiscard]] ShaderPart FragmentPlaceOnTransparentBackground() {
|
||||
return {
|
||||
|
@ -61,13 +56,19 @@ OverlayWidget::RendererGL::RendererGL(not_null<OverlayWidget*> owner)
|
|||
_saveMsgImage.invalidate();
|
||||
_footerImage.invalidate();
|
||||
_captionImage.invalidate();
|
||||
invalidateControls();
|
||||
}, _lifetime);
|
||||
}
|
||||
|
||||
void OverlayWidget::RendererGL::init(
|
||||
not_null<QOpenGLWidget*> widget,
|
||||
QOpenGLFunctions &f) {
|
||||
_factor = widget->devicePixelRatio();
|
||||
constexpr auto kQuads = 8;
|
||||
constexpr auto kQuadVertices = kQuads * 4;
|
||||
constexpr auto kQuadValues = kQuadVertices * 4;
|
||||
constexpr auto kControlsValues = kControlsCount * kControlValues;
|
||||
constexpr auto kValues = kQuadValues + kControlsValues;
|
||||
|
||||
_contentBuffer.emplace();
|
||||
_contentBuffer->setUsagePattern(QOpenGLBuffer::DynamicDraw);
|
||||
_contentBuffer->create();
|
||||
|
@ -104,6 +105,21 @@ void OverlayWidget::RendererGL::init(
|
|||
FragmentSampleYUV420Texture(),
|
||||
}));
|
||||
|
||||
_fillProgram.emplace();
|
||||
LinkProgram(
|
||||
&*_fillProgram,
|
||||
VertexShader({ VertexViewportTransform() }),
|
||||
FragmentShader({ FragmentStaticColor() }));
|
||||
|
||||
_controlsProgram.emplace();
|
||||
LinkProgram(
|
||||
&*_controlsProgram,
|
||||
_texturedVertexShader,
|
||||
FragmentShader({
|
||||
FragmentSampleARGB32Texture(),
|
||||
FragmentGlobalOpacity(),
|
||||
}));
|
||||
|
||||
_background.init(f);
|
||||
}
|
||||
|
||||
|
@ -116,6 +132,8 @@ void OverlayWidget::RendererGL::deinit(
|
|||
_texturedVertexShader = nullptr;
|
||||
_withTransparencyProgram = std::nullopt;
|
||||
_yuv420Program = std::nullopt;
|
||||
_fillProgram = std::nullopt;
|
||||
_controlsProgram = std::nullopt;
|
||||
_contentBuffer = std::nullopt;
|
||||
}
|
||||
|
||||
|
@ -124,14 +142,20 @@ void OverlayWidget::RendererGL::resize(
|
|||
QOpenGLFunctions &f,
|
||||
int w,
|
||||
int h) {
|
||||
_factor = widget->devicePixelRatio();
|
||||
_viewport = QSize(w, h);
|
||||
const auto factor = widget->devicePixelRatio();
|
||||
if (_factor != factor) {
|
||||
_factor = factor;
|
||||
_controlsImage.invalidate();
|
||||
}
|
||||
_viewport = QSize{ w, h };
|
||||
_uniformViewport = QVector2D(
|
||||
_viewport.width() * _factor,
|
||||
_viewport.height() * _factor);
|
||||
setDefaultViewport(f);
|
||||
}
|
||||
|
||||
void OverlayWidget::RendererGL::setDefaultViewport(QOpenGLFunctions &f) {
|
||||
const auto size = _viewport * _factor;
|
||||
f.glViewport(0, 0, size.width(), size.height());
|
||||
f.glViewport(0, 0, _uniformViewport.x(), _uniformViewport.y());
|
||||
}
|
||||
|
||||
void OverlayWidget::RendererGL::paint(
|
||||
|
@ -171,6 +195,7 @@ void OverlayWidget::RendererGL::paintBackground() {
|
|||
_viewport,
|
||||
_factor,
|
||||
bg);
|
||||
_contentBuffer->bind();
|
||||
}
|
||||
|
||||
void OverlayWidget::RendererGL::paintTransformedVideoFrame(
|
||||
|
@ -269,6 +294,7 @@ void OverlayWidget::RendererGL::paintTransformedStaticContent(
|
|||
const auto cacheKey = image.cacheKey();
|
||||
const auto upload = (_cacheKey != cacheKey);
|
||||
if (upload) {
|
||||
_cacheKey = cacheKey;
|
||||
const auto stride = image.bytesPerLine() / 4;
|
||||
const auto data = image.constBits();
|
||||
uploadTexture(
|
||||
|
@ -316,10 +342,9 @@ void OverlayWidget::RendererGL::paintTransformedContent(
|
|||
texCoords[3][0], texCoords[3][1],
|
||||
};
|
||||
|
||||
_contentBuffer->bind();
|
||||
_contentBuffer->write(0, coords, sizeof(coords));
|
||||
|
||||
program->setUniformValue("viewport", QSizeF(_viewport * _factor));
|
||||
program->setUniformValue("viewport", _uniformViewport);
|
||||
program->setUniformValue("s_texture", GLint(0));
|
||||
|
||||
toggleBlending(false);
|
||||
|
@ -395,6 +420,13 @@ void OverlayWidget::RendererGL::paintSaveMsg(QRect outer) {
|
|||
}, kSaveMsgOffset, true);
|
||||
}
|
||||
|
||||
void OverlayWidget::RendererGL::paintControlsStart() {
|
||||
validateControls();
|
||||
_f->glActiveTexture(GL_TEXTURE0);
|
||||
_controlsImage.bind(*_f);
|
||||
toggleBlending(true);
|
||||
}
|
||||
|
||||
void OverlayWidget::RendererGL::paintControl(
|
||||
OverState control,
|
||||
QRect outer,
|
||||
|
@ -402,7 +434,114 @@ void OverlayWidget::RendererGL::paintControl(
|
|||
QRect inner,
|
||||
float64 innerOpacity,
|
||||
const style::icon &icon) {
|
||||
AssertIsDebug(controls);
|
||||
const auto meta = ControlMeta(control);
|
||||
Assert(meta.icon == &icon);
|
||||
|
||||
const auto &bg = st::mediaviewControlBg->c;
|
||||
const auto bgAlpha = int(std::round(bg.alpha() * outerOpacity));
|
||||
const auto offset = kControlsOffset + (meta.index * kControlValues) / 4;
|
||||
const auto fgOffset = offset + 2;
|
||||
const auto bgRect = TransformRect(outer, _viewport, _factor);
|
||||
const auto iconRect = _controlsImage.texturedRect(
|
||||
inner,
|
||||
_controlsTextures[meta.index]);
|
||||
const auto iconGeometry = transformRect(iconRect.geometry);
|
||||
const GLfloat coords[] = {
|
||||
bgRect.left(), bgRect.top(),
|
||||
bgRect.right(), bgRect.top(),
|
||||
bgRect.right(), bgRect.bottom(),
|
||||
bgRect.left(), bgRect.bottom(),
|
||||
|
||||
iconGeometry.left(), iconGeometry.top(),
|
||||
iconRect.texture.left(), iconRect.texture.bottom(),
|
||||
|
||||
iconGeometry.right(), iconGeometry.top(),
|
||||
iconRect.texture.right(), iconRect.texture.bottom(),
|
||||
|
||||
iconGeometry.right(), iconGeometry.bottom(),
|
||||
iconRect.texture.right(), iconRect.texture.top(),
|
||||
|
||||
iconGeometry.left(), iconGeometry.bottom(),
|
||||
iconRect.texture.left(), iconRect.texture.top(),
|
||||
};
|
||||
if (!outer.isEmpty() && bgAlpha > 0) {
|
||||
_contentBuffer->write(
|
||||
offset * 4 * sizeof(GLfloat),
|
||||
coords,
|
||||
sizeof(coords));
|
||||
_f->glUseProgram(_fillProgram->programId());
|
||||
_fillProgram->setUniformValue("viewport", _uniformViewport);
|
||||
FillRectangle(
|
||||
*_f,
|
||||
&*_fillProgram,
|
||||
offset,
|
||||
QColor(bg.red(), bg.green(), bg.blue(), bgAlpha));
|
||||
} else {
|
||||
_contentBuffer->write(
|
||||
fgOffset * 4 * sizeof(GLfloat),
|
||||
coords + (fgOffset - offset) * 4,
|
||||
sizeof(coords) - (fgOffset - offset) * 4 * sizeof(GLfloat));
|
||||
}
|
||||
_f->glUseProgram(_controlsProgram->programId());
|
||||
_controlsProgram->setUniformValue("g_opacity", GLfloat(innerOpacity));
|
||||
_controlsProgram->setUniformValue("viewport", _uniformViewport);
|
||||
FillTexturedRectangle(*_f, &*_controlsProgram, fgOffset);
|
||||
}
|
||||
|
||||
auto OverlayWidget::RendererGL::ControlMeta(OverState control)
|
||||
-> Control {
|
||||
switch (control) {
|
||||
case OverLeftNav: return { 0, &st::mediaviewLeft };
|
||||
case OverRightNav: return { 1, &st::mediaviewRight };
|
||||
case OverClose: return { 2, &st::mediaviewClose };
|
||||
case OverSave: return { 3, &st::mediaviewSave };
|
||||
case OverRotate: return { 4, &st::mediaviewRotate };
|
||||
case OverMore: return { 5, &st::mediaviewMore };
|
||||
}
|
||||
Unexpected("Control value in OverlayWidget::RendererGL::ControlIndex.");
|
||||
}
|
||||
|
||||
void OverlayWidget::RendererGL::validateControls() {
|
||||
if (!_controlsImage.image().isNull()) {
|
||||
return;
|
||||
}
|
||||
const auto metas = {
|
||||
ControlMeta(OverLeftNav),
|
||||
ControlMeta(OverRightNav),
|
||||
ControlMeta(OverClose),
|
||||
ControlMeta(OverSave),
|
||||
ControlMeta(OverRotate),
|
||||
ControlMeta(OverMore),
|
||||
};
|
||||
auto maxWidth = 0;
|
||||
auto fullHeight = 0;
|
||||
for (const auto meta : metas) {
|
||||
maxWidth = std::max(meta.icon->width(), maxWidth);
|
||||
fullHeight += meta.icon->height();
|
||||
}
|
||||
auto image = QImage(
|
||||
QSize(maxWidth, fullHeight) * _factor,
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
image.fill(Qt::transparent);
|
||||
image.setDevicePixelRatio(_factor);
|
||||
{
|
||||
auto p = QPainter(&image);
|
||||
auto index = 0;
|
||||
auto height = 0;
|
||||
for (const auto meta : metas) {
|
||||
meta.icon->paint(p, 0, height, maxWidth);
|
||||
_controlsTextures[index++] = QRect(
|
||||
QPoint(0, height) * _factor,
|
||||
meta.icon->size() * _factor);
|
||||
height += meta.icon->height();
|
||||
}
|
||||
}
|
||||
_controlsImage.setImage(std::move(image));
|
||||
}
|
||||
|
||||
void OverlayWidget::RendererGL::invalidateControls() {
|
||||
_controlsImage.invalidate();
|
||||
ranges::fill(_controlsTextures, QRect());
|
||||
}
|
||||
|
||||
void OverlayWidget::RendererGL::paintFooter(QRect outer, float64 opacity) {
|
||||
|
@ -439,10 +578,12 @@ void OverlayWidget::RendererGL::invalidate() {
|
|||
&_footerImage,
|
||||
&_captionImage,
|
||||
&_groupThumbsImage,
|
||||
&_controlsImage,
|
||||
};
|
||||
for (const auto image : images) {
|
||||
image->setImage(QImage());
|
||||
}
|
||||
invalidateControls();
|
||||
}
|
||||
|
||||
void OverlayWidget::RendererGL::paintUsingRaster(
|
||||
|
@ -494,7 +635,7 @@ void OverlayWidget::RendererGL::paintUsingRaster(
|
|||
sizeof(coords));
|
||||
|
||||
_f->glUseProgram(_imageProgram->programId());
|
||||
_imageProgram->setUniformValue("viewport", QSizeF(_viewport * _factor));
|
||||
_imageProgram->setUniformValue("viewport", _uniformViewport);
|
||||
_imageProgram->setUniformValue("s_texture", GLint(0));
|
||||
|
||||
_f->glActiveTexture(GL_TEXTURE0);
|
||||
|
|
|
@ -39,6 +39,10 @@ public:
|
|||
QOpenGLFunctions &f) override;
|
||||
|
||||
private:
|
||||
struct Control {
|
||||
int index = -1;
|
||||
not_null<const style::icon*> icon;
|
||||
};
|
||||
bool handleHideWorkaround(QOpenGLFunctions &f);
|
||||
void setDefaultViewport(QOpenGLFunctions &f);
|
||||
|
||||
|
@ -60,6 +64,7 @@ private:
|
|||
void paintThemePreview(QRect outer) override;
|
||||
void paintDocumentBubble(QRect outer, QRect icon) override;
|
||||
void paintSaveMsg(QRect outer) override;
|
||||
void paintControlsStart() override;
|
||||
void paintControl(
|
||||
OverState control,
|
||||
QRect outer,
|
||||
|
@ -80,6 +85,8 @@ private:
|
|||
int bufferOffset,
|
||||
bool transparent = false);
|
||||
|
||||
void validateControls();
|
||||
void invalidateControls();
|
||||
void toggleBlending(bool enabled);
|
||||
|
||||
[[nodiscard]] Ui::GL::Rect transformRect(const QRect &raster) const;
|
||||
|
@ -100,12 +107,15 @@ private:
|
|||
Ui::GL::BackgroundFiller _background;
|
||||
QSize _viewport;
|
||||
float _factor = 1.;
|
||||
QVector2D _uniformViewport;
|
||||
|
||||
std::optional<QOpenGLBuffer> _contentBuffer;
|
||||
std::optional<QOpenGLShaderProgram> _imageProgram;
|
||||
QOpenGLShader *_texturedVertexShader = nullptr;
|
||||
std::optional<QOpenGLShaderProgram> _withTransparencyProgram;
|
||||
std::optional<QOpenGLShaderProgram> _yuv420Program;
|
||||
std::optional<QOpenGLShaderProgram> _fillProgram;
|
||||
std::optional<QOpenGLShaderProgram> _controlsProgram;
|
||||
Ui::GL::Textures<4> _textures;
|
||||
QSize _rgbaSize;
|
||||
QSize _lumaSize;
|
||||
|
@ -121,6 +131,12 @@ private:
|
|||
Ui::GL::Image _footerImage;
|
||||
Ui::GL::Image _captionImage;
|
||||
Ui::GL::Image _groupThumbsImage;
|
||||
Ui::GL::Image _controlsImage;
|
||||
|
||||
static constexpr auto kControlsCount = 6;
|
||||
[[nodiscard]] static Control ControlMeta(OverState control);
|
||||
std::array<QRect, kControlsCount> _controlsTextures;
|
||||
|
||||
bool _blendingEnabled = false;
|
||||
|
||||
rpl::lifetime _lifetime;
|
||||
|
|
|
@ -120,6 +120,9 @@ void OverlayWidget::RendererSW::paintSaveMsg(QRect outer) {
|
|||
}
|
||||
}
|
||||
|
||||
void OverlayWidget::RendererSW::paintControlsStart() {
|
||||
}
|
||||
|
||||
void OverlayWidget::RendererSW::paintControl(
|
||||
OverState control,
|
||||
QRect outer,
|
||||
|
|
|
@ -40,6 +40,7 @@ private:
|
|||
void paintThemePreview(QRect outer) override;
|
||||
void paintDocumentBubble(QRect outer, QRect icon) override;
|
||||
void paintSaveMsg(QRect outer) override;
|
||||
void paintControlsStart() override;
|
||||
void paintControl(
|
||||
OverState control,
|
||||
QRect outer,
|
||||
|
|
|
@ -27,6 +27,7 @@ public:
|
|||
virtual void paintThemePreview(QRect outer) = 0;
|
||||
virtual void paintDocumentBubble(QRect outer, QRect icon) = 0;
|
||||
virtual void paintSaveMsg(QRect outer) = 0;
|
||||
virtual void paintControlsStart() = 0;
|
||||
virtual void paintControl(
|
||||
OverState control,
|
||||
QRect outer,
|
||||
|
|
|
@ -3181,10 +3181,13 @@ void OverlayWidget::paint(not_null<Renderer*> renderer) {
|
|||
fillTransparentBackground);
|
||||
}
|
||||
paintRadialLoading(renderer);
|
||||
} else if (_themePreviewShown) {
|
||||
renderer->paintThemePreview(_themePreviewRect);
|
||||
} else if (documentBubbleShown() && !_docRect.isEmpty()) {
|
||||
renderer->paintDocumentBubble(_docRect, _docIconRect);
|
||||
} else {
|
||||
int a = 0;
|
||||
if (_themePreviewShown) {
|
||||
renderer->paintThemePreview(_themePreviewRect);
|
||||
} else if (documentBubbleShown() && !_docRect.isEmpty()) {
|
||||
renderer->paintDocumentBubble(_docRect, _docIconRect);
|
||||
}
|
||||
}
|
||||
updateSaveMsgState();
|
||||
if (_saveMsgStarted && _saveMsgOpacity.current() > 0.) {
|
||||
|
@ -3453,6 +3456,7 @@ void OverlayWidget::paintControls(
|
|||
const style::icon &icon;
|
||||
};
|
||||
const QRect kEmpty;
|
||||
// When adding / removing controls please update RendererGL.
|
||||
const Control controls[] = {
|
||||
{
|
||||
OverLeftNav,
|
||||
|
@ -3492,6 +3496,7 @@ void OverlayWidget::paintControls(
|
|||
st::mediaviewMore },
|
||||
};
|
||||
|
||||
renderer->paintControlsStart();
|
||||
for (const auto &control : controls) {
|
||||
if (!control.visible) {
|
||||
continue;
|
||||
|
@ -3938,7 +3943,7 @@ void OverlayWidget::preloadData(int delta) {
|
|||
if (!_index) {
|
||||
return;
|
||||
}
|
||||
auto from = *_index + (delta ? delta : -1);
|
||||
auto from = *_index + (delta ? -delta : -1);
|
||||
auto till = *_index + (delta ? delta * kPreloadCount : 1);
|
||||
if (from > till) std::swap(from, till);
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 06f7b1d4ec414a631010a9a3e2ef20a335523bc6
|
||||
Subproject commit 02049aeaa8806ef5d23fbf050be7e341e2d5bbde
|
Loading…
Add table
Reference in a new issue