Add noise to blur to remove color banding.
This commit is contained in:
parent
3d76e6de55
commit
dd79b3c0d5
|
@ -24,8 +24,12 @@ using namespace Ui::GL;
|
||||||
|
|
||||||
constexpr auto kScaleForBlurTextureIndex = 3;
|
constexpr auto kScaleForBlurTextureIndex = 3;
|
||||||
constexpr auto kFirstBlurPassTextureIndex = 4;
|
constexpr auto kFirstBlurPassTextureIndex = 4;
|
||||||
constexpr auto kBlurTextureSizeFactor = 1.7;
|
constexpr auto kNoiseTextureSize = 256;
|
||||||
constexpr auto kBlurOpacity = 0.7;
|
|
||||||
|
// The more the scale - more blurred the image.
|
||||||
|
constexpr auto kBlurTextureSizeFactor = 4.;
|
||||||
|
constexpr auto kBlurOpacity = 0.65;
|
||||||
|
constexpr auto kDitherNoiseAmount = 0.002;
|
||||||
constexpr auto kMinCameraVisiblePart = 0.75;
|
constexpr auto kMinCameraVisiblePart = 0.75;
|
||||||
|
|
||||||
constexpr auto kQuads = 7;
|
constexpr auto kQuads = 7;
|
||||||
|
@ -66,15 +70,128 @@ const int diameter = 2 * radius + 1;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] ShaderPart FragmentGenerateNoise() {
|
||||||
|
const auto size = QString::number(kNoiseTextureSize);
|
||||||
|
return {
|
||||||
|
.header = R"(
|
||||||
|
const float permTexUnit = 1.0 / )" + size + R"(.0;
|
||||||
|
const float permTexUnitHalf = 0.5 / )" + size + R"(.0;
|
||||||
|
const float grainsize = 1.3;
|
||||||
|
const float noiseCoordRotation = 1.425;
|
||||||
|
const vec2 dimensions = vec2()" + size + ", " + size + R"();
|
||||||
|
|
||||||
|
vec4 rnm(vec2 tc) {
|
||||||
|
float noise = sin(dot(tc, vec2(12.9898, 78.233))) * 43758.5453;
|
||||||
|
return vec4(
|
||||||
|
fract(noise),
|
||||||
|
fract(noise * 1.2154),
|
||||||
|
fract(noise * 1.3453),
|
||||||
|
fract(noise * 1.3647)
|
||||||
|
) * 2.0 - 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float fade(float t) {
|
||||||
|
return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
float pnoise3D(vec3 p) {
|
||||||
|
vec3 pi = permTexUnit * floor(p) + permTexUnitHalf;
|
||||||
|
vec3 pf = fract(p);
|
||||||
|
float perm = rnm(pi.xy).a;
|
||||||
|
float n000 = dot(rnm(vec2(perm, pi.z)).rgb * 4.0 - 1.0, pf);
|
||||||
|
float n001 = dot(
|
||||||
|
rnm(vec2(perm, pi.z + permTexUnit)).rgb * 4.0 - 1.0,
|
||||||
|
pf - vec3(0.0, 0.0, 1.0));
|
||||||
|
perm = rnm(pi.xy + vec2(0.0, permTexUnit)).a;
|
||||||
|
float n010 = dot(
|
||||||
|
rnm(vec2(perm, pi.z)).rgb * 4.0 - 1.0,
|
||||||
|
pf - vec3(0.0, 1.0, 0.0));
|
||||||
|
float n011 = dot(
|
||||||
|
rnm(vec2(perm, pi.z + permTexUnit)).rgb * 4.0 - 1.0,
|
||||||
|
pf - vec3(0.0, 1.0, 1.0));
|
||||||
|
perm = rnm(pi.xy + vec2(permTexUnit, 0.0)).a;
|
||||||
|
float n100 = dot(
|
||||||
|
rnm(vec2(perm, pi.z)).rgb * 4.0 - 1.0,
|
||||||
|
pf - vec3(1.0, 0.0, 0.0));
|
||||||
|
float n101 = dot(
|
||||||
|
rnm(vec2(perm, pi.z + permTexUnit)).rgb * 4.0 - 1.0,
|
||||||
|
pf - vec3(1.0, 0.0, 1.0));
|
||||||
|
perm = rnm(pi.xy + vec2(permTexUnit, permTexUnit)).a;
|
||||||
|
float n110 = dot(
|
||||||
|
rnm(vec2(perm, pi.z)).rgb * 4.0 - 1.0,
|
||||||
|
pf - vec3(1.0, 1.0, 0.0));
|
||||||
|
float n111 = dot(
|
||||||
|
rnm(vec2(perm, pi.z + permTexUnit)).rgb * 4.0 - 1.0,
|
||||||
|
pf - vec3(1.0, 1.0, 1.0));
|
||||||
|
vec4 n_x = mix(
|
||||||
|
vec4(n000, n001, n010, n011),
|
||||||
|
vec4(n100, n101, n110, n111),
|
||||||
|
fade(pf.x));
|
||||||
|
vec2 n_xy = mix(n_x.xy, n_x.zw, fade(pf.y));
|
||||||
|
return mix(n_xy.x, n_xy.y, fade(pf.z));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 rotateTexCoords(in lowp vec2 tc, in lowp float angle) {
|
||||||
|
float cosa = cos(angle);
|
||||||
|
float sina = sin(angle);
|
||||||
|
return vec2(
|
||||||
|
((tc.x * 2.0 - 1.0) * cosa - (tc.y * 2.0 - 1.0) * sina) * 0.5 + 0.5,
|
||||||
|
((tc.y * 2.0 - 1.0) * cosa + (tc.x * 2.0 - 1.0) * sina) * 0.5 + 0.5);
|
||||||
|
}
|
||||||
|
)",
|
||||||
|
.body = R"(
|
||||||
|
vec2 rotatedCoords = rotateTexCoords(
|
||||||
|
gl_FragCoord.xy / dimensions.xy,
|
||||||
|
noiseCoordRotation);
|
||||||
|
float intensity = pnoise3D(vec3(
|
||||||
|
rotatedCoords.x * dimensions.x / grainsize,
|
||||||
|
rotatedCoords.y * dimensions.y / grainsize,
|
||||||
|
0.0));
|
||||||
|
|
||||||
|
// Looks like intensity is almost always in [-2, 2] range.
|
||||||
|
float clamped = clamp((intensity + 2.) * 0.25, 0., 1.);
|
||||||
|
result = vec4(clamped, 0., 0., 1.);
|
||||||
|
)",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] ShaderPart FragmentDitherNoise() {
|
||||||
|
const auto size = QString::number(kNoiseTextureSize);
|
||||||
|
return {
|
||||||
|
.header = R"(
|
||||||
|
uniform sampler2D n_texture;
|
||||||
|
)",
|
||||||
|
.body = R"(
|
||||||
|
vec2 noiseTextureCoord = gl_FragCoord.xy / )" + size + R"(.;
|
||||||
|
float noiseClamped = texture2D(n_texture, noiseTextureCoord).r;
|
||||||
|
float noiseIntensity = (noiseClamped * 4.) - 2.;
|
||||||
|
|
||||||
|
vec3 lumcoeff = vec3(0.299, 0.587, 0.114);
|
||||||
|
float luminance = dot(result.rgb, lumcoeff);
|
||||||
|
float lum = smoothstep(0.2, 0.0, luminance) + luminance;
|
||||||
|
vec3 noiseColor = mix(vec3(noiseIntensity), vec3(0.0), pow(lum, 4.0));
|
||||||
|
|
||||||
|
result.rgb = result.rgb + noiseColor * noiseGrain;
|
||||||
|
)",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Depends on FragmentSampleTexture().
|
// Depends on FragmentSampleTexture().
|
||||||
[[nodiscard]] ShaderPart FragmentFrameColor() {
|
[[nodiscard]] ShaderPart FragmentFrameColor() {
|
||||||
|
const auto round = FragmentRoundCorners();
|
||||||
const auto blur = FragmentBlurTexture(true, 'b');
|
const auto blur = FragmentBlurTexture(true, 'b');
|
||||||
|
const auto noise = FragmentDitherNoise();
|
||||||
return {
|
return {
|
||||||
.header = R"(
|
.header = R"(
|
||||||
uniform vec4 frameBg;
|
uniform vec4 frameBg;
|
||||||
uniform vec3 shadow; // fullHeight, shown, maxOpacity
|
uniform vec3 shadow; // fullHeight, shown, maxOpacity
|
||||||
uniform float paused; // 0. <-> 1.
|
uniform float paused; // 0. <-> 1.
|
||||||
|
|
||||||
|
)" + blur.header + round.header + noise.header + R"(
|
||||||
|
|
||||||
const float backgroundOpacity = )" + QString::number(kBlurOpacity) + R"(;
|
const float backgroundOpacity = )" + QString::number(kBlurOpacity) + R"(;
|
||||||
|
const float noiseGrain = )" + QString::number(kDitherNoiseAmount) + R"(;
|
||||||
|
|
||||||
float insideTexture() {
|
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);
|
||||||
|
@ -82,10 +199,12 @@ float insideTexture() {
|
||||||
float outsideCheck = dot(fromTextureEdge, fromTextureEdge);
|
float outsideCheck = dot(fromTextureEdge, fromTextureEdge);
|
||||||
return step(outsideCheck, 0);
|
return step(outsideCheck, 0);
|
||||||
}
|
}
|
||||||
)" + blur.header + R"(
|
|
||||||
vec4 background() {
|
vec4 background() {
|
||||||
vec4 result;
|
vec4 result;
|
||||||
)" + blur.body + R"(
|
|
||||||
|
)" + blur.body + noise.body + R"(
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
)",
|
)",
|
||||||
|
@ -99,7 +218,7 @@ vec4 background() {
|
||||||
float shadowValue = max(1. - (shadowCoord / shadow.x), 0.);
|
float shadowValue = max(1. - (shadowCoord / shadow.x), 0.);
|
||||||
float shadowShown = max(shadowValue * shadow.y, paused) * shadow.z;
|
float shadowShown = max(shadowValue * shadow.y, paused) * shadow.z;
|
||||||
result = vec4(result.rgb * (1. - shadowShown), result.a);
|
result = vec4(result.rgb * (1. - shadowShown), result.a);
|
||||||
)",
|
)" + round.body,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,10 +238,10 @@ vec4 background() {
|
||||||
|
|
||||||
[[nodiscard]] QSize CountBlurredSize(
|
[[nodiscard]] QSize CountBlurredSize(
|
||||||
QSize unscaled,
|
QSize unscaled,
|
||||||
QSize viewport,
|
QSize outer,
|
||||||
float factor) {
|
float factor) {
|
||||||
factor *= kBlurTextureSizeFactor; // The more the scale - more blurred the image.
|
factor *= kBlurTextureSizeFactor;
|
||||||
const auto area = viewport / int(std::round(factor * cScale() / 100));
|
const auto area = outer / int(std::round(factor * cScale() / 100));
|
||||||
const auto scaled = unscaled.scaled(area, Qt::KeepAspectRatio);
|
const auto scaled = unscaled.scaled(area, Qt::KeepAspectRatio);
|
||||||
return (scaled.width() > unscaled.width()
|
return (scaled.width() > unscaled.width()
|
||||||
|| scaled.height() > unscaled.height())
|
|| scaled.height() > unscaled.height())
|
||||||
|
@ -208,6 +327,9 @@ void Viewport::RendererGL::init(
|
||||||
_frameBuffer->bind();
|
_frameBuffer->bind();
|
||||||
_frameBuffer->allocate(kValues * sizeof(GLfloat));
|
_frameBuffer->allocate(kValues * sizeof(GLfloat));
|
||||||
_downscaleProgram.yuv420.emplace();
|
_downscaleProgram.yuv420.emplace();
|
||||||
|
const auto downscaleVertexSource = VertexShader({
|
||||||
|
VertexPassTextureCoord(),
|
||||||
|
});
|
||||||
_downscaleVertexShader = LinkProgram(
|
_downscaleVertexShader = LinkProgram(
|
||||||
&*_downscaleProgram.yuv420,
|
&*_downscaleProgram.yuv420,
|
||||||
VertexShader({
|
VertexShader({
|
||||||
|
@ -216,6 +338,9 @@ void Viewport::RendererGL::init(
|
||||||
FragmentShader({
|
FragmentShader({
|
||||||
FragmentSampleYUV420Texture(),
|
FragmentSampleYUV420Texture(),
|
||||||
})).vertex;
|
})).vertex;
|
||||||
|
if (!_downscaleProgram.yuv420->isLinked()) {
|
||||||
|
//...
|
||||||
|
}
|
||||||
_blurProgram.emplace();
|
_blurProgram.emplace();
|
||||||
LinkProgram(
|
LinkProgram(
|
||||||
&*_blurProgram,
|
&*_blurProgram,
|
||||||
|
@ -234,7 +359,6 @@ void Viewport::RendererGL::init(
|
||||||
FragmentShader({
|
FragmentShader({
|
||||||
FragmentSampleYUV420Texture(),
|
FragmentSampleYUV420Texture(),
|
||||||
FragmentFrameColor(),
|
FragmentFrameColor(),
|
||||||
FragmentRoundCorners(),
|
|
||||||
})).vertex;
|
})).vertex;
|
||||||
|
|
||||||
_imageProgram.emplace();
|
_imageProgram.emplace();
|
||||||
|
@ -248,6 +372,8 @@ void Viewport::RendererGL::init(
|
||||||
FragmentSampleARGB32Texture(),
|
FragmentSampleARGB32Texture(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
validateNoiseTexture(f, 0);
|
||||||
|
|
||||||
_background.init(f);
|
_background.init(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,6 +413,8 @@ void Viewport::RendererGL::deinit(
|
||||||
_blurProgram = std::nullopt;
|
_blurProgram = std::nullopt;
|
||||||
_frameProgram.argb32 = std::nullopt;
|
_frameProgram.argb32 = std::nullopt;
|
||||||
_frameProgram.yuv420 = std::nullopt;
|
_frameProgram.yuv420 = std::nullopt;
|
||||||
|
_noiseTexture.destroy(f);
|
||||||
|
_noiseFramebuffer.destroy(f);
|
||||||
for (auto &data : _tileData) {
|
for (auto &data : _tileData) {
|
||||||
data.textures.destroy(f);
|
data.textures.destroy(f);
|
||||||
}
|
}
|
||||||
|
@ -314,9 +442,10 @@ void Viewport::RendererGL::paint(
|
||||||
not_null<QOpenGLWidget*> widget,
|
not_null<QOpenGLWidget*> widget,
|
||||||
QOpenGLFunctions &f) {
|
QOpenGLFunctions &f) {
|
||||||
_factor = widget->devicePixelRatio();
|
_factor = widget->devicePixelRatio();
|
||||||
|
const auto defaultFramebufferObject = widget->defaultFramebufferObject();
|
||||||
|
|
||||||
validateDatas();
|
validateDatas();
|
||||||
fillBackground(f);
|
fillBackground(f);
|
||||||
const auto defaultFramebufferObject = widget->defaultFramebufferObject();
|
|
||||||
auto index = 0;
|
auto index = 0;
|
||||||
for (const auto &tile : _owner->_tiles) {
|
for (const auto &tile : _owner->_tiles) {
|
||||||
if (!tile->shown()) {
|
if (!tile->shown()) {
|
||||||
|
@ -584,7 +713,10 @@ void Viewport::RendererGL::paintTile(
|
||||||
_frameBuffer->bind();
|
_frameBuffer->bind();
|
||||||
_frameBuffer->write(0, coords, sizeof(coords));
|
_frameBuffer->write(0, coords, sizeof(coords));
|
||||||
|
|
||||||
const auto blurSize = CountBlurredSize(unscaled, _viewport, _factor);
|
const auto blurSize = CountBlurredSize(
|
||||||
|
unscaled,
|
||||||
|
geometry.size(),
|
||||||
|
_factor);
|
||||||
prepareObjects(f, tileData, blurSize);
|
prepareObjects(f, tileData, blurSize);
|
||||||
f.glViewport(0, 0, blurSize.width(), blurSize.height());
|
f.glViewport(0, 0, blurSize.width(), blurSize.height());
|
||||||
|
|
||||||
|
@ -625,10 +757,11 @@ void Viewport::RendererGL::paintTile(
|
||||||
program->setUniformValue("paused", GLfloat(paused));
|
program->setUniformValue("paused", GLfloat(paused));
|
||||||
|
|
||||||
f.glActiveTexture(_rgbaFrame ? GL_TEXTURE1 : GL_TEXTURE3);
|
f.glActiveTexture(_rgbaFrame ? GL_TEXTURE1 : GL_TEXTURE3);
|
||||||
tileData.textures.bind(
|
tileData.textures.bind(f, kFirstBlurPassTextureIndex);
|
||||||
f,
|
|
||||||
tileData.textureIndex * 5 + kFirstBlurPassTextureIndex);
|
|
||||||
program->setUniformValue("b_texture", GLint(_rgbaFrame ? 1 : 3));
|
program->setUniformValue("b_texture", GLint(_rgbaFrame ? 1 : 3));
|
||||||
|
f.glActiveTexture(_rgbaFrame ? GL_TEXTURE2 : GL_TEXTURE5);
|
||||||
|
_noiseTexture.bind(f, 0);
|
||||||
|
program->setUniformValue("n_texture", GLint(_rgbaFrame ? 2 : 5));
|
||||||
program->setUniformValue(
|
program->setUniformValue(
|
||||||
"texelOffset",
|
"texelOffset",
|
||||||
GLfloat(1.f / blurSize.height()));
|
GLfloat(1.f / blurSize.height()));
|
||||||
|
@ -692,7 +825,15 @@ void Viewport::RendererGL::prepareObjects(
|
||||||
QOpenGLFunctions &f,
|
QOpenGLFunctions &f,
|
||||||
TileData &tileData,
|
TileData &tileData,
|
||||||
QSize blurSize) {
|
QSize blurSize) {
|
||||||
tileData.textures.ensureCreated(f);
|
if (!tileData.textures.created()) {
|
||||||
|
tileData.textures.ensureCreated(f); // All are GL_LINEAR, except..
|
||||||
|
tileData.textures.bind(f, kScaleForBlurTextureIndex);
|
||||||
|
|
||||||
|
// kScaleForBlurTextureIndex is attached to framebuffer 0,
|
||||||
|
// and is used to draw to framebuffer 1 of the same size.
|
||||||
|
f.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
f.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
}
|
||||||
tileData.framebuffers.ensureCreated(f);
|
tileData.framebuffers.ensureCreated(f);
|
||||||
|
|
||||||
if (tileData.textureBlurSize == blurSize) {
|
if (tileData.textureBlurSize == blurSize) {
|
||||||
|
@ -701,8 +842,6 @@ void Viewport::RendererGL::prepareObjects(
|
||||||
tileData.textureBlurSize = blurSize;
|
tileData.textureBlurSize = blurSize;
|
||||||
|
|
||||||
const auto create = [&](int framebufferIndex, int index) {
|
const auto create = [&](int framebufferIndex, int index) {
|
||||||
index += tileData.textureIndex * 5;
|
|
||||||
|
|
||||||
tileData.textures.bind(f, index);
|
tileData.textures.bind(f, index);
|
||||||
f.glTexImage2D(
|
f.glTexImage2D(
|
||||||
GL_TEXTURE_2D,
|
GL_TEXTURE_2D,
|
||||||
|
@ -762,7 +901,7 @@ void Viewport::RendererGL::bindFrame(
|
||||||
ensureARGB32Program();
|
ensureARGB32Program();
|
||||||
f.glUseProgram(program.argb32->programId());
|
f.glUseProgram(program.argb32->programId());
|
||||||
f.glActiveTexture(GL_TEXTURE0);
|
f.glActiveTexture(GL_TEXTURE0);
|
||||||
tileData.textures.bind(f, tileData.textureIndex * 5 + 0);
|
tileData.textures.bind(f, 0);
|
||||||
if (upload) {
|
if (upload) {
|
||||||
const auto &image = _userpicFrame
|
const auto &image = _userpicFrame
|
||||||
? tileData.userpicFrame
|
? tileData.userpicFrame
|
||||||
|
@ -785,7 +924,7 @@ void Viewport::RendererGL::bindFrame(
|
||||||
const auto yuv = data.yuv420;
|
const auto yuv = data.yuv420;
|
||||||
f.glUseProgram(program.yuv420->programId());
|
f.glUseProgram(program.yuv420->programId());
|
||||||
f.glActiveTexture(GL_TEXTURE0);
|
f.glActiveTexture(GL_TEXTURE0);
|
||||||
tileData.textures.bind(f, tileData.textureIndex * 5 + 0);
|
tileData.textures.bind(f, 0);
|
||||||
if (upload) {
|
if (upload) {
|
||||||
f.glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
f.glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
uploadTexture(
|
uploadTexture(
|
||||||
|
@ -800,7 +939,7 @@ void Viewport::RendererGL::bindFrame(
|
||||||
tileData.rgbaSize = QSize();
|
tileData.rgbaSize = QSize();
|
||||||
}
|
}
|
||||||
f.glActiveTexture(GL_TEXTURE1);
|
f.glActiveTexture(GL_TEXTURE1);
|
||||||
tileData.textures.bind(f, tileData.textureIndex * 5 + 1);
|
tileData.textures.bind(f, 1);
|
||||||
if (upload) {
|
if (upload) {
|
||||||
uploadTexture(
|
uploadTexture(
|
||||||
f,
|
f,
|
||||||
|
@ -812,7 +951,7 @@ void Viewport::RendererGL::bindFrame(
|
||||||
yuv->u.data);
|
yuv->u.data);
|
||||||
}
|
}
|
||||||
f.glActiveTexture(GL_TEXTURE2);
|
f.glActiveTexture(GL_TEXTURE2);
|
||||||
tileData.textures.bind(f, tileData.textureIndex * 5 + 2);
|
tileData.textures.bind(f, 2);
|
||||||
if (upload) {
|
if (upload) {
|
||||||
uploadTexture(
|
uploadTexture(
|
||||||
f,
|
f,
|
||||||
|
@ -886,9 +1025,7 @@ void Viewport::RendererGL::drawFirstBlurPass(
|
||||||
|
|
||||||
f.glUseProgram(_blurProgram->programId());
|
f.glUseProgram(_blurProgram->programId());
|
||||||
f.glActiveTexture(GL_TEXTURE0);
|
f.glActiveTexture(GL_TEXTURE0);
|
||||||
tileData.textures.bind(
|
tileData.textures.bind(f, kScaleForBlurTextureIndex);
|
||||||
f,
|
|
||||||
tileData.textureIndex * 5 + kScaleForBlurTextureIndex);
|
|
||||||
|
|
||||||
_blurProgram->setUniformValue("b_texture", GLint(0));
|
_blurProgram->setUniformValue("b_texture", GLint(0));
|
||||||
_blurProgram->setUniformValue(
|
_blurProgram->setUniformValue(
|
||||||
|
@ -1145,6 +1282,73 @@ void Viewport::RendererGL::validateDatas() {
|
||||||
_names.setImage(std::move(paintToImage));
|
_names.setImage(std::move(paintToImage));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Viewport::RendererGL::validateNoiseTexture(
|
||||||
|
QOpenGLFunctions &f,
|
||||||
|
GLuint defaultFramebufferObject) {
|
||||||
|
if (_noiseTexture.created()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_noiseTexture.ensureCreated(f, GL_NEAREST, GL_REPEAT);
|
||||||
|
_noiseTexture.bind(f, 0);
|
||||||
|
f.glTexImage2D(
|
||||||
|
GL_TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
GL_RED,
|
||||||
|
kNoiseTextureSize,
|
||||||
|
kNoiseTextureSize,
|
||||||
|
0,
|
||||||
|
GL_RED,
|
||||||
|
GL_UNSIGNED_BYTE,
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
_noiseFramebuffer.ensureCreated(f);
|
||||||
|
_noiseFramebuffer.bind(f, 0);
|
||||||
|
|
||||||
|
f.glFramebufferTexture2D(
|
||||||
|
GL_FRAMEBUFFER,
|
||||||
|
GL_COLOR_ATTACHMENT0,
|
||||||
|
GL_TEXTURE_2D,
|
||||||
|
_noiseTexture.id(0),
|
||||||
|
0);
|
||||||
|
|
||||||
|
f.glViewport(0, 0, kNoiseTextureSize, kNoiseTextureSize);
|
||||||
|
|
||||||
|
const GLfloat coords[] = {
|
||||||
|
-1, -1,
|
||||||
|
-1, 1,
|
||||||
|
1, 1,
|
||||||
|
1, -1,
|
||||||
|
};
|
||||||
|
auto buffer = QOpenGLBuffer();
|
||||||
|
buffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
|
||||||
|
buffer.create();
|
||||||
|
buffer.bind();
|
||||||
|
buffer.allocate(coords, sizeof(coords));
|
||||||
|
|
||||||
|
auto program = QOpenGLShaderProgram();
|
||||||
|
LinkProgram(
|
||||||
|
&program,
|
||||||
|
VertexShader({}),
|
||||||
|
FragmentShader({ FragmentGenerateNoise() }));
|
||||||
|
f.glUseProgram(program.programId());
|
||||||
|
|
||||||
|
GLint position = program.attributeLocation("position");
|
||||||
|
f.glVertexAttribPointer(
|
||||||
|
position,
|
||||||
|
2,
|
||||||
|
GL_FLOAT,
|
||||||
|
GL_FALSE,
|
||||||
|
2 * sizeof(GLfloat),
|
||||||
|
nullptr);
|
||||||
|
f.glEnableVertexAttribArray(position);
|
||||||
|
|
||||||
|
f.glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||||
|
|
||||||
|
f.glDisableVertexAttribArray(position);
|
||||||
|
|
||||||
|
f.glUseProgram(0);
|
||||||
|
}
|
||||||
|
|
||||||
void Viewport::RendererGL::validateOutlineAnimation(
|
void Viewport::RendererGL::validateOutlineAnimation(
|
||||||
not_null<VideoTile*> tile,
|
not_null<VideoTile*> tile,
|
||||||
TileData &data) {
|
TileData &data) {
|
||||||
|
|
|
@ -57,7 +57,6 @@ private:
|
||||||
QImage userpicFrame;
|
QImage userpicFrame;
|
||||||
QRect nameRect;
|
QRect nameRect;
|
||||||
int nameVersion = 0;
|
int nameVersion = 0;
|
||||||
mutable int textureIndex = 0;
|
|
||||||
mutable int trackIndex = -1;
|
mutable int trackIndex = -1;
|
||||||
mutable QSize rgbaSize;
|
mutable QSize rgbaSize;
|
||||||
mutable QSize textureSize;
|
mutable QSize textureSize;
|
||||||
|
@ -102,6 +101,9 @@ private:
|
||||||
TileData &tileData,
|
TileData &tileData,
|
||||||
QSize blurSize);
|
QSize blurSize);
|
||||||
void validateDatas();
|
void validateDatas();
|
||||||
|
void validateNoiseTexture(
|
||||||
|
QOpenGLFunctions &f,
|
||||||
|
GLuint defaultFramebufferObject);
|
||||||
void validateOutlineAnimation(
|
void validateOutlineAnimation(
|
||||||
not_null<VideoTile*> tile,
|
not_null<VideoTile*> tile,
|
||||||
TileData &data);
|
TileData &data);
|
||||||
|
@ -142,6 +144,8 @@ private:
|
||||||
std::optional<QOpenGLShaderProgram> _blurProgram;
|
std::optional<QOpenGLShaderProgram> _blurProgram;
|
||||||
Program _frameProgram;
|
Program _frameProgram;
|
||||||
std::optional<QOpenGLShaderProgram> _imageProgram;
|
std::optional<QOpenGLShaderProgram> _imageProgram;
|
||||||
|
Ui::GL::Textures<1> _noiseTexture;
|
||||||
|
Ui::GL::Framebuffers<1> _noiseFramebuffer;
|
||||||
QOpenGLShader *_downscaleVertexShader = nullptr;
|
QOpenGLShader *_downscaleVertexShader = nullptr;
|
||||||
QOpenGLShader *_frameVertexShader = nullptr;
|
QOpenGLShader *_frameVertexShader = nullptr;
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 35236988b7bc489b7683019db89636d4030db1ce
|
Subproject commit 4ae6d319634be7aa3530ad3e934a187f630bd6fd
|
Loading…
Reference in New Issue