mirror of
https://git.allpurposem.at/mat/WiggleWobble.git
synced 2025-12-23 21:11:29 +01:00
feat: switch to hooking renderWindow and inserting a pass beforehand
This commit is contained in:
parent
734911c395
commit
81723f4cca
206
src/main.cpp
206
src/main.cpp
@ -3,13 +3,17 @@
|
|||||||
|
|
||||||
#include <hyprgraphics/color/Color.hpp>
|
#include <hyprgraphics/color/Color.hpp>
|
||||||
// version.hpp will be generated by meson
|
// version.hpp will be generated by meson
|
||||||
|
#include "src/plugins/PluginAPI.hpp"
|
||||||
|
#include "src/render/Framebuffer.hpp"
|
||||||
#include "src/render/Shader.hpp"
|
#include "src/render/Shader.hpp"
|
||||||
|
#include "src/render/pass/PassElement.hpp"
|
||||||
|
#include "src/render/pass/RectPassElement.hpp"
|
||||||
#include "version.hpp"
|
#include "version.hpp"
|
||||||
|
|
||||||
#include <hyprland/src/Compositor.hpp>
|
#include <hyprland/src/Compositor.hpp>
|
||||||
#include <hyprland/src/desktop/Window.hpp>
|
#include <hyprland/src/desktop/Window.hpp>
|
||||||
#include <hyprland/src/render/Renderer.hpp>
|
#include <hyprland/src/render/Renderer.hpp>
|
||||||
#include <hyprland/src/render/Transformer.hpp>
|
#include <hyprutils/math/Region.hpp>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
// Do NOT change this function.
|
// Do NOT change this function.
|
||||||
@ -17,140 +21,82 @@ APICALL EXPORT std::string PLUGIN_API_VERSION() {
|
|||||||
return HYPRLAND_API_VERSION;
|
return HYPRLAND_API_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
class CWindowTransformer: public IWindowTransformer {
|
class CBindOwnFramebuffer final: public IPassElement {
|
||||||
public:
|
public:
|
||||||
virtual CFramebuffer* transform(CFramebuffer* in);
|
explicit CBindOwnFramebuffer(CFramebuffer m_framebuffer) :
|
||||||
virtual void preWindowRender(CSurfacePassElement::SRenderData* pRenderData);
|
m_framebuffer(std::move(m_framebuffer)) {}
|
||||||
|
|
||||||
|
void draw(const CRegion& damage);
|
||||||
|
|
||||||
|
bool needsLiveBlur() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool needsPrecomputeBlur() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* passName() {
|
||||||
|
return "BIND_OWN_FRAMEBUFFER";
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float m_rot = 0;
|
CFramebuffer m_framebuffer;
|
||||||
Vector2D m_prevPos;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<CWindowTransformer*> ptrs;
|
|
||||||
|
|
||||||
void renderTex(CBox monbox, CTexture& tex, float rot) {
|
|
||||||
if (g_pHyprOpenGL->m_renderData.damage.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
CBox newBox = monbox.scale(g_pHyprOpenGL->m_renderData.renderModif.combinedScale());
|
|
||||||
g_pHyprOpenGL->m_renderData.renderModif.applyToBox(newBox);
|
|
||||||
|
|
||||||
Mat3x3 matrix = g_pHyprOpenGL->m_renderData.monitorProjection.projectBox(
|
|
||||||
monbox,
|
|
||||||
wlTransformToHyprutils(invertTransform(WL_OUTPUT_TRANSFORM_NORMAL)),
|
|
||||||
rot
|
|
||||||
);
|
|
||||||
Mat3x3 glMatrix = g_pHyprOpenGL->m_renderData.projection.copy().multiply(matrix);
|
|
||||||
|
|
||||||
SShader* shader = &g_pHyprOpenGL->m_shaders->m_shPASSTHRURGBA;
|
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
glBindTexture(tex.m_target, tex.m_texID);
|
|
||||||
|
|
||||||
glUseProgram(shader->program);
|
|
||||||
|
|
||||||
glUniformMatrix3fv(
|
|
||||||
shader->uniformLocations[SHADER_PROJ],
|
|
||||||
1,
|
|
||||||
GL_TRUE,
|
|
||||||
glMatrix.getMatrix().data()
|
|
||||||
);
|
|
||||||
glUniform1i(shader->uniformLocations[SHADER_TEX], 0);
|
|
||||||
|
|
||||||
const auto TOPLEFT = Vector2D(newBox.x, newBox.y);
|
|
||||||
const auto FULLSIZE = Vector2D(newBox.width, newBox.height);
|
|
||||||
|
|
||||||
glUniform2f(shader->uniformLocations[SHADER_TOP_LEFT], TOPLEFT.x, TOPLEFT.y);
|
|
||||||
glUniform2f(shader->uniformLocations[SHADER_FULL_SIZE], FULLSIZE.x, FULLSIZE.y);
|
|
||||||
glUniform1f(shader->uniformLocations[SHADER_RADIUS], 0);
|
|
||||||
|
|
||||||
glUniform1i(shader->uniformLocations[SHADER_DISCARD_OPAQUE], 0);
|
|
||||||
glUniform1i(shader->uniformLocations[SHADER_DISCARD_ALPHA], 0);
|
|
||||||
|
|
||||||
glUniform1f(shader->uniformLocations[SHADER_ALPHA], 1);
|
|
||||||
|
|
||||||
glVertexAttribPointer(
|
|
||||||
shader->uniformLocations[SHADER_POS_ATTRIB],
|
|
||||||
2,
|
|
||||||
GL_FLOAT,
|
|
||||||
GL_FALSE,
|
|
||||||
0,
|
|
||||||
fullVerts
|
|
||||||
);
|
|
||||||
glVertexAttribPointer(
|
|
||||||
shader->uniformLocations[SHADER_TEX_ATTRIB],
|
|
||||||
2,
|
|
||||||
GL_FLOAT,
|
|
||||||
GL_FALSE,
|
|
||||||
0,
|
|
||||||
fullVerts
|
|
||||||
);
|
|
||||||
|
|
||||||
glEnableVertexAttribArray(shader->uniformLocations[SHADER_POS_ATTRIB]);
|
|
||||||
glEnableVertexAttribArray(shader->uniformLocations[SHADER_TEX_ATTRIB]);
|
|
||||||
|
|
||||||
for (auto& RECT : g_pHyprOpenGL->m_renderData.damage.getRects()) {
|
|
||||||
g_pHyprOpenGL->scissor(&RECT);
|
|
||||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_pHyprOpenGL->scissor(nullptr);
|
|
||||||
|
|
||||||
glDisableVertexAttribArray(shader->uniformLocations[SHADER_POS_ATTRIB]);
|
|
||||||
glDisableVertexAttribArray(shader->uniformLocations[SHADER_TEX_ATTRIB]);
|
|
||||||
|
|
||||||
glBindTexture(tex.m_target, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CWindowTransformer::preWindowRender(CSurfacePassElement::SRenderData* pRenderData) {
|
|
||||||
auto&& newPos = pRenderData->pos;
|
|
||||||
|
|
||||||
auto delta = newPos - m_prevPos;
|
|
||||||
|
|
||||||
m_rot = delta.x * 0.01f;
|
|
||||||
std::println("delta.x: {}", delta.x);
|
|
||||||
|
|
||||||
// pRenderData->pos.x += 50;
|
|
||||||
pRenderData->rounding = 5;
|
|
||||||
pRenderData->alpha = 0.9;
|
|
||||||
|
|
||||||
m_prevPos = newPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
CFramebuffer* CWindowTransformer::transform(CFramebuffer* in) {
|
|
||||||
static CFramebuffer off;
|
|
||||||
|
|
||||||
if (!off.isAllocated() || off.m_size != in->m_size) {
|
|
||||||
off.release();
|
|
||||||
off.alloc(in->m_size.x, in->m_size.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
off.bind();
|
|
||||||
g_pHyprOpenGL->clear(CHyprColor {0, 0, 0, 0});
|
|
||||||
|
|
||||||
CBox monbox = {// m_prevPos.x,
|
|
||||||
// m_prevPos.y,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
g_pHyprOpenGL->m_renderData.pMonitor->m_transformedSize.x,
|
|
||||||
g_pHyprOpenGL->m_renderData.pMonitor->m_transformedSize.y
|
|
||||||
};
|
|
||||||
|
|
||||||
renderTex(monbox, *in->getTexture(), m_rot);
|
|
||||||
|
|
||||||
return &off;
|
|
||||||
}
|
|
||||||
|
|
||||||
void onNewWindow(std::any data) {
|
void onNewWindow(std::any data) {
|
||||||
// data is guaranteed
|
// data is guaranteed
|
||||||
auto PWINDOW = std::any_cast<PHLWINDOW>(data);
|
auto PWINDOW = std::any_cast<PHLWINDOW>(data);
|
||||||
ptrs.push_back(static_cast<CWindowTransformer*>(
|
|
||||||
PWINDOW->m_transformers.emplace_back(new CWindowTransformer {}).get()
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static SP<HOOK_CALLBACK_FN> g_p = nullptr;
|
static SP<HOOK_CALLBACK_FN> g_openWindow = nullptr;
|
||||||
|
inline CFunctionHook* g_pRenderWindowHook = nullptr;
|
||||||
|
|
||||||
|
typedef void (*origRenderWindow)(
|
||||||
|
void*,
|
||||||
|
PHLWINDOW,
|
||||||
|
PHLMONITOR,
|
||||||
|
const Time::steady_tp&,
|
||||||
|
bool,
|
||||||
|
eRenderPassMode,
|
||||||
|
bool,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
|
||||||
|
void hkRenderWindow(
|
||||||
|
void* thisptr,
|
||||||
|
PHLWINDOW pWindow,
|
||||||
|
PHLMONITOR pMonitor,
|
||||||
|
const Time::steady_tp& time,
|
||||||
|
bool decorate,
|
||||||
|
eRenderPassMode mode,
|
||||||
|
bool ignorePosition = false,
|
||||||
|
bool standalone = false
|
||||||
|
) {
|
||||||
|
std::println("renderWindow hooked!");
|
||||||
|
CHyprRenderer* pRenderer = (CHyprRenderer*)thisptr;
|
||||||
|
|
||||||
|
CBox monbox =
|
||||||
|
{pWindow->m_position.x, pWindow->m_position.y, pWindow->m_size.x, pWindow->m_size.y};
|
||||||
|
|
||||||
|
// test that it works
|
||||||
|
CRectPassElement::SRectData data;
|
||||||
|
data.color = CHyprColor(1, 0, 0, 0.2f);
|
||||||
|
data.box = monbox;
|
||||||
|
pRenderer->m_renderPass.add(makeUnique<CRectPassElement>(data));
|
||||||
|
|
||||||
|
// then call the original...
|
||||||
|
(*(origRenderWindow)g_pRenderWindowHook->m_original)(
|
||||||
|
thisptr,
|
||||||
|
pWindow,
|
||||||
|
pMonitor,
|
||||||
|
time,
|
||||||
|
decorate,
|
||||||
|
mode,
|
||||||
|
ignorePosition,
|
||||||
|
standalone
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
||||||
PHANDLE = handle;
|
PHANDLE = handle;
|
||||||
@ -169,12 +115,17 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
|||||||
throw std::runtime_error("[WiggleWobble] Version mismatch");
|
throw std::runtime_error("[WiggleWobble] Version mismatch");
|
||||||
}
|
}
|
||||||
|
|
||||||
g_p = HyprlandAPI::registerCallbackDynamic(
|
g_openWindow = HyprlandAPI::registerCallbackDynamic(
|
||||||
PHANDLE,
|
PHANDLE,
|
||||||
"openWindow",
|
"openWindow",
|
||||||
[](void* self, SCallbackInfo& info, std::any data) { onNewWindow(data); }
|
[](void* self, SCallbackInfo& info, std::any data) { onNewWindow(data); }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
static const auto METHODS = HyprlandAPI::findFunctionsByName(PHANDLE, "renderWindow");
|
||||||
|
g_pRenderWindowHook =
|
||||||
|
HyprlandAPI::createFunctionHook(handle, METHODS[0].address, (void*)&hkRenderWindow);
|
||||||
|
g_pRenderWindowHook->hook();
|
||||||
|
|
||||||
HyprlandAPI::reloadConfig();
|
HyprlandAPI::reloadConfig();
|
||||||
|
|
||||||
HyprlandAPI::addNotification(
|
HyprlandAPI::addNotification(
|
||||||
@ -188,5 +139,6 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
APICALL EXPORT void PLUGIN_EXIT() {
|
APICALL EXPORT void PLUGIN_EXIT() {
|
||||||
g_p = nullptr;
|
g_pRenderWindowHook = nullptr;
|
||||||
|
g_openWindow = nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user