chore: refactor to multiple files

This commit is contained in:
Matias 2025-07-16 22:28:08 +02:00
parent 28fd76c147
commit 8211583606
No known key found for this signature in database
GPG Key ID: ED35A6AC65A06B69
10 changed files with 400 additions and 416 deletions

View File

@ -1,29 +0,0 @@
#pragma once
#define WLR_USE_UNSTABLE
#include <hyprland/src/render/decorations/IHyprWindowDecoration.hpp>
class CCustomDecoration : public IHyprWindowDecoration {
public:
CCustomDecoration(CWindow*);
virtual ~CCustomDecoration();
virtual SWindowDecorationExtents getWindowDecorationExtents();
virtual void draw(CMonitor*, float a, const Vector2D& offset);
virtual eDecorationType getDecorationType();
virtual void updateWindow(CWindow*);
virtual void damageEntire();
private:
SWindowDecorationExtents m_seExtents;
CWindow* m_pWindow = nullptr;
Vector2D m_vLastWindowPos;
Vector2D m_vLastWindowSize;
};

View File

@ -1,32 +0,0 @@
#pragma once
#define WLR_USE_UNSTABLE
#include <hyprland/src/layout/IHyprLayout.hpp>
struct SWindowData {
CWindow* pWindow = nullptr;
};
class CHyprCustomLayout : public IHyprLayout {
public:
virtual void onWindowCreatedTiling(CWindow*);
virtual void onWindowRemovedTiling(CWindow*);
virtual bool isWindowTiled(CWindow*);
virtual void recalculateMonitor(const int&);
virtual void recalculateWindow(CWindow*);
virtual void resizeActiveWindow(const Vector2D&, CWindow* pWindow = nullptr);
virtual void fullscreenRequestForWindow(CWindow*, eFullscreenMode, bool);
virtual std::any layoutMessage(SLayoutMessageHeader, std::string);
virtual SWindowRenderLayoutHints requestRenderHints(CWindow*);
virtual void switchWindows(CWindow*, CWindow*);
virtual void alterSplitRatio(CWindow*, float, bool);
virtual std::string getLayoutName();
virtual void replaceWindowDataWith(CWindow* from, CWindow* to);
virtual void onEnable();
virtual void onDisable();
private:
std::vector<SWindowData> m_vWindowData;
};

17
include/globals.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef WW_GLOBALS_H
#define WW_GLOBALS_H
#include <hyprland/src/desktop/DesktopTypes.hpp>
#include <hyprland/src/plugins/PluginAPI.hpp>
#include <hyprland/src/render/Framebuffer.hpp>
#include <map>
inline HANDLE PHANDLE = nullptr;
class CWobblyWindow;
extern std::map<PHLWINDOWREF, CFramebuffer> g_windowFramebuffers;
extern std::map<PHLWINDOWREF, Vector2D> g_windowPositions;
extern std::map<PHLWINDOWREF, CWobblyWindow> g_wobblyWindows;
#endif

View File

@ -1,5 +0,0 @@
#pragma once
#include <hyprland/src/plugins/PluginAPI.hpp>
inline HANDLE PHANDLE = nullptr;

85
include/renderpasses.h Normal file
View File

@ -0,0 +1,85 @@
#ifndef WW_RENDERPASSES_H
#define WW_RENDERPASSES_H
#include <hyprland/src/desktop/Window.hpp>
#include <hyprland/src/render/Framebuffer.hpp>
#include <hyprland/src/render/OpenGL.hpp>
#include <hyprland/src/render/pass/PassElement.hpp>
class CBindOwnFramebufferPassElement final: public IPassElement {
public:
explicit CBindOwnFramebufferPassElement(CFramebuffer* pFramebuffer) :
m_pFramebuffer {pFramebuffer} {}
void draw(const CRegion& damage) override;
bool needsLiveBlur() override {
return false;
}
bool needsPrecomputeBlur() override {
return false;
}
const char* passName() override {
return "BIND_OWN_FRAMEBUFFER";
}
std::optional<CBox> boundingBox() override {
return std::nullopt;
}
CRegion opaqueRegion() override {
return CRegion {};
}
private:
CFramebuffer* m_pFramebuffer;
};
class CRenderWobblyWindowPassElement final: public IPassElement {
static inline SShader* s_shader {};
static inline constexpr unsigned int s_SUBDIVS = 8;
static_assert(s_SUBDIVS > 0);
static inline GLuint s_VAO, s_VBO, s_VBO_UVs, s_EBO;
public:
static inline std::vector<float> s_baseVerts;
explicit CRenderWobblyWindowPassElement(CFramebuffer* pOldFramebuffer, PHLWINDOWREF pWindow) :
m_pOldFramebuffer {pOldFramebuffer},
m_pWindow {pWindow} {}
static void initGPUObjects();
void draw(const CRegion& damage) override;
bool needsLiveBlur() override {
return true;
}
bool needsPrecomputeBlur() override {
return false;
}
const char* passName() override {
return "RENDER_WOBBLY_WINDOW";
}
std::optional<CBox> boundingBox() override {
return g_pHyprOpenGL->m_renderData.pMonitor->logicalBox();
}
CRegion opaqueRegion() override {
return CRegion {};
}
private:
CFramebuffer* m_pOldFramebuffer;
PHLWINDOWREF m_pWindow;
static inline SShader* s_pShader = nullptr;
};
#endif

32
include/wobblywindow.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef WW_WOBBLYWINDOW_H
#define WW_WOBBLYWINDOW_H
#include "renderpasses.h"
#include <hyprland/src/Compositor.hpp>
#include <hyprutils/math/Vector2D.hpp>
class CWobblyWindow {
struct SParticle {
Vector2D position;
Vector2D velocity;
};
Time::steady_tp m_lastTime {Time::steadyNow()};
public:
// static wobble parameters
static inline float s_springStrength = 500.f;
static inline float s_dampingStrength = 12.f;
static inline float s_drag = 0.4f;
std::vector<SParticle> m_particles;
std::vector<Vector2D> m_targetPositions;
std::optional<Vector2D> m_grabPosition {std::nullopt};
Vector2D m_windowMovement;
CWobblyWindow();
bool step(Time::steady_tp time);
};
#endif

View File

@ -1,12 +1,12 @@
#include "globals.hpp"
#include "globals.h"
#include "renderpasses.h"
#include "version.hpp" // generated by meson
#include "wobblywindow.h"
#include <GLES3/gl32.h>
#include <any>
#include <cmath>
#include <hyprgraphics/color/Color.hpp>
// version.hpp will be generated by meson
#include "version.hpp"
#include <hyprland/src/Compositor.hpp>
#include <hyprland/src/desktop/DesktopTypes.hpp>
#include <hyprland/src/desktop/Window.hpp>
@ -30,261 +30,9 @@ APICALL EXPORT std::string PLUGIN_API_VERSION() {
return HYPRLAND_API_VERSION;
}
SShader* g_shader {};
constexpr unsigned int g_SUBDIVS = 8;
static_assert(g_SUBDIVS > 0);
GLuint g_VAO, g_VBO, g_VBO_UVs, g_EBO;
std::vector<float> g_baseVerts;
unsigned int g_indexCount = 0;
class CBindOwnFramebufferPassElement final: public IPassElement {
public:
explicit CBindOwnFramebufferPassElement(CFramebuffer* pFramebuffer) :
m_pFramebuffer {pFramebuffer} {}
void draw(const CRegion& damage) override {
m_pFramebuffer->bind();
g_pHyprOpenGL->m_renderData.currentFB = m_pFramebuffer;
GLCALL(glClearColor(0, 0, 0, 0));
GLCALL(glClear(GL_COLOR_BUFFER_BIT));
}
bool needsLiveBlur() override {
return false;
}
bool needsPrecomputeBlur() override {
return false;
}
const char* passName() override {
return "BIND_OWN_FRAMEBUFFER";
}
std::optional<CBox> boundingBox() override {
return std::nullopt;
}
CRegion opaqueRegion() override {
return CRegion {};
}
private:
CFramebuffer* m_pFramebuffer;
};
class CWobblyWindow {
struct SParticle {
Vector2D position;
Vector2D velocity;
};
Time::steady_tp m_lastTime {Time::steadyNow()};
public:
// static wobble parameters
static inline float s_springStrength = 500.f;
static inline float s_dampingStrength = 12.f;
static inline float s_drag = 0.4f;
std::vector<SParticle> m_particles;
std::vector<Vector2D> m_targetPositions;
std::optional<Vector2D> m_grabPosition {std::nullopt};
Vector2D m_windowMovement;
CWobblyWindow() {
m_particles.reserve(g_baseVerts.size() / 2);
m_targetPositions.reserve(g_baseVerts.size() / 2);
for (unsigned int i {}; i < g_baseVerts.size(); i += 2) {
m_particles.push_back(SParticle {Vector2D {g_baseVerts[i], g_baseVerts[i + 1]}, {}});
m_targetPositions.push_back(Vector2D {g_baseVerts[i], g_baseVerts[i + 1]});
}
}
bool step(Time::steady_tp time) {
const auto usec =
std::chrono::duration_cast<std::chrono::microseconds>(time - m_lastTime).count();
const float dt = std::min(0.016f, usec * 0.000001f);
m_lastTime = time;
Vector2D totalVel {};
for (unsigned int i {}; i < m_particles.size(); i++) {
auto&& particle = m_particles[i];
auto&& particlePositon = particle.position;
auto&& targetPosition = m_targetPositions[i];
const Vector2D directionToTarget = targetPosition - particlePositon;
if (m_grabPosition.has_value()) {
const float distanceToDragPosition =
m_grabPosition.value().distance(particlePositon);
const float dragStrength = std::clamp(distanceToDragPosition, 0.f, 1.f);
particle.position += m_windowMovement * dragStrength;
}
const Vector2D springForce =
directionToTarget * s_springStrength - particle.velocity * s_dampingStrength;
particle.velocity += springForce * dt;
// Apply drag
const Vector2D dragForceVector = (particle.velocity * particle.velocity) * -s_drag;
// * Area
auto dir = particle.velocity;
float magnitude = dir.normalize();
if (magnitude != 0)
particle.velocity += (dragForceVector * dir) * dt;
// Apply velocity
particle.position += particle.velocity * dt;
totalVel += particle.velocity;
}
const bool shouldEnd =
m_windowMovement.size() == 0 and totalVel.size() / m_particles.size() < .001f;
// std::println(
// "Top left: {}, totalVel: {}",
// m_particles[0].position,
// totalVel.size() / m_particles.size()
// );
m_windowMovement = Vector2D {};
return shouldEnd;
}
};
inline std::map<PHLWINDOWREF, CFramebuffer> g_windowFramebuffers;
inline std::map<PHLWINDOWREF, Vector2D> g_windowPositions;
inline std::map<PHLWINDOWREF, CWobblyWindow> g_wobblyWindows;
class CRenderWobblyWindowPassElement final: public IPassElement {
public:
explicit CRenderWobblyWindowPassElement(CFramebuffer* pOldFramebuffer, PHLWINDOWREF pWindow) :
m_pOldFramebuffer {pOldFramebuffer},
m_pWindow {pWindow} {}
void draw(const CRegion& damage) override {
auto* const pWindowFB = g_pHyprOpenGL->m_renderData.currentFB;
m_pOldFramebuffer->bind();
g_pHyprOpenGL->m_renderData.currentFB = m_pOldFramebuffer;
const auto windowBox = m_pWindow->getFullWindowBoundingBox();
CBox newBox = windowBox;
g_pHyprOpenGL->m_renderData.renderModif.applyToBox(newBox);
// get transform
const auto TRANSFORM =
wlTransformToHyprutils(invertTransform(g_pHyprOpenGL->m_renderData.pMonitor->m_transform
));
Mat3x3 matrix =
g_pHyprOpenGL->m_renderData.monitorProjection.projectBox(newBox, TRANSFORM, newBox.rot);
Mat3x3 glMatrix = g_pHyprOpenGL->m_renderData.projection.copy().multiply(matrix);
GLCALL(glActiveTexture(GL_TEXTURE0));
pWindowFB->getTexture()->bind();
g_pHyprOpenGL->useProgram(g_shader->program);
g_shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
g_shader->setUniformInt(SHADER_TEX, 0);
GLCALL(glBindVertexArray(g_VAO));
GLCALL(glBindBuffer(GL_ARRAY_BUFFER, g_VBO));
// TODO: can we avoid this entirely by rendering the window to framebuffer pos 0,0?
const Vector2D UVTopLeft = Vector2D {windowBox.x, windowBox.y} / pWindowFB->m_size;
const Vector2D UVBottomRight =
Vector2D {windowBox.x + windowBox.width, windowBox.y + windowBox.height}
/ pWindowFB->m_size;
const unsigned int vertsPerRow = g_SUBDIVS + 1;
std::vector<float> UVs;
UVs.reserve(vertsPerRow * vertsPerRow * 2);
const auto step = (UVBottomRight - UVTopLeft) / (g_SUBDIVS);
for (unsigned int y = 0; y < vertsPerRow; ++y) {
const float v = UVTopLeft.y + y * step.y;
for (unsigned int x = 0; x < vertsPerRow; ++x) {
const float u = UVTopLeft.x + x * step.x;
UVs.push_back(u);
UVs.push_back(v);
}
}
GLCALL(glBindBuffer(GL_ARRAY_BUFFER, g_VBO_UVs));
GLCALL(glBufferSubData(GL_ARRAY_BUFFER, 0, UVs.size() * sizeof(float), UVs.data()));
if (g_wobblyWindows.contains(m_pWindow)) {
auto&& wobble = g_wobblyWindows[m_pWindow];
// TODO: these should never be nan
// if (not std::isnan(wobble.m_particles[0].position.x)) {
// TODO: we need the particle positions in their own vec, to avoid this copy
std::vector<float> verts;
verts.reserve(vertsPerRow * vertsPerRow * 2);
for (auto&& particle : wobble.m_particles) {
verts.push_back(particle.position.x);
verts.push_back(particle.position.y);
}
GLCALL(glBindBuffer(GL_ARRAY_BUFFER, g_VBO));
GLCALL(glBufferSubData(GL_ARRAY_BUFFER, 0, verts.size() * sizeof(float), verts.data()));
// }
} else {
// restore default verts
GLCALL(glBindBuffer(GL_ARRAY_BUFFER, g_VBO));
GLCALL(glBufferSubData(
GL_ARRAY_BUFFER,
0,
g_baseVerts.size() * sizeof(float),
g_baseVerts.data()
));
}
GLCALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_EBO));
GLCALL(glDrawElements(GL_TRIANGLE_STRIP, g_indexCount, GL_UNSIGNED_INT, 0));
GLCALL(glBindVertexArray(0));
pWindowFB->getTexture()->unbind();
}
bool needsLiveBlur() override {
return true;
}
bool needsPrecomputeBlur() override {
return false;
}
const char* passName() override {
return "RENDER_WOBBLY_WINDOW";
}
std::optional<CBox> boundingBox() override {
return g_pHyprOpenGL->m_renderData.pMonitor->logicalBox();
}
CRegion opaqueRegion() override {
return CRegion {};
}
private:
CFramebuffer* m_pOldFramebuffer;
PHLWINDOWREF m_pWindow;
};
std::map<PHLWINDOWREF, CFramebuffer> g_windowFramebuffers;
std::map<PHLWINDOWREF, Vector2D> g_windowPositions;
std::map<PHLWINDOWREF, CWobblyWindow> g_wobblyWindows;
void registerWindow(PHLWINDOW pWindow) {
g_windowPositions[pWindow] = pWindow->m_realPosition->value();
@ -404,95 +152,6 @@ void hkRenderWindow(
}
}
void initGPUObjects() {
g_shader = &g_pHyprOpenGL->m_shaders->m_shRGBA;
// std::vector<float> finalVerts;
const unsigned int vertsPerRow = g_SUBDIVS + 1;
g_baseVerts.reserve(vertsPerRow * vertsPerRow * 2);
const float step = 1.f / (g_SUBDIVS);
for (unsigned int y = 0; y < vertsPerRow; ++y) {
for (unsigned int x = 0; x < vertsPerRow; ++x) {
g_baseVerts.push_back(x * step);
g_baseVerts.push_back(y * step);
}
}
std::vector<GLuint> indices;
g_indexCount = 3 * 2 * g_SUBDIVS * g_SUBDIVS;
indices.reserve(g_indexCount);
for (int y = 0; y < g_SUBDIVS; ++y) {
for (int x = 0; x < g_SUBDIVS; ++x) {
indices.push_back(y * vertsPerRow + x + 1); // top right
indices.push_back(y * vertsPerRow + x); // top left
indices.push_back((y + 1) * vertsPerRow + x + 1); // bottom right
indices.push_back(y * vertsPerRow + x); // top left
indices.push_back((y + 1) * vertsPerRow + x); // bottom left
indices.push_back((y + 1) * vertsPerRow + x + 1); // bottom right
}
}
GLCALL(glGenVertexArrays(1, &g_VAO));
GLCALL(glGenBuffers(1, &g_VBO));
GLCALL(glGenBuffers(1, &g_VBO_UVs));
GLCALL(glGenBuffers(1, &g_EBO));
GLCALL(glBindVertexArray(g_VAO));
GLCALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_EBO));
GLCALL(glBufferData(
GL_ELEMENT_ARRAY_BUFFER,
indices.size() * sizeof(GLuint),
indices.data(),
GL_STATIC_DRAW
));
GLCALL(glBindBuffer(GL_ARRAY_BUFFER, g_VBO));
{
GLCALL(glBufferData(
GL_ARRAY_BUFFER,
g_baseVerts.size() * sizeof(float),
g_baseVerts.data(),
GL_DYNAMIC_DRAW
));
GLCALL(glEnableVertexAttribArray(g_shader->uniformLocations[SHADER_POS_ATTRIB]));
GLCALL(glVertexAttribPointer(
g_shader->uniformLocations[SHADER_POS_ATTRIB],
2,
GL_FLOAT,
GL_FALSE,
0,
nullptr
));
}
GLCALL(glBindBuffer(GL_ARRAY_BUFFER, g_VBO_UVs));
{
GLCALL(glBufferData(
GL_ARRAY_BUFFER,
g_baseVerts.size() * sizeof(float),
g_baseVerts.data(),
GL_DYNAMIC_DRAW
)); // Initial dummy UVs
GLCALL(glEnableVertexAttribArray(g_shader->uniformLocations[SHADER_TEX_ATTRIB]));
GLCALL(glVertexAttribPointer(
g_shader->uniformLocations[SHADER_TEX_ATTRIB],
2,
GL_FLOAT,
GL_FALSE,
0,
nullptr
));
}
GLCALL(glBindVertexArray(0));
GLCALL(glBindBuffer(GL_ARRAY_BUFFER, 0));
}
APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
PHANDLE = handle;
@ -510,7 +169,7 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
throw std::runtime_error("[WiggleWobble] Version mismatch");
}
initGPUObjects();
CRenderWobblyWindowPassElement::initGPUObjects();
for (auto&& window : g_pCompositor->m_windows)
registerWindow(window);
@ -549,6 +208,7 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
}
APICALL EXPORT void PLUGIN_EXIT() {
// TODO: CRenderWobblyWindowPassElement::deinitGPUObjects();
g_pRenderWindowHook = nullptr;
g_openWindow = nullptr;
}

View File

@ -1,5 +1,5 @@
shared_module('wigglewobble',
'main.cpp',
['main.cpp','wobblywindow.cpp','renderpasses.cpp'],
cpp_args: ['-DWLR_USE_UNSTABLE'],
include_directories: incdir,
# sometimes you need to add other hyprland dependencies yourself

187
src/renderpasses.cpp Normal file
View File

@ -0,0 +1,187 @@
#include "renderpasses.h"
#include "globals.h"
#include "wobblywindow.h"
void CBindOwnFramebufferPassElement::draw(const CRegion& damage) {
m_pFramebuffer->bind();
g_pHyprOpenGL->m_renderData.currentFB = m_pFramebuffer;
GLCALL(glClearColor(0, 0, 0, 0));
GLCALL(glClear(GL_COLOR_BUFFER_BIT));
}
void CRenderWobblyWindowPassElement::initGPUObjects() {
s_pShader = &g_pHyprOpenGL->m_shaders->m_shRGBA;
const unsigned int vertsPerRow = s_SUBDIVS + 1;
s_baseVerts.reserve(vertsPerRow * vertsPerRow * 2);
const float step = 1.f / (s_SUBDIVS);
for (unsigned int y = 0; y < vertsPerRow; ++y) {
for (unsigned int x = 0; x < vertsPerRow; ++x) {
s_baseVerts.push_back(x * step);
s_baseVerts.push_back(y * step);
}
}
std::vector<GLuint> indices;
indices.reserve(3 * 2 * s_SUBDIVS * s_SUBDIVS);
for (int y = 0; y < s_SUBDIVS; ++y) {
for (int x = 0; x < s_SUBDIVS; ++x) {
indices.push_back(y * vertsPerRow + x + 1); // top right
indices.push_back(y * vertsPerRow + x); // top left
indices.push_back((y + 1) * vertsPerRow + x + 1); // bottom right
indices.push_back(y * vertsPerRow + x); // top left
indices.push_back((y + 1) * vertsPerRow + x); // bottom left
indices.push_back((y + 1) * vertsPerRow + x + 1); // bottom right
}
}
GLCALL(glGenVertexArrays(1, &s_VAO));
GLCALL(glGenBuffers(1, &s_VBO));
GLCALL(glGenBuffers(1, &s_VBO_UVs));
GLCALL(glGenBuffers(1, &s_EBO));
GLCALL(glBindVertexArray(s_VAO));
GLCALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s_EBO));
GLCALL(glBufferData(
GL_ELEMENT_ARRAY_BUFFER,
indices.size() * sizeof(GLuint),
indices.data(),
GL_STATIC_DRAW
));
GLCALL(glBindBuffer(GL_ARRAY_BUFFER, s_VBO));
{
GLCALL(glBufferData(
GL_ARRAY_BUFFER,
s_baseVerts.size() * sizeof(float),
s_baseVerts.data(),
GL_DYNAMIC_DRAW
));
GLCALL(glEnableVertexAttribArray(s_pShader->uniformLocations[SHADER_POS_ATTRIB]));
GLCALL(glVertexAttribPointer(
s_pShader->uniformLocations[SHADER_POS_ATTRIB],
2,
GL_FLOAT,
GL_FALSE,
0,
nullptr
));
}
GLCALL(glBindBuffer(GL_ARRAY_BUFFER, s_VBO_UVs));
{
GLCALL(glBufferData(
GL_ARRAY_BUFFER,
s_baseVerts.size() * sizeof(float),
s_baseVerts.data(),
GL_DYNAMIC_DRAW
)); // Initial dummy UVs
GLCALL(glEnableVertexAttribArray(s_pShader->uniformLocations[SHADER_TEX_ATTRIB]));
GLCALL(glVertexAttribPointer(
s_pShader->uniformLocations[SHADER_TEX_ATTRIB],
2,
GL_FLOAT,
GL_FALSE,
0,
nullptr
));
}
GLCALL(glBindVertexArray(0));
GLCALL(glBindBuffer(GL_ARRAY_BUFFER, 0));
}
void CRenderWobblyWindowPassElement::draw(const CRegion& damage) {
auto* const pWindowFB = g_pHyprOpenGL->m_renderData.currentFB;
m_pOldFramebuffer->bind();
g_pHyprOpenGL->m_renderData.currentFB = m_pOldFramebuffer;
const auto windowBox = m_pWindow->getFullWindowBoundingBox();
CBox newBox = windowBox;
g_pHyprOpenGL->m_renderData.renderModif.applyToBox(newBox);
// get transform
const auto TRANSFORM =
wlTransformToHyprutils(invertTransform(g_pHyprOpenGL->m_renderData.pMonitor->m_transform));
Mat3x3 matrix =
g_pHyprOpenGL->m_renderData.monitorProjection.projectBox(newBox, TRANSFORM, newBox.rot);
Mat3x3 glMatrix = g_pHyprOpenGL->m_renderData.projection.copy().multiply(matrix);
GLCALL(glActiveTexture(GL_TEXTURE0));
pWindowFB->getTexture()->bind();
g_pHyprOpenGL->useProgram(s_pShader->program);
s_pShader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
s_pShader->setUniformInt(SHADER_TEX, 0);
GLCALL(glBindVertexArray(s_VAO));
GLCALL(glBindBuffer(GL_ARRAY_BUFFER, s_VBO));
// TODO: can we avoid this entirely by rendering the window to framebuffer pos 0,0?
const Vector2D UVTopLeft = Vector2D {windowBox.x, windowBox.y} / pWindowFB->m_size;
const Vector2D UVBottomRight =
Vector2D {windowBox.x + windowBox.width, windowBox.y + windowBox.height}
/ pWindowFB->m_size;
const unsigned int vertsPerRow = s_SUBDIVS + 1;
std::vector<float> UVs;
UVs.reserve(vertsPerRow * vertsPerRow * 2);
const auto step = (UVBottomRight - UVTopLeft) / (s_SUBDIVS);
for (unsigned int y = 0; y < vertsPerRow; ++y) {
const float v = UVTopLeft.y + y * step.y;
for (unsigned int x = 0; x < vertsPerRow; ++x) {
const float u = UVTopLeft.x + x * step.x;
UVs.push_back(u);
UVs.push_back(v);
}
}
GLCALL(glBindBuffer(GL_ARRAY_BUFFER, s_VBO_UVs));
GLCALL(glBufferSubData(GL_ARRAY_BUFFER, 0, UVs.size() * sizeof(float), UVs.data()));
if (g_wobblyWindows.contains(m_pWindow)) {
auto&& wobble = g_wobblyWindows[m_pWindow];
// TODO: these should never be nan
// if (not std::isnan(wobble.m_particles[0].position.x)) {
// TODO: we need the particle positions in their own vec, to avoid this copy
std::vector<float> verts;
verts.reserve(vertsPerRow * vertsPerRow * 2);
for (auto&& particle : wobble.m_particles) {
verts.push_back(particle.position.x);
verts.push_back(particle.position.y);
}
GLCALL(glBindBuffer(GL_ARRAY_BUFFER, s_VBO));
GLCALL(glBufferSubData(GL_ARRAY_BUFFER, 0, verts.size() * sizeof(float), verts.data()));
// }
} else {
// restore default verts
GLCALL(glBindBuffer(GL_ARRAY_BUFFER, s_VBO));
GLCALL(glBufferSubData(
GL_ARRAY_BUFFER,
0,
s_baseVerts.size() * sizeof(float),
s_baseVerts.data()
));
}
GLCALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s_EBO));
GLCALL(glDrawElements(GL_TRIANGLE_STRIP, 3 * 2 * s_SUBDIVS * s_SUBDIVS, GL_UNSIGNED_INT, 0));
GLCALL(glBindVertexArray(0));
pWindowFB->getTexture()->unbind();
}

69
src/wobblywindow.cpp Normal file
View File

@ -0,0 +1,69 @@
#include "wobblywindow.h"
#include "globals.h"
CWobblyWindow::CWobblyWindow() {
auto&& verts = CRenderWobblyWindowPassElement::s_baseVerts;
m_particles.reserve(verts.size() / 2);
m_targetPositions.reserve(verts.size() / 2);
for (unsigned int i {}; i < verts.size(); i += 2) {
m_particles.push_back(SParticle {Vector2D {verts[i], verts[i + 1]}, {}});
m_targetPositions.push_back(Vector2D {verts[i], verts[i + 1]});
}
}
bool CWobblyWindow::step(Time::steady_tp time) {
const auto usec =
std::chrono::duration_cast<std::chrono::microseconds>(time - m_lastTime).count();
const float dt = std::min(0.016f, usec * 0.000001f);
m_lastTime = time;
Vector2D totalVel {};
for (unsigned int i {}; i < m_particles.size(); i++) {
auto&& particle = m_particles[i];
auto&& particlePositon = particle.position;
auto&& targetPosition = m_targetPositions[i];
const Vector2D directionToTarget = targetPosition - particlePositon;
if (m_grabPosition.has_value()) {
const float distanceToDragPosition = m_grabPosition.value().distance(particlePositon);
const float dragStrength = std::clamp(distanceToDragPosition, 0.f, 1.f);
particle.position += m_windowMovement * dragStrength;
}
const Vector2D springForce =
directionToTarget * s_springStrength - particle.velocity * s_dampingStrength;
particle.velocity += springForce * dt;
// Apply drag
const Vector2D dragForceVector = (particle.velocity * particle.velocity) * -s_drag;
// * Area
auto dir = particle.velocity;
float magnitude = dir.normalize();
if (magnitude != 0)
particle.velocity += (dragForceVector * dir) * dt;
// Apply velocity
particle.position += particle.velocity * dt;
totalVel += particle.velocity;
}
const bool shouldEnd =
m_windowMovement.size() == 0 and totalVel.size() / m_particles.size() < .001f;
// std::println(
// "Top left: {}, totalVel: {}",
// m_particles[0].position,
// totalVel.size() / m_particles.size()
// );
m_windowMovement = Vector2D {};
return shouldEnd;
}