diff --git a/include/customDecoration.hpp b/include/customDecoration.hpp deleted file mode 100644 index 4d89cfc..0000000 --- a/include/customDecoration.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#define WLR_USE_UNSTABLE - -#include - -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; -}; diff --git a/include/customLayout.hpp b/include/customLayout.hpp deleted file mode 100644 index 57d0770..0000000 --- a/include/customLayout.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#define WLR_USE_UNSTABLE - -#include - -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 m_vWindowData; -}; diff --git a/include/globals.h b/include/globals.h new file mode 100644 index 0000000..157da0a --- /dev/null +++ b/include/globals.h @@ -0,0 +1,17 @@ +#ifndef WW_GLOBALS_H +#define WW_GLOBALS_H + +#include +#include +#include +#include + +inline HANDLE PHANDLE = nullptr; + +class CWobblyWindow; + +extern std::map g_windowFramebuffers; +extern std::map g_windowPositions; +extern std::map g_wobblyWindows; + +#endif diff --git a/include/globals.hpp b/include/globals.hpp deleted file mode 100644 index 66c4f04..0000000 --- a/include/globals.hpp +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include - -inline HANDLE PHANDLE = nullptr; diff --git a/include/renderpasses.h b/include/renderpasses.h new file mode 100644 index 0000000..3535cb1 --- /dev/null +++ b/include/renderpasses.h @@ -0,0 +1,85 @@ +#ifndef WW_RENDERPASSES_H +#define WW_RENDERPASSES_H + +#include +#include +#include +#include + +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 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 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 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 diff --git a/include/wobblywindow.h b/include/wobblywindow.h new file mode 100644 index 0000000..11f0d02 --- /dev/null +++ b/include/wobblywindow.h @@ -0,0 +1,32 @@ +#ifndef WW_WOBBLYWINDOW_H +#define WW_WOBBLYWINDOW_H + +#include "renderpasses.h" + +#include +#include + +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 m_particles; + std::vector m_targetPositions; + std::optional m_grabPosition {std::nullopt}; + Vector2D m_windowMovement; + + CWobblyWindow(); + + bool step(Time::steady_tp time); +}; +#endif diff --git a/src/main.cpp b/src/main.cpp index 27776db..dd5b323 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,12 +1,12 @@ -#include "globals.hpp" +#include "globals.h" +#include "renderpasses.h" +#include "version.hpp" // generated by meson +#include "wobblywindow.h" #include #include #include #include -// version.hpp will be generated by meson -#include "version.hpp" - #include #include #include @@ -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 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 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 m_particles; - std::vector m_targetPositions; - std::optional 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(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 g_windowFramebuffers; -inline std::map g_windowPositions; -inline std::map 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 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 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 boundingBox() override { - return g_pHyprOpenGL->m_renderData.pMonitor->logicalBox(); - } - - CRegion opaqueRegion() override { - return CRegion {}; - } - - private: - CFramebuffer* m_pOldFramebuffer; - PHLWINDOWREF m_pWindow; -}; +std::map g_windowFramebuffers; +std::map g_windowPositions; +std::map 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 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 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; } diff --git a/src/meson.build b/src/meson.build index b866856..57b05bb 100644 --- a/src/meson.build +++ b/src/meson.build @@ -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 diff --git a/src/renderpasses.cpp b/src/renderpasses.cpp new file mode 100644 index 0000000..b052248 --- /dev/null +++ b/src/renderpasses.cpp @@ -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 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 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 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(); +} diff --git a/src/wobblywindow.cpp b/src/wobblywindow.cpp new file mode 100644 index 0000000..7de9e42 --- /dev/null +++ b/src/wobblywindow.cpp @@ -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(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; +}