Add some utilities for OpenGL shaders.
This commit is contained in:
parent
2a26d4a91a
commit
808f8c7dea
7 changed files with 382 additions and 0 deletions
|
|
@ -61,6 +61,10 @@ PRIVATE
|
|||
ui/gl/gl_detection.h
|
||||
ui/gl/gl_image.cpp
|
||||
ui/gl/gl_image.h
|
||||
ui/gl/gl_math.cpp
|
||||
ui/gl/gl_math.h
|
||||
ui/gl/gl_shader.cpp
|
||||
ui/gl/gl_shader.h
|
||||
ui/gl/gl_surface.cpp
|
||||
ui/gl/gl_surface.h
|
||||
ui/image/image_prepare.cpp
|
||||
|
|
|
|||
|
|
@ -82,4 +82,31 @@ void Image::destroy(QOpenGLFunctions &f) {
|
|||
_cacheKey = 0;
|
||||
}
|
||||
|
||||
TexturedRect Image::texturedRect(
|
||||
const QRect &geometry,
|
||||
const QRect &texture,
|
||||
const QRect &clip) {
|
||||
Expects(!_image.isNull());
|
||||
|
||||
const auto visible = clip.isNull()
|
||||
? geometry
|
||||
: clip.intersected(geometry);
|
||||
const auto xFactor = texture.width() / geometry.width();
|
||||
const auto yFactor = texture.height() / geometry.height();
|
||||
const auto usedTexture = QRect(
|
||||
texture.x() + (visible.x() - geometry.x()) * xFactor,
|
||||
texture.y() + (visible.y() - geometry.y()) * yFactor,
|
||||
visible.width() * xFactor,
|
||||
visible.height() * yFactor);
|
||||
const auto dimensions = QSizeF(_image.size());
|
||||
return {
|
||||
.geometry = Rect(visible),
|
||||
.texture = Rect(QRectF(
|
||||
usedTexture.x() / dimensions.width(),
|
||||
usedTexture.y() / dimensions.height(),
|
||||
usedTexture.width() / dimensions.width(),
|
||||
usedTexture.height() / dimensions.height())),
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace Ui::GL
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
//
|
||||
#pragma once
|
||||
|
||||
#include "ui/gl/gl_math.h"
|
||||
|
||||
#include <QtGui/QOpenGLFunctions>
|
||||
|
||||
namespace Ui::GL {
|
||||
|
|
@ -47,6 +49,11 @@ private:
|
|||
|
||||
};
|
||||
|
||||
struct TexturedRect {
|
||||
Rect geometry;
|
||||
Rect texture;
|
||||
};
|
||||
|
||||
class Image final {
|
||||
public:
|
||||
void setImage(QImage image);
|
||||
|
|
@ -57,6 +64,11 @@ public:
|
|||
void bind(QOpenGLFunctions &f);
|
||||
void destroy(QOpenGLFunctions &f);
|
||||
|
||||
[[nodiscard]] TexturedRect texturedRect(
|
||||
const QRect &geometry,
|
||||
const QRect &texture,
|
||||
const QRect &clip = QRect());
|
||||
|
||||
explicit operator bool() const {
|
||||
return !_image.isNull();
|
||||
}
|
||||
|
|
|
|||
35
ui/gl/gl_math.cpp
Normal file
35
ui/gl/gl_math.cpp
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
// 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_math.h"
|
||||
|
||||
namespace Ui::GL {
|
||||
|
||||
QVector4D Uniform(const QRect &rect, float factor) {
|
||||
return QVector4D(
|
||||
rect.x() * factor,
|
||||
rect.y() * factor,
|
||||
rect.width() * factor,
|
||||
rect.height() * factor);
|
||||
}
|
||||
|
||||
QVector4D Uniform(const Rect &rect) {
|
||||
return QVector4D(rect.x(), rect.y(), rect.width(), rect.height());
|
||||
}
|
||||
|
||||
QVector4D Uniform(const QColor &color) {
|
||||
return QVector4D(
|
||||
color.redF(),
|
||||
color.greenF(),
|
||||
color.blueF(),
|
||||
color.alphaF());
|
||||
}
|
||||
|
||||
QSizeF Uniform(QSize size) {
|
||||
return size;
|
||||
}
|
||||
|
||||
} // namespace Ui::GL
|
||||
75
ui/gl/gl_math.h
Normal file
75
ui/gl/gl_math.h
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
// 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 <QtGui/QVector4D>
|
||||
#include <QtCore/QSizeF>
|
||||
|
||||
namespace Ui::GL {
|
||||
|
||||
class Rect final {
|
||||
public:
|
||||
Rect(QRect rect)
|
||||
: _x(rect.x())
|
||||
, _y(rect.y())
|
||||
, _width(rect.width())
|
||||
, _height(rect.height()) {
|
||||
}
|
||||
|
||||
Rect(QRectF rect)
|
||||
: _x(rect.x())
|
||||
, _y(rect.y())
|
||||
, _width(rect.width())
|
||||
, _height(rect.height()) {
|
||||
}
|
||||
|
||||
Rect(float x, float y, float width, float height)
|
||||
: _x(x)
|
||||
, _y(y)
|
||||
, _width(width)
|
||||
, _height(height) {
|
||||
}
|
||||
|
||||
[[nodiscard]] float x() const {
|
||||
return _x;
|
||||
}
|
||||
[[nodiscard]] float y() const {
|
||||
return _y;
|
||||
}
|
||||
[[nodiscard]] float width() const {
|
||||
return _width;
|
||||
}
|
||||
[[nodiscard]] float height() const {
|
||||
return _height;
|
||||
}
|
||||
[[nodiscard]] float left() const {
|
||||
return _x;
|
||||
}
|
||||
[[nodiscard]] float top() const {
|
||||
return _y;
|
||||
}
|
||||
[[nodiscard]] float right() const {
|
||||
return _x + _width;
|
||||
}
|
||||
[[nodiscard]] float bottom() const {
|
||||
return _y + _height;
|
||||
}
|
||||
|
||||
private:
|
||||
float _x = 0;
|
||||
float _y = 0;
|
||||
float _width = 0;
|
||||
float _height = 0;
|
||||
|
||||
};
|
||||
|
||||
[[nodiscard]] QVector4D Uniform(const QRect &rect, float factor);
|
||||
[[nodiscard]] QVector4D Uniform(const Rect &rect);
|
||||
[[nodiscard]] QVector4D Uniform(const QColor &color);
|
||||
[[nodiscard]] QSizeF Uniform(QSize size);
|
||||
|
||||
} // namespace Ui::GL
|
||||
183
ui/gl/gl_shader.cpp
Normal file
183
ui/gl/gl_shader.cpp
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
// 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_shader.h"
|
||||
|
||||
#include "base/debug_log.h"
|
||||
|
||||
namespace Ui::GL {
|
||||
|
||||
QString VertexShader(const std::vector<ShaderPart> &parts) {
|
||||
const auto accumulate = [&](auto proj) {
|
||||
return ranges::accumulate(parts, QString(), std::plus<>(), proj);
|
||||
};
|
||||
return R"(
|
||||
#version 120
|
||||
attribute vec2 position;
|
||||
)" + accumulate(&ShaderPart::header) + R"(
|
||||
void main() {
|
||||
vec4 result = vec4(position, 0., 1.);
|
||||
)" + accumulate(&ShaderPart::body) + R"(
|
||||
gl_Position = result;
|
||||
}
|
||||
)";
|
||||
}
|
||||
|
||||
QString FragmentShader(const std::vector<ShaderPart> &parts) {
|
||||
const auto accumulate = [&](auto proj) {
|
||||
return ranges::accumulate(parts, QString(), std::plus<>(), proj);
|
||||
};
|
||||
return R"(
|
||||
#version 120
|
||||
)" + accumulate(&ShaderPart::header) + R"(
|
||||
void main() {
|
||||
vec4 result = vec4(0., 0., 0., 0.);
|
||||
)" + accumulate(&ShaderPart::body) + R"(
|
||||
gl_FragColor = result;
|
||||
}
|
||||
)";
|
||||
}
|
||||
|
||||
ShaderPart VertexPassTextureCoord() {
|
||||
return {
|
||||
.header = R"(
|
||||
attribute vec2 texcoord;
|
||||
varying vec2 v_texcoord;
|
||||
)",
|
||||
.body = R"(
|
||||
v_texcoord = texcoord;
|
||||
)",
|
||||
};
|
||||
}
|
||||
|
||||
ShaderPart FragmentSampleARGB32Texture() {
|
||||
return {
|
||||
.header = R"(
|
||||
varying vec2 v_texcoord;
|
||||
uniform sampler2D s_texture;
|
||||
)",
|
||||
.body = R"(
|
||||
result = texture2D(s_texture, v_texcoord);
|
||||
result = vec4(result.b, result.g, result.r, result.a);
|
||||
)",
|
||||
};
|
||||
}
|
||||
|
||||
ShaderPart FragmentSampleYUV420Texture() {
|
||||
return {
|
||||
.header = R"(
|
||||
varying vec2 v_texcoord;
|
||||
uniform sampler2D y_texture;
|
||||
uniform sampler2D u_texture;
|
||||
uniform sampler2D v_texture;
|
||||
)",
|
||||
.body = R"(
|
||||
float y = texture2D(y_texture, v_texcoord).r;
|
||||
float u = texture2D(u_texture, v_texcoord).r - 0.5;
|
||||
float v = texture2D(v_texture, v_texcoord).r - 0.5;
|
||||
result = vec4(y + 1.403 * v, y - 0.344 * u - 0.714 * v, y + 1.77 * u, 1);
|
||||
)",
|
||||
};
|
||||
}
|
||||
|
||||
ShaderPart VertexViewportTransform() {
|
||||
return {
|
||||
.header = R"(
|
||||
uniform vec2 viewport;
|
||||
vec4 transform(vec4 position) {
|
||||
return vec4(
|
||||
vec2(-1, -1) + 2 * position.xy / viewport,
|
||||
position.z,
|
||||
position.w);
|
||||
}
|
||||
)",
|
||||
.body = R"(
|
||||
result = transform(result);
|
||||
)",
|
||||
};
|
||||
}
|
||||
|
||||
ShaderPart FragmentRoundCorners() {
|
||||
return {
|
||||
.header = R"(
|
||||
uniform vec4 roundRect;
|
||||
uniform vec4 roundBg;
|
||||
uniform float roundRadius;
|
||||
float roundedCorner() {
|
||||
vec2 rectHalf = roundRect.zw / 2;
|
||||
vec2 rectCenter = roundRect.xy + rectHalf;
|
||||
vec2 fromRectCenter = abs(gl_FragCoord.xy - rectCenter);
|
||||
vec2 vectorRadius = vec2(roundRadius + 0.5, roundRadius + 0.5);
|
||||
vec2 fromCenterWithRadius = fromRectCenter + vectorRadius;
|
||||
vec2 fromRoundingCenter = max(fromCenterWithRadius, rectHalf)
|
||||
- rectHalf;
|
||||
float d = length(fromRoundingCenter) - roundRadius;
|
||||
return 1. - smoothstep(0., 1., d);
|
||||
}
|
||||
)",
|
||||
.body = R"(
|
||||
float rounded = roundedCorner();
|
||||
result = result * rounded + roundBg * (1. - rounded);
|
||||
)",
|
||||
};
|
||||
}
|
||||
|
||||
ShaderPart FragmentStaticColor() {
|
||||
return {
|
||||
.header = R"(
|
||||
uniform vec4 s_color;
|
||||
)",
|
||||
.body = R"(
|
||||
result = s_color;
|
||||
)",
|
||||
};
|
||||
}
|
||||
|
||||
not_null<QOpenGLShader*> MakeShader(
|
||||
not_null<QOpenGLShaderProgram*> program,
|
||||
QOpenGLShader::ShaderType type,
|
||||
const QString &source) {
|
||||
const auto result = new QOpenGLShader(type, program);
|
||||
if (!result->compileSourceCode(source)) {
|
||||
LOG(("Shader Compilation Failed: %1, error %2."
|
||||
).arg(source
|
||||
).arg(result->log()));
|
||||
}
|
||||
program->addShader(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
Program LinkProgram(
|
||||
not_null<QOpenGLShaderProgram*> program,
|
||||
std::variant<QString, not_null<QOpenGLShader*>> vertex,
|
||||
std::variant<QString, not_null<QOpenGLShader*>> fragment) {
|
||||
const auto vertexAsSource = v::is<QString>(vertex);
|
||||
const auto v = vertexAsSource
|
||||
? MakeShader(
|
||||
program,
|
||||
QOpenGLShader::Vertex,
|
||||
v::get<QString>(vertex))
|
||||
: v::get<not_null<QOpenGLShader*>>(vertex);
|
||||
if (!vertexAsSource) {
|
||||
program->addShader(v);
|
||||
}
|
||||
const auto fragmentAsSource = v::is<QString>(fragment);
|
||||
const auto f = fragmentAsSource
|
||||
? MakeShader(
|
||||
program,
|
||||
QOpenGLShader::Fragment,
|
||||
v::get<QString>(fragment))
|
||||
: v::get<not_null<QOpenGLShader*>>(fragment);
|
||||
if (!fragmentAsSource) {
|
||||
program->addShader(f);
|
||||
}
|
||||
if (!program->link()) {
|
||||
LOG(("Shader Link Failed: %1.").arg(program->log()));
|
||||
}
|
||||
return { v, f };
|
||||
}
|
||||
|
||||
} // namespace Ui::GL
|
||||
46
ui/gl/gl_shader.h
Normal file
46
ui/gl/gl_shader.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
// 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 <QtCore/QString>
|
||||
#include <QtGui/QOpenGLShader>
|
||||
|
||||
class OpenGLShaderProgram;
|
||||
|
||||
namespace Ui::GL {
|
||||
|
||||
struct ShaderPart {
|
||||
QString header;
|
||||
QString body;
|
||||
};
|
||||
|
||||
[[nodiscard]] QString VertexShader(const std::vector<ShaderPart> &parts);
|
||||
[[nodiscard]] QString FragmentShader(const std::vector<ShaderPart> &parts);
|
||||
|
||||
[[nodiscard]] ShaderPart VertexPassTextureCoord();
|
||||
[[nodiscard]] ShaderPart FragmentSampleARGB32Texture();
|
||||
[[nodiscard]] ShaderPart FragmentSampleYUV420Texture();
|
||||
[[nodiscard]] ShaderPart VertexViewportTransform();
|
||||
[[nodiscard]] ShaderPart FragmentRoundCorners();
|
||||
[[nodiscard]] ShaderPart FragmentStaticColor();
|
||||
|
||||
not_null<QOpenGLShader*> MakeShader(
|
||||
not_null<QOpenGLShaderProgram*> program,
|
||||
QOpenGLShader::ShaderType type,
|
||||
const QString &source);
|
||||
|
||||
struct Program {
|
||||
not_null<QOpenGLShader*> vertex;
|
||||
not_null<QOpenGLShader*> fragment;
|
||||
};
|
||||
|
||||
Program LinkProgram(
|
||||
not_null<QOpenGLShaderProgram*> program,
|
||||
std::variant<QString, not_null<QOpenGLShader*>> vertex,
|
||||
std::variant<QString, not_null<QOpenGLShader*>> fragment);
|
||||
|
||||
} // namespace Ui::GL
|
||||
Loading…
Add table
Reference in a new issue