mirror of
https://github.com/hyprwm/hyprlock.git
synced 2024-12-22 13:29:48 +01:00
widgets: Reload backgrounds and not just images (#583)
* widgets: Reload background and fade * clang-format also clang-format * undo possibly unwanted format on Renderer.hpp * rename stuff + style * codestyle + initialize reloadTime * remove trailing eols
This commit is contained in:
parent
381a284b3b
commit
058830668e
7 changed files with 365 additions and 30 deletions
|
@ -191,6 +191,9 @@ void CConfigManager::init() {
|
||||||
m_config.addSpecialConfigValue("background", "vibrancy", Hyprlang::FLOAT{0.1686});
|
m_config.addSpecialConfigValue("background", "vibrancy", Hyprlang::FLOAT{0.1686});
|
||||||
m_config.addSpecialConfigValue("background", "vibrancy_darkness", Hyprlang::FLOAT{0.05});
|
m_config.addSpecialConfigValue("background", "vibrancy_darkness", Hyprlang::FLOAT{0.05});
|
||||||
m_config.addSpecialConfigValue("background", "zindex", Hyprlang::INT{-1});
|
m_config.addSpecialConfigValue("background", "zindex", Hyprlang::INT{-1});
|
||||||
|
m_config.addSpecialConfigValue("background", "reload_time", Hyprlang::INT{-1});
|
||||||
|
m_config.addSpecialConfigValue("background", "reload_cmd", Hyprlang::STRING{""});
|
||||||
|
m_config.addSpecialConfigValue("background", "crossfade_time", Hyprlang::FLOAT{-1.0});
|
||||||
|
|
||||||
m_config.addSpecialCategory("shape", Hyprlang::SSpecialCategoryOptions{.key = nullptr, .anonymousKeyBased = true});
|
m_config.addSpecialCategory("shape", Hyprlang::SSpecialCategoryOptions{.key = nullptr, .anonymousKeyBased = true});
|
||||||
m_config.addSpecialConfigValue("shape", "monitor", Hyprlang::STRING{""});
|
m_config.addSpecialConfigValue("shape", "monitor", Hyprlang::STRING{""});
|
||||||
|
@ -318,6 +321,9 @@ std::vector<CConfigManager::SWidgetConfig> CConfigManager::getWidgetConfigs() {
|
||||||
{"brightness", m_config.getSpecialConfigValue("background", "brightness", k.c_str())},
|
{"brightness", m_config.getSpecialConfigValue("background", "brightness", k.c_str())},
|
||||||
{"vibrancy_darkness", m_config.getSpecialConfigValue("background", "vibrancy_darkness", k.c_str())},
|
{"vibrancy_darkness", m_config.getSpecialConfigValue("background", "vibrancy_darkness", k.c_str())},
|
||||||
{"zindex", m_config.getSpecialConfigValue("background", "zindex", k.c_str())},
|
{"zindex", m_config.getSpecialConfigValue("background", "zindex", k.c_str())},
|
||||||
|
{"reload_time", m_config.getSpecialConfigValue("background", "reload_time", k.c_str())},
|
||||||
|
{"reload_cmd", m_config.getSpecialConfigValue("background", "reload_cmd", k.c_str())},
|
||||||
|
{"crossfade_time", m_config.getSpecialConfigValue("background", "crossfade_time", k.c_str())},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
|
@ -106,6 +106,27 @@ CRenderer::CRenderer() {
|
||||||
texShader.tint = glGetUniformLocation(prog, "tint");
|
texShader.tint = glGetUniformLocation(prog, "tint");
|
||||||
texShader.useAlphaMatte = glGetUniformLocation(prog, "useAlphaMatte");
|
texShader.useAlphaMatte = glGetUniformLocation(prog, "useAlphaMatte");
|
||||||
|
|
||||||
|
prog = createProgram(TEXVERTSRC, TEXMIXFRAGSRCRGBA);
|
||||||
|
texMixShader.program = prog;
|
||||||
|
texMixShader.proj = glGetUniformLocation(prog, "proj");
|
||||||
|
texMixShader.tex = glGetUniformLocation(prog, "tex1");
|
||||||
|
texMixShader.tex2 = glGetUniformLocation(prog, "tex2");
|
||||||
|
texMixShader.alphaMatte = glGetUniformLocation(prog, "texMatte");
|
||||||
|
texMixShader.alpha = glGetUniformLocation(prog, "alpha");
|
||||||
|
texMixShader.mixFactor = glGetUniformLocation(prog, "mixFactor");
|
||||||
|
texMixShader.texAttrib = glGetAttribLocation(prog, "texcoord");
|
||||||
|
texMixShader.matteTexAttrib = glGetAttribLocation(prog, "texcoordMatte");
|
||||||
|
texMixShader.posAttrib = glGetAttribLocation(prog, "pos");
|
||||||
|
texMixShader.discardOpaque = glGetUniformLocation(prog, "discardOpaque");
|
||||||
|
texMixShader.discardAlpha = glGetUniformLocation(prog, "discardAlpha");
|
||||||
|
texMixShader.discardAlphaValue = glGetUniformLocation(prog, "discardAlphaValue");
|
||||||
|
texMixShader.topLeft = glGetUniformLocation(prog, "topLeft");
|
||||||
|
texMixShader.fullSize = glGetUniformLocation(prog, "fullSize");
|
||||||
|
texMixShader.radius = glGetUniformLocation(prog, "radius");
|
||||||
|
texMixShader.applyTint = glGetUniformLocation(prog, "applyTint");
|
||||||
|
texMixShader.tint = glGetUniformLocation(prog, "tint");
|
||||||
|
texMixShader.useAlphaMatte = glGetUniformLocation(prog, "useAlphaMatte");
|
||||||
|
|
||||||
prog = createProgram(TEXVERTSRC, FRAGBLUR1);
|
prog = createProgram(TEXVERTSRC, FRAGBLUR1);
|
||||||
blurShader1.program = prog;
|
blurShader1.program = prog;
|
||||||
blurShader1.tex = glGetUniformLocation(prog, "tex");
|
blurShader1.tex = glGetUniformLocation(prog, "tex");
|
||||||
|
@ -347,6 +368,52 @@ void CRenderer::renderTexture(const CBox& box, const CTexture& tex, float a, int
|
||||||
glBindTexture(tex.m_iTarget, 0);
|
glBindTexture(tex.m_iTarget, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CRenderer::renderTextureMix(const CBox& box, const CTexture& tex, const CTexture& tex2, float a, float mixFactor, int rounding, std::optional<eTransform> tr) {
|
||||||
|
const auto ROUNDEDBOX = box.copy().round();
|
||||||
|
Mat3x3 matrix = projMatrix.projectBox(ROUNDEDBOX, tr.value_or(HYPRUTILS_TRANSFORM_FLIPPED_180), box.rot);
|
||||||
|
Mat3x3 glMatrix = projection.copy().multiply(matrix);
|
||||||
|
|
||||||
|
CShader* shader = &texMixShader;
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindTexture(tex.m_iTarget, tex.m_iTexID);
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE1);
|
||||||
|
glBindTexture(tex2.m_iTarget, tex2.m_iTexID);
|
||||||
|
|
||||||
|
glUseProgram(shader->program);
|
||||||
|
|
||||||
|
glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix.getMatrix().data());
|
||||||
|
glUniform1i(shader->tex, 0);
|
||||||
|
glUniform1i(shader->tex2, 1);
|
||||||
|
glUniform1f(shader->alpha, a);
|
||||||
|
glUniform1f(shader->mixFactor, mixFactor);
|
||||||
|
const auto TOPLEFT = Vector2D(ROUNDEDBOX.x, ROUNDEDBOX.y);
|
||||||
|
const auto FULLSIZE = Vector2D(ROUNDEDBOX.width, ROUNDEDBOX.height);
|
||||||
|
|
||||||
|
// Rounded corners
|
||||||
|
glUniform2f(shader->topLeft, TOPLEFT.x, TOPLEFT.y);
|
||||||
|
glUniform2f(shader->fullSize, FULLSIZE.x, FULLSIZE.y);
|
||||||
|
glUniform1f(shader->radius, rounding);
|
||||||
|
|
||||||
|
glUniform1i(shader->discardOpaque, 0);
|
||||||
|
glUniform1i(shader->discardAlpha, 0);
|
||||||
|
glUniform1i(shader->applyTint, 0);
|
||||||
|
|
||||||
|
glVertexAttribPointer(shader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
|
||||||
|
glVertexAttribPointer(shader->texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(shader->posAttrib);
|
||||||
|
glEnableVertexAttribArray(shader->texAttrib);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
|
||||||
|
glDisableVertexAttribArray(shader->posAttrib);
|
||||||
|
glDisableVertexAttribArray(shader->texAttrib);
|
||||||
|
|
||||||
|
glBindTexture(tex.m_iTarget, 0);
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::unique_ptr<IWidget>>* CRenderer::getOrCreateWidgetsFor(const CSessionLockSurface* surf) {
|
std::vector<std::unique_ptr<IWidget>>* CRenderer::getOrCreateWidgetsFor(const CSessionLockSurface* surf) {
|
||||||
if (!widgets.contains(surf)) {
|
if (!widgets.contains(surf)) {
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ class CRenderer {
|
||||||
void renderRect(const CBox& box, const CColor& col, int rounding = 0);
|
void renderRect(const CBox& box, const CColor& col, int rounding = 0);
|
||||||
void renderBorder(const CBox& box, const CGradientValueData& gradient, int thickness, int rounding = 0, float alpha = 1.0);
|
void renderBorder(const CBox& box, const CGradientValueData& gradient, int thickness, int rounding = 0, float alpha = 1.0);
|
||||||
void renderTexture(const CBox& box, const CTexture& tex, float a = 1.0, int rounding = 0, std::optional<eTransform> tr = {});
|
void renderTexture(const CBox& box, const CTexture& tex, float a = 1.0, int rounding = 0, std::optional<eTransform> tr = {});
|
||||||
|
void renderTextureMix(const CBox& box, const CTexture& tex, const CTexture& tex2, float a = 1.0, float mixFactor = 0.0, int rounding = 0, std::optional<eTransform> tr = {});
|
||||||
void blurFB(const CFramebuffer& outfb, SBlurParams params);
|
void blurFB(const CFramebuffer& outfb, SBlurParams params);
|
||||||
|
|
||||||
std::unique_ptr<CAsyncResourceGatherer> asyncResourceGatherer;
|
std::unique_ptr<CAsyncResourceGatherer> asyncResourceGatherer;
|
||||||
|
@ -50,6 +51,7 @@ class CRenderer {
|
||||||
|
|
||||||
CShader rectShader;
|
CShader rectShader;
|
||||||
CShader texShader;
|
CShader texShader;
|
||||||
|
CShader texMixShader;
|
||||||
CShader blurShader1;
|
CShader blurShader1;
|
||||||
CShader blurShader2;
|
CShader blurShader2;
|
||||||
CShader blurPrepareShader;
|
CShader blurPrepareShader;
|
||||||
|
|
|
@ -13,7 +13,9 @@ class CShader {
|
||||||
GLint color = -1;
|
GLint color = -1;
|
||||||
GLint alphaMatte = -1;
|
GLint alphaMatte = -1;
|
||||||
GLint tex = -1;
|
GLint tex = -1;
|
||||||
|
GLint tex2 = -1;
|
||||||
GLint alpha = -1;
|
GLint alpha = -1;
|
||||||
|
GLfloat mixFactor = -1;
|
||||||
GLint posAttrib = -1;
|
GLint posAttrib = -1;
|
||||||
GLint texAttrib = -1;
|
GLint texAttrib = -1;
|
||||||
GLint matteTexAttrib = -1;
|
GLint matteTexAttrib = -1;
|
||||||
|
|
|
@ -129,6 +129,49 @@ void main() {
|
||||||
gl_FragColor = pixColor * alpha;
|
gl_FragColor = pixColor * alpha;
|
||||||
})#";
|
})#";
|
||||||
|
|
||||||
|
inline const std::string TEXMIXFRAGSRCRGBA = R"#(
|
||||||
|
precision highp float;
|
||||||
|
varying vec2 v_texcoord; // is in 0-1
|
||||||
|
uniform sampler2D tex1;
|
||||||
|
uniform sampler2D tex2;
|
||||||
|
uniform float mixFactor;
|
||||||
|
uniform float alpha;
|
||||||
|
|
||||||
|
uniform vec2 topLeft;
|
||||||
|
uniform vec2 fullSize;
|
||||||
|
uniform float radius;
|
||||||
|
|
||||||
|
uniform int discardOpaque;
|
||||||
|
uniform int discardAlpha;
|
||||||
|
uniform float discardAlphaValue;
|
||||||
|
|
||||||
|
uniform int applyTint;
|
||||||
|
uniform vec3 tint;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
|
||||||
|
vec4 pixColor = mix(texture2D(tex1, v_texcoord), texture2D(tex2, v_texcoord), smoothstep(0.0, 1.0, mixFactor));
|
||||||
|
|
||||||
|
if (discardOpaque == 1 && pixColor[3] * alpha == 1.0)
|
||||||
|
discard;
|
||||||
|
|
||||||
|
if (discardAlpha == 1 && pixColor[3] <= discardAlphaValue)
|
||||||
|
discard;
|
||||||
|
|
||||||
|
if (applyTint == 1) {
|
||||||
|
pixColor[0] = pixColor[0] * tint[0];
|
||||||
|
pixColor[1] = pixColor[1] * tint[1];
|
||||||
|
pixColor[2] = pixColor[2] * tint[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (radius > 0.0) {
|
||||||
|
)#" +
|
||||||
|
ROUNDED_SHADER_FUNC("pixColor") + R"#(
|
||||||
|
}
|
||||||
|
|
||||||
|
gl_FragColor = pixColor * alpha;
|
||||||
|
})#";
|
||||||
|
|
||||||
inline const std::string FRAGBLUR1 = R"#(
|
inline const std::string FRAGBLUR1 = R"#(
|
||||||
#version 100
|
#version 100
|
||||||
precision highp float;
|
precision highp float;
|
||||||
|
|
|
@ -1,10 +1,33 @@
|
||||||
#include "Background.hpp"
|
#include "Background.hpp"
|
||||||
#include "../Renderer.hpp"
|
#include "../Renderer.hpp"
|
||||||
|
#include "../../core/hyprlock.hpp"
|
||||||
|
#include "src/helpers/Log.hpp"
|
||||||
|
#include <chrono>
|
||||||
#include <hyprlang.hpp>
|
#include <hyprlang.hpp>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <memory>
|
||||||
|
#include <GLES3/gl32.h>
|
||||||
|
|
||||||
|
CBackground::~CBackground() {
|
||||||
|
|
||||||
|
if (reloadTimer) {
|
||||||
|
reloadTimer->cancel();
|
||||||
|
reloadTimer.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fade) {
|
||||||
|
if (fade->crossFadeTimer) {
|
||||||
|
fade->crossFadeTimer->cancel();
|
||||||
|
fade->crossFadeTimer.reset();
|
||||||
|
}
|
||||||
|
fade.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CBackground::CBackground(const Vector2D& viewport_, COutput* output_, const std::string& resourceID_, const std::unordered_map<std::string, std::any>& props, bool ss) :
|
CBackground::CBackground(const Vector2D& viewport_, COutput* output_, const std::string& resourceID_, const std::unordered_map<std::string, std::any>& props, bool ss) :
|
||||||
viewport(viewport_), resourceID(resourceID_), output(output_), isScreenshot(ss) {
|
viewport(viewport_), resourceID(resourceID_), output(output_), isScreenshot(ss) {
|
||||||
|
|
||||||
|
try {
|
||||||
color = std::any_cast<Hyprlang::INT>(props.at("color"));
|
color = std::any_cast<Hyprlang::INT>(props.at("color"));
|
||||||
blurPasses = std::any_cast<Hyprlang::INT>(props.at("blur_passes"));
|
blurPasses = std::any_cast<Hyprlang::INT>(props.at("blur_passes"));
|
||||||
blurSize = std::any_cast<Hyprlang::INT>(props.at("blur_size"));
|
blurSize = std::any_cast<Hyprlang::INT>(props.at("blur_size"));
|
||||||
|
@ -13,6 +36,23 @@ CBackground::CBackground(const Vector2D& viewport_, COutput* output_, const std:
|
||||||
noise = std::any_cast<Hyprlang::FLOAT>(props.at("noise"));
|
noise = std::any_cast<Hyprlang::FLOAT>(props.at("noise"));
|
||||||
brightness = std::any_cast<Hyprlang::FLOAT>(props.at("brightness"));
|
brightness = std::any_cast<Hyprlang::FLOAT>(props.at("brightness"));
|
||||||
contrast = std::any_cast<Hyprlang::FLOAT>(props.at("contrast"));
|
contrast = std::any_cast<Hyprlang::FLOAT>(props.at("contrast"));
|
||||||
|
path = std::any_cast<Hyprlang::STRING>(props.at("path"));
|
||||||
|
reloadCommand = std::any_cast<Hyprlang::STRING>(props.at("reload_cmd"));
|
||||||
|
reloadTime = std::any_cast<Hyprlang::INT>(props.at("reload_time"));
|
||||||
|
crossFadeTime = std::any_cast<Hyprlang::FLOAT>(props.at("crossfade_time"));
|
||||||
|
|
||||||
|
} catch (const std::bad_any_cast& e) {
|
||||||
|
RASSERT(false, "Failed to construct CBackground: {}", e.what()); //
|
||||||
|
} catch (const std::out_of_range& e) {
|
||||||
|
RASSERT(false, "Missing propperty for CBackground: {}", e.what()); //
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
modificationTime = std::filesystem::last_write_time(path);
|
||||||
|
} catch (std::exception& e) { Debug::log(ERR, "{}", e.what()); }
|
||||||
|
|
||||||
|
if (!isScreenshot)
|
||||||
|
plantReloadTimer(); // No reloads for screenshots.
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBackground::renderRect(CColor color) {
|
void CBackground::renderRect(CColor color) {
|
||||||
|
@ -20,6 +60,27 @@ void CBackground::renderRect(CColor color) {
|
||||||
g_pRenderer->renderRect(monbox, color, 0);
|
g_pRenderer->renderRect(monbox, color, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void onReloadTimer(std::shared_ptr<CTimer> self, void* data) {
|
||||||
|
const auto PBG = (CBackground*)data;
|
||||||
|
|
||||||
|
PBG->onReloadTimerUpdate();
|
||||||
|
PBG->plantReloadTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void onCrossFadeTimer(std::shared_ptr<CTimer> self, void* data) {
|
||||||
|
const auto PBG = (CBackground*)data;
|
||||||
|
PBG->onCrossFadeTimerUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void onAssetCallback(void* data) {
|
||||||
|
const auto PBG = (CBackground*)data;
|
||||||
|
PBG->startCrossFadeOrUpdateRender();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void onAssetCallbackTimer(std::shared_ptr<CTimer> self, void* data) {
|
||||||
|
onAssetCallback(data);
|
||||||
|
}
|
||||||
|
|
||||||
bool CBackground::draw(const SRenderData& data) {
|
bool CBackground::draw(const SRenderData& data) {
|
||||||
|
|
||||||
if (resourceID.empty()) {
|
if (resourceID.empty()) {
|
||||||
|
@ -45,10 +106,13 @@ bool CBackground::draw(const SRenderData& data) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((blurPasses > 0 || isScreenshot) && !blurredFB.isAllocated()) {
|
if (fade || ((blurPasses > 0 || isScreenshot) && (!blurredFB.isAllocated() || firstRender))) {
|
||||||
|
|
||||||
|
if (firstRender)
|
||||||
|
firstRender = false;
|
||||||
|
|
||||||
// make it brah
|
// make it brah
|
||||||
Vector2D size = asset->texture.m_vSize;
|
Vector2D size = asset->texture.m_vSize;
|
||||||
|
|
||||||
if (output->transform % 2 == 1 && isScreenshot) {
|
if (output->transform % 2 == 1 && isScreenshot) {
|
||||||
size.x = asset->texture.m_vSize.y;
|
size.x = asset->texture.m_vSize.y;
|
||||||
size.y = asset->texture.m_vSize.x;
|
size.y = asset->texture.m_vSize.x;
|
||||||
|
@ -67,13 +131,23 @@ bool CBackground::draw(const SRenderData& data) {
|
||||||
else
|
else
|
||||||
texbox.x = -(texbox.w - viewport.x) / 2.f;
|
texbox.x = -(texbox.w - viewport.x) / 2.f;
|
||||||
texbox.round();
|
texbox.round();
|
||||||
|
|
||||||
|
if (!blurredFB.isAllocated())
|
||||||
blurredFB.alloc(viewport.x, viewport.y); // TODO 10 bit
|
blurredFB.alloc(viewport.x, viewport.y); // TODO 10 bit
|
||||||
|
|
||||||
blurredFB.bind();
|
blurredFB.bind();
|
||||||
|
|
||||||
|
if (fade)
|
||||||
|
g_pRenderer->renderTextureMix(texbox, asset->texture, pendingAsset->texture, 1.0,
|
||||||
|
std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - fade->start).count() / (1000 * crossFadeTime),
|
||||||
|
0, HYPRUTILS_TRANSFORM_NORMAL);
|
||||||
|
else
|
||||||
g_pRenderer->renderTexture(texbox, asset->texture, 1.0, 0,
|
g_pRenderer->renderTexture(texbox, asset->texture, 1.0, 0,
|
||||||
isScreenshot ?
|
isScreenshot ?
|
||||||
wlTransformToHyprutils(invertTransform(output->transform)) :
|
wlTransformToHyprutils(invertTransform(output->transform)) :
|
||||||
HYPRUTILS_TRANSFORM_NORMAL); // this could be omitted but whatever it's only once and makes code cleaner plus less blurring on large texs
|
HYPRUTILS_TRANSFORM_NORMAL); // this could be omitted but whatever it's only once and makes code cleaner plus less blurring on large texs
|
||||||
|
|
||||||
|
|
||||||
if (blurPasses > 0)
|
if (blurPasses > 0)
|
||||||
g_pRenderer->blurFB(blurredFB, CRenderer::SBlurParams{blurSize, blurPasses, noise, contrast, brightness, vibrancy, vibrancy_darkness});
|
g_pRenderer->blurFB(blurredFB, CRenderer::SBlurParams{blurSize, blurPasses, noise, contrast, brightness, vibrancy, vibrancy_darkness});
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
|
@ -97,5 +171,114 @@ bool CBackground::draw(const SRenderData& data) {
|
||||||
texbox.round();
|
texbox.round();
|
||||||
g_pRenderer->renderTexture(texbox, *tex, data.opacity, 0, HYPRUTILS_TRANSFORM_FLIPPED_180);
|
g_pRenderer->renderTexture(texbox, *tex, data.opacity, 0, HYPRUTILS_TRANSFORM_FLIPPED_180);
|
||||||
|
|
||||||
return data.opacity < 1.0;
|
return fade || data.opacity < 1.0; // actively render during fading
|
||||||
|
}
|
||||||
|
|
||||||
|
void CBackground::plantReloadTimer() {
|
||||||
|
|
||||||
|
if (reloadTime == 0)
|
||||||
|
reloadTimer = g_pHyprlock->addTimer(std::chrono::hours(1), onReloadTimer, this, true);
|
||||||
|
else if (reloadTime > 0)
|
||||||
|
reloadTimer = g_pHyprlock->addTimer(std::chrono::seconds(reloadTime), onReloadTimer, this, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CBackground::onCrossFadeTimerUpdate() {
|
||||||
|
|
||||||
|
// Animation done: Unload previous asset, deinitialize the fade and pass the asset
|
||||||
|
|
||||||
|
if (fade) {
|
||||||
|
fade->crossFadeTimer.reset();
|
||||||
|
fade.reset(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(blurPasses > 0 || isScreenshot))
|
||||||
|
blurredFB.release();
|
||||||
|
|
||||||
|
asset = pendingAsset;
|
||||||
|
resourceID = pendingResourceID;
|
||||||
|
pendingResourceID = "";
|
||||||
|
pendingAsset = nullptr;
|
||||||
|
firstRender = true;
|
||||||
|
|
||||||
|
g_pHyprlock->renderOutput(output->stringPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CBackground::onReloadTimerUpdate() {
|
||||||
|
const std::string OLDPATH = path;
|
||||||
|
|
||||||
|
// Path parsing and early returns
|
||||||
|
|
||||||
|
if (!reloadCommand.empty()) {
|
||||||
|
path = g_pHyprlock->spawnSync(reloadCommand);
|
||||||
|
|
||||||
|
if (path.ends_with('\n'))
|
||||||
|
path.pop_back();
|
||||||
|
|
||||||
|
if (path.starts_with("file://"))
|
||||||
|
path = path.substr(7);
|
||||||
|
|
||||||
|
if (path.empty())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const auto MTIME = std::filesystem::last_write_time(path);
|
||||||
|
if (OLDPATH == path && MTIME == modificationTime)
|
||||||
|
return;
|
||||||
|
|
||||||
|
modificationTime = MTIME;
|
||||||
|
} catch (std::exception& e) {
|
||||||
|
path = OLDPATH;
|
||||||
|
Debug::log(ERR, "{}", e.what());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pendingResourceID.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Issue the next request
|
||||||
|
|
||||||
|
request.id = std::string{"background:"} + path + ",time:" + std::to_string((uint64_t)modificationTime.time_since_epoch().count());
|
||||||
|
pendingResourceID = request.id;
|
||||||
|
request.asset = path;
|
||||||
|
request.type = CAsyncResourceGatherer::eTargetType::TARGET_IMAGE;
|
||||||
|
|
||||||
|
request.callback = onAssetCallback;
|
||||||
|
request.callbackData = this;
|
||||||
|
|
||||||
|
g_pRenderer->asyncResourceGatherer->requestAsyncAssetPreload(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CBackground::startCrossFadeOrUpdateRender() {
|
||||||
|
auto newAsset = g_pRenderer->asyncResourceGatherer->getAssetByID(pendingResourceID);
|
||||||
|
if (newAsset) {
|
||||||
|
if (newAsset->texture.m_iType == TEXTURE_INVALID) {
|
||||||
|
g_pRenderer->asyncResourceGatherer->unloadAsset(newAsset);
|
||||||
|
Debug::log(ERR, "New asset had an invalid texture!");
|
||||||
|
} else if (resourceID != pendingResourceID) {
|
||||||
|
pendingAsset = newAsset;
|
||||||
|
if (crossFadeTime > 0) {
|
||||||
|
// Start a fade
|
||||||
|
if (!fade)
|
||||||
|
fade = std::make_unique<SFade>(std::chrono::system_clock::now(), 0, nullptr);
|
||||||
|
else {
|
||||||
|
// Maybe we where already fading so reset it just in case, but should'nt be happening.
|
||||||
|
if (fade->crossFadeTimer) {
|
||||||
|
fade->crossFadeTimer->cancel();
|
||||||
|
fade->crossFadeTimer.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fade->start = std::chrono::system_clock::now();
|
||||||
|
fade->a = 0;
|
||||||
|
fade->crossFadeTimer = g_pHyprlock->addTimer(std::chrono::milliseconds((int)(1000.0 * crossFadeTime)), onCrossFadeTimer, this);
|
||||||
|
} else {
|
||||||
|
onCrossFadeTimerUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (!pendingResourceID.empty()) {
|
||||||
|
Debug::log(WARN, "Asset {} not available after the asyncResourceGatherer's callback!", pendingResourceID);
|
||||||
|
g_pHyprlock->addTimer(std::chrono::milliseconds(100), onAssetCallbackTimer, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_pHyprlock->renderOutput(output->stringPort);
|
||||||
}
|
}
|
|
@ -3,21 +3,37 @@
|
||||||
#include "IWidget.hpp"
|
#include "IWidget.hpp"
|
||||||
#include "../../helpers/Color.hpp"
|
#include "../../helpers/Color.hpp"
|
||||||
#include "../../helpers/Math.hpp"
|
#include "../../helpers/Math.hpp"
|
||||||
|
#include "../../core/Timer.hpp"
|
||||||
#include "../Framebuffer.hpp"
|
#include "../Framebuffer.hpp"
|
||||||
|
#include "../AsyncResourceGatherer.hpp"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <any>
|
#include <any>
|
||||||
|
#include <chrono>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
struct SPreloadedAsset;
|
struct SPreloadedAsset;
|
||||||
class COutput;
|
class COutput;
|
||||||
|
|
||||||
|
struct SFade {
|
||||||
|
std::chrono::system_clock::time_point start;
|
||||||
|
float a = 0;
|
||||||
|
std::shared_ptr<CTimer> crossFadeTimer = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
class CBackground : public IWidget {
|
class CBackground : public IWidget {
|
||||||
public:
|
public:
|
||||||
CBackground(const Vector2D& viewport, COutput* output_, const std::string& resourceID, const std::unordered_map<std::string, std::any>& props, bool ss_);
|
CBackground(const Vector2D& viewport, COutput* output_, const std::string& resourceID, const std::unordered_map<std::string, std::any>& props, bool ss_);
|
||||||
|
~CBackground();
|
||||||
|
|
||||||
virtual bool draw(const SRenderData& data);
|
virtual bool draw(const SRenderData& data);
|
||||||
void renderRect(CColor color);
|
void renderRect(CColor color);
|
||||||
|
|
||||||
|
void onReloadTimerUpdate();
|
||||||
|
void onCrossFadeTimerUpdate();
|
||||||
|
void plantReloadTimer();
|
||||||
|
void startCrossFadeOrUpdateRender();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// if needed
|
// if needed
|
||||||
CFramebuffer blurredFB;
|
CFramebuffer blurredFB;
|
||||||
|
@ -30,9 +46,25 @@ class CBackground : public IWidget {
|
||||||
float vibrancy = 0.1696;
|
float vibrancy = 0.1696;
|
||||||
float vibrancy_darkness = 0.0;
|
float vibrancy_darkness = 0.0;
|
||||||
Vector2D viewport;
|
Vector2D viewport;
|
||||||
|
std::string path = "";
|
||||||
|
|
||||||
std::string resourceID;
|
std::string resourceID;
|
||||||
|
std::string pendingResourceID;
|
||||||
|
|
||||||
|
float crossFadeTime = -1.0;
|
||||||
|
|
||||||
CColor color;
|
CColor color;
|
||||||
SPreloadedAsset* asset = nullptr;
|
SPreloadedAsset* asset = nullptr;
|
||||||
COutput* output = nullptr;
|
COutput* output = nullptr;
|
||||||
bool isScreenshot = false;
|
bool isScreenshot = false;
|
||||||
|
SPreloadedAsset* pendingAsset = nullptr;
|
||||||
|
bool firstRender = true;
|
||||||
|
|
||||||
|
std::unique_ptr<SFade> fade;
|
||||||
|
|
||||||
|
int reloadTime = -1;
|
||||||
|
std::string reloadCommand;
|
||||||
|
CAsyncResourceGatherer::SPreloadRequest request;
|
||||||
|
std::shared_ptr<CTimer> reloadTimer;
|
||||||
|
std::filesystem::file_time_type modificationTime;
|
||||||
};
|
};
|
Loading…
Reference in a new issue