From 8b7aa442268a4928f7582d97b33cb624b29d0cde Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 2 Jun 2021 20:27:30 +0400 Subject: [PATCH] Provide some simple OpenGL primitives. --- CMakeLists.txt | 2 + ui/gl/gl_math.cpp | 9 +++ ui/gl/gl_math.h | 5 ++ ui/gl/gl_primitives.cpp | 148 ++++++++++++++++++++++++++++++++++++++++ ui/gl/gl_primitives.h | 54 +++++++++++++++ ui/style/style_core.cpp | 17 ++--- ui/style/style_core.h | 2 +- 7 files changed, 228 insertions(+), 9 deletions(-) create mode 100644 ui/gl/gl_primitives.cpp create mode 100644 ui/gl/gl_primitives.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e63930d..21f6acf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,6 +63,8 @@ PRIVATE ui/gl/gl_image.h ui/gl/gl_math.cpp ui/gl/gl_math.h + ui/gl/gl_primitives.cpp + ui/gl/gl_primitives.h ui/gl/gl_shader.cpp ui/gl/gl_shader.h ui/gl/gl_surface.cpp diff --git a/ui/gl/gl_math.cpp b/ui/gl/gl_math.cpp index ad37155..98fc9fc 100644 --- a/ui/gl/gl_math.cpp +++ b/ui/gl/gl_math.cpp @@ -32,4 +32,13 @@ QSizeF Uniform(QSize size) { return size; } +Rect TransformRect(const Rect &raster, QSize viewport, float factor) { + return { + raster.left() * factor, + float(viewport.height() - raster.bottom()) * factor, + raster.width() * factor, + raster.height() * factor, + }; +} + } // namespace Ui::GL diff --git a/ui/gl/gl_math.h b/ui/gl/gl_math.h index 16d2fc3..cc35d65 100644 --- a/ui/gl/gl_math.h +++ b/ui/gl/gl_math.h @@ -76,4 +76,9 @@ private: [[nodiscard]] QVector4D Uniform(const QColor &color); [[nodiscard]] QSizeF Uniform(QSize size); +[[nodiscard]] Rect TransformRect( + const Rect &raster, + QSize viewport, + float factor); + } // namespace Ui::GL diff --git a/ui/gl/gl_primitives.cpp b/ui/gl/gl_primitives.cpp new file mode 100644 index 0000000..036e4f3 --- /dev/null +++ b/ui/gl/gl_primitives.cpp @@ -0,0 +1,148 @@ +// This file is part of Desktop App Toolkit, +// a set of libraries for developing nice desktop applications. +// +// For license and copyright information please follow this link: +// https://github.com/desktop-app/legal/blob/master/LEGAL +// +#include "ui/gl/gl_primitives.h" + +#include "ui/gl/gl_shader.h" +#include "ui/style/style_core.h" + +#include + +namespace Ui::GL { + +static_assert(std::is_same_v); + +void FillRectVertices(float *coords, Rect rect) { + coords[0] = coords[10] = rect.left(); + coords[1] = coords[11] = rect.top(); + coords[2] = rect.right(); + coords[3] = rect.top(); + coords[4] = coords[6] = rect.right(); + coords[5] = coords[7] = rect.bottom(); + coords[8] = rect.left(); + coords[9] = rect.bottom(); +} + +void FillTriangles( + QOpenGLFunctions &f, + gsl::span coords, + not_null buffer, + not_null program, + QSize viewportWithFactor, + const QColor &color, + Fn additional) { + Expects(coords.size() % 6 == 0); + + if (coords.empty()) { + return; + } + buffer->bind(); + buffer->allocate(coords.data(), coords.size() * sizeof(GLfloat)); + + f.glUseProgram(program->programId()); + program->setUniformValue("viewport", QSizeF(viewportWithFactor)); + program->setUniformValue("s_color", Uniform(color)); + + GLint position = program->attributeLocation("position"); + f.glVertexAttribPointer( + position, + 2, + GL_FLOAT, + GL_FALSE, + 2 * sizeof(GLfloat), + nullptr); + f.glEnableVertexAttribArray(position); + + if (additional) { + additional(); + } + + f.glDrawArrays(GL_TRIANGLES, 0, coords.size() / 2); + + f.glDisableVertexAttribArray(position); +} + +void FillTexturedRectangle( + QOpenGLFunctions &f, + not_null program, + int skipVertices) { + const auto shift = [&](int elements) { + return reinterpret_cast( + (skipVertices * 4 + elements) * sizeof(GLfloat)); + }; + GLint position = program->attributeLocation("position"); + f.glVertexAttribPointer( + position, + 2, + GL_FLOAT, + GL_FALSE, + 4 * sizeof(GLfloat), + shift(0)); + f.glEnableVertexAttribArray(position); + + GLint texcoord = program->attributeLocation("v_texcoordIn"); + 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); +} + +void BackgroundFiller::init(QOpenGLFunctions &f) { + _bgBuffer.emplace(); + _bgBuffer->setUsagePattern(QOpenGLBuffer::DynamicDraw); + _bgBuffer->create(); + _bgProgram.emplace(); + LinkProgram( + &*_bgProgram, + VertexShader({ VertexViewportTransform() }), + FragmentShader({ FragmentStaticColor() })); +} + +void BackgroundFiller::deinit(QOpenGLFunctions &f) { + _bgProgram.reset(); + _bgBuffer.reset(); +} + +void BackgroundFiller::fill( + QOpenGLFunctions &f, + const QRegion ®ion, + QSize viewport, + float factor, + const style::color &color) { + const auto &rgb = color->c.toRgb(); + if (region.isEmpty()) { + return; + } else if (region.end() - region.begin() == 1 + && (*region.begin()).size() == viewport) { + f.glClearColor(rgb.redF(), rgb.greenF(), rgb.blueF(), rgb.alphaF()); + f.glClear(GL_COLOR_BUFFER_BIT); + return; + } + _bgTriangles.resize((region.end() - region.begin()) * 12); + auto coords = _bgTriangles.data(); + for (const auto rect : region) { + FillRectVertices(coords, TransformRect(rect, viewport, factor)); + coords += 12; + } + FillTriangles( + f, + _bgTriangles, + &*_bgBuffer, + &*_bgProgram, + viewport * factor, + rgb); +} + +} // namespace Ui::GL diff --git a/ui/gl/gl_primitives.h b/ui/gl/gl_primitives.h new file mode 100644 index 0000000..3ec0755 --- /dev/null +++ b/ui/gl/gl_primitives.h @@ -0,0 +1,54 @@ +// This file is part of Desktop App Toolkit, +// a set of libraries for developing nice desktop applications. +// +// For license and copyright information please follow this link: +// https://github.com/desktop-app/legal/blob/master/LEGAL +// +#pragma once + +#include "ui/gl/gl_math.h" +#include "ui/style/style_core.h" + +#include +#include + +class QOpenGLFunctions; + +namespace Ui::GL { + +void FillRectVertices(float *coords, Rect rect); + +void FillTriangles( + QOpenGLFunctions &f, + gsl::span coords, + not_null buffer, + not_null program, + QSize viewportWithFactor, + const QColor &color, + Fn additional = nullptr); + +void FillTexturedRectangle( + QOpenGLFunctions &f, + not_null program, + int skipVertices = 0); + +class BackgroundFiller final { +public: + void init(QOpenGLFunctions &f); + void deinit(QOpenGLFunctions &); + + void fill( + QOpenGLFunctions &f, + const QRegion ®ion, + QSize viewport, + float factor, + const style::color &color); + +private: + std::optional _bgBuffer; + std::optional _bgProgram; + std::vector _bgTriangles; + +}; + +} // namespace Ui::GL diff --git a/ui/style/style_core.cpp b/ui/style/style_core.cpp index 171b390..2a68082 100644 --- a/ui/style/style_core.cpp +++ b/ui/style/style_core.cpp @@ -126,18 +126,19 @@ void colorizeImage(const QImage &src, QColor c, QImage *outResult, QRect srcRect outResult->setDevicePixelRatio(src.devicePixelRatio()); } -QBrush transparentPlaceholderBrush() { - auto size = st::transparentPlaceholderSize * DevicePixelRatio(); - auto transparent = QImage(2 * size, 2 * size, QImage::Format_ARGB32_Premultiplied); - transparent.fill(st::mediaviewTransparentBg->c); +QImage TransparentPlaceholder() { + const auto size = st::transparentPlaceholderSize * DevicePixelRatio(); + auto result = QImage( + 2 * size, 2 * size, + QImage::Format_ARGB32_Premultiplied); + result.fill(st::mediaviewTransparentBg->c); { - QPainter p(&transparent); + QPainter p(&result); p.fillRect(0, size, size, size, st::mediaviewTransparentFg); p.fillRect(size, 0, size, size, st::mediaviewTransparentFg); } - transparent.setDevicePixelRatio(DevicePixelRatio()); - return QBrush(transparent); - + result.setDevicePixelRatio(DevicePixelRatio()); + return result; } namespace internal { diff --git a/ui/style/style_core.h b/ui/style/style_core.h index d996342..cd9324f 100644 --- a/ui/style/style_core.h +++ b/ui/style/style_core.h @@ -58,7 +58,7 @@ inline QImage colorizeImage(const QImage &src, const color &c, QRect srcRect = Q return colorizeImage(src, c->c, srcRect); } -QBrush transparentPlaceholderBrush(); +[[nodiscard]] QImage TransparentPlaceholder(); namespace internal {