mirror of
https://git.allpurposem.at/mat/WiggleWobble.git
synced 2025-12-23 21:11:29 +01:00
feat: add working wobble! but there's a ton of rendering weirdness
This commit is contained in:
parent
168c43269e
commit
92438a9bce
187
src/main.cpp
187
src/main.cpp
@ -1,18 +1,21 @@
|
|||||||
#include "globals.hpp"
|
#include "globals.hpp"
|
||||||
|
|
||||||
#include <GLES3/gl32.h>
|
#include <GLES3/gl32.h>
|
||||||
#include <algorithm>
|
|
||||||
#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/OpenGL.hpp"
|
|
||||||
#include "src/render/pass/PassElement.hpp"
|
|
||||||
#include "version.hpp"
|
#include "version.hpp"
|
||||||
|
|
||||||
#include <hyprland/src/Compositor.hpp>
|
#include <hyprland/src/Compositor.hpp>
|
||||||
|
#include <hyprland/src/desktop/DesktopTypes.hpp>
|
||||||
#include <hyprland/src/desktop/Window.hpp>
|
#include <hyprland/src/desktop/Window.hpp>
|
||||||
|
#include <hyprland/src/helpers/Monitor.hpp>
|
||||||
|
#include <hyprland/src/helpers/time/Time.hpp>
|
||||||
|
#include <hyprland/src/managers/input/InputManager.hpp>
|
||||||
|
#include <hyprland/src/plugins/PluginAPI.hpp>
|
||||||
|
#include <hyprland/src/render/Framebuffer.hpp>
|
||||||
|
#include <hyprland/src/render/OpenGL.hpp>
|
||||||
#include <hyprland/src/render/Renderer.hpp>
|
#include <hyprland/src/render/Renderer.hpp>
|
||||||
|
#include <hyprland/src/render/pass/PassElement.hpp>
|
||||||
#include <hyprutils/math/Box.hpp>
|
#include <hyprutils/math/Box.hpp>
|
||||||
#include <hyprutils/math/Region.hpp>
|
#include <hyprutils/math/Region.hpp>
|
||||||
#include <hyprutils/math/Vector2D.hpp>
|
#include <hyprutils/math/Vector2D.hpp>
|
||||||
@ -27,10 +30,11 @@ APICALL EXPORT std::string PLUGIN_API_VERSION() {
|
|||||||
|
|
||||||
SShader* g_shader {};
|
SShader* g_shader {};
|
||||||
|
|
||||||
constexpr unsigned int g_SUBDIVS = 2;
|
constexpr unsigned int g_SUBDIVS = 8;
|
||||||
static_assert(g_SUBDIVS > 0);
|
static_assert(g_SUBDIVS > 0);
|
||||||
|
|
||||||
GLuint g_VAO, g_VBO, g_VBO_UVs, g_EBO;
|
GLuint g_VAO, g_VBO, g_VBO_UVs, g_EBO;
|
||||||
|
std::vector<float> g_baseVerts;
|
||||||
unsigned int g_indexCount = 0;
|
unsigned int g_indexCount = 0;
|
||||||
|
|
||||||
class CBindOwnFramebufferPassElement final: public IPassElement {
|
class CBindOwnFramebufferPassElement final: public IPassElement {
|
||||||
@ -66,6 +70,95 @@ class CBindOwnFramebufferPassElement final: public IPassElement {
|
|||||||
CFramebuffer* m_pFramebuffer;
|
CFramebuffer* m_pFramebuffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
float map_value_in_range(
|
||||||
|
float value,
|
||||||
|
float inMin,
|
||||||
|
float inMax,
|
||||||
|
float outMin = 0.0,
|
||||||
|
float outMax = 1.0
|
||||||
|
) {
|
||||||
|
return (value - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = 8.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 = 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];
|
||||||
|
|
||||||
|
auto&& directionToTarget = targetPosition - particlePositon;
|
||||||
|
|
||||||
|
if (m_grabPosition.has_value()) {
|
||||||
|
auto&& distanceToDragPosition = m_grabPosition.value().distance(particlePositon);
|
||||||
|
auto&& dragStrength = std::clamp((float)distanceToDragPosition, 0.f, 1.f);
|
||||||
|
|
||||||
|
particle.position += m_windowMovement * dragStrength;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto&& springForce =
|
||||||
|
directionToTarget * s_springStrength - particle.velocity * s_dampingStrength;
|
||||||
|
particle.velocity += springForce * dt;
|
||||||
|
|
||||||
|
// Apply drag
|
||||||
|
auto&& 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalVel.distanceSq(Vector2D {}) < 0.1f;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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 {
|
class CRenderWobblyWindowPassElement final: public IPassElement {
|
||||||
public:
|
public:
|
||||||
explicit CRenderWobblyWindowPassElement(CFramebuffer* pOldFramebuffer, PHLWINDOWREF pWindow) :
|
explicit CRenderWobblyWindowPassElement(CFramebuffer* pOldFramebuffer, PHLWINDOWREF pWindow) :
|
||||||
@ -102,6 +195,7 @@ class CRenderWobblyWindowPassElement final: public IPassElement {
|
|||||||
GLCALL(glBindVertexArray(g_VAO));
|
GLCALL(glBindVertexArray(g_VAO));
|
||||||
GLCALL(glBindBuffer(GL_ARRAY_BUFFER, g_VBO));
|
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 UVTopLeft = Vector2D {windowBox.x, windowBox.y} / pWindowFB->m_size;
|
||||||
const Vector2D UVBottomRight =
|
const Vector2D UVBottomRight =
|
||||||
Vector2D {windowBox.x + windowBox.width, windowBox.y + windowBox.height}
|
Vector2D {windowBox.x + windowBox.width, windowBox.y + windowBox.height}
|
||||||
@ -126,6 +220,21 @@ class CRenderWobblyWindowPassElement final: public IPassElement {
|
|||||||
GLCALL(glBindBuffer(GL_ARRAY_BUFFER, g_VBO_UVs));
|
GLCALL(glBindBuffer(GL_ARRAY_BUFFER, g_VBO_UVs));
|
||||||
GLCALL(glBufferSubData(GL_ARRAY_BUFFER, 0, UVs.size() * sizeof(float), UVs.data()));
|
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: 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()));
|
||||||
|
}
|
||||||
|
|
||||||
GLCALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_EBO));
|
GLCALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_EBO));
|
||||||
GLCALL(glDrawElements(GL_TRIANGLE_STRIP, g_indexCount, GL_UNSIGNED_INT, 0));
|
GLCALL(glDrawElements(GL_TRIANGLE_STRIP, g_indexCount, GL_UNSIGNED_INT, 0));
|
||||||
|
|
||||||
@ -154,13 +263,10 @@ class CRenderWobblyWindowPassElement final: public IPassElement {
|
|||||||
PHLWINDOWREF m_pWindow;
|
PHLWINDOWREF m_pWindow;
|
||||||
};
|
};
|
||||||
|
|
||||||
void onNewWindow(std::any data) {
|
void registerWindow(PHLWINDOW pWindow) {
|
||||||
// data is guaranteed
|
g_windowPositions[pWindow] = pWindow->m_realPosition->value();
|
||||||
auto PWINDOW = std::any_cast<PHLWINDOW>(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::map<PHLWINDOWREF, CFramebuffer> g_windowFramebuffers;
|
|
||||||
|
|
||||||
static SP<HOOK_CALLBACK_FN> g_openWindow = nullptr;
|
static SP<HOOK_CALLBACK_FN> g_openWindow = nullptr;
|
||||||
inline CFunctionHook* g_pRenderWindowHook = nullptr;
|
inline CFunctionHook* g_pRenderWindowHook = nullptr;
|
||||||
|
|
||||||
@ -188,11 +294,40 @@ void hkRenderWindow(
|
|||||||
CHyprRenderer* pRenderer = (CHyprRenderer*)thisptr;
|
CHyprRenderer* pRenderer = (CHyprRenderer*)thisptr;
|
||||||
|
|
||||||
const bool shouldWobble = [&]() -> bool {
|
const bool shouldWobble = [&]() -> bool {
|
||||||
if (mode == RENDER_PASS_MAIN or mode == RENDER_PASS_ALL) {
|
if (mode != RENDER_PASS_MAIN and mode != RENDER_PASS_ALL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// did the window move
|
||||||
|
if (const auto pos = pWindow->m_realPosition->value(); pos != g_windowPositions[pWindow]) {
|
||||||
|
auto&& wobble = g_wobblyWindows[pWindow];
|
||||||
|
|
||||||
|
const auto windowBox = pWindow->getFullWindowBoundingBox();
|
||||||
|
const auto windowSize = Vector2D {windowBox.width, windowBox.height};
|
||||||
|
|
||||||
|
if (g_pInputManager->m_currentlyDraggedWindow == pWindow) {
|
||||||
|
if (not wobble.m_grabPosition.has_value()) {
|
||||||
|
auto&& mousePos = g_pInputManager->getMouseCoordsInternal();
|
||||||
|
wobble.m_grabPosition = (mousePos - pos) / windowSize;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
wobble.m_grabPosition = std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
wobble.m_windowMovement = (pos - g_windowPositions[pWindow]) / windowSize;
|
||||||
|
for (auto&& particle : wobble.m_particles) {
|
||||||
|
particle.position -= wobble.m_windowMovement;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update last pos
|
||||||
|
g_windowPositions[pWindow] = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_wobblyWindows.contains(pWindow)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return true;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
auto* const pOldFramebuffer = g_pHyprOpenGL->m_renderData.currentFB;
|
auto* const pOldFramebuffer = g_pHyprOpenGL->m_renderData.currentFB;
|
||||||
@ -232,6 +367,10 @@ void hkRenderWindow(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (shouldWobble) {
|
if (shouldWobble) {
|
||||||
|
const bool shouldStop = g_wobblyWindows[pWindow].step(time);
|
||||||
|
if (shouldStop)
|
||||||
|
g_wobblyWindows.erase(pWindow);
|
||||||
|
|
||||||
pRenderer->m_renderPass.add(
|
pRenderer->m_renderPass.add(
|
||||||
makeUnique<CRenderWobblyWindowPassElement>(pOldFramebuffer, pWindow)
|
makeUnique<CRenderWobblyWindowPassElement>(pOldFramebuffer, pWindow)
|
||||||
);
|
);
|
||||||
@ -243,14 +382,13 @@ void initGPUObjects() {
|
|||||||
|
|
||||||
// std::vector<float> finalVerts;
|
// std::vector<float> finalVerts;
|
||||||
const unsigned int vertsPerRow = g_SUBDIVS + 1;
|
const unsigned int vertsPerRow = g_SUBDIVS + 1;
|
||||||
std::vector<float> verts;
|
g_baseVerts.reserve(vertsPerRow * vertsPerRow * 2);
|
||||||
verts.reserve(vertsPerRow * vertsPerRow * 2);
|
|
||||||
|
|
||||||
const float step = 1.f / (g_SUBDIVS);
|
const float step = 1.f / (g_SUBDIVS);
|
||||||
for (unsigned int y = 0; y < vertsPerRow; ++y) {
|
for (unsigned int y = 0; y < vertsPerRow; ++y) {
|
||||||
for (unsigned int x = 0; x < vertsPerRow; ++x) {
|
for (unsigned int x = 0; x < vertsPerRow; ++x) {
|
||||||
verts.push_back(x * step);
|
g_baseVerts.push_back(x * step);
|
||||||
verts.push_back(y * step);
|
g_baseVerts.push_back(y * step);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,8 +427,8 @@ void initGPUObjects() {
|
|||||||
{
|
{
|
||||||
GLCALL(glBufferData(
|
GLCALL(glBufferData(
|
||||||
GL_ARRAY_BUFFER,
|
GL_ARRAY_BUFFER,
|
||||||
verts.size() * sizeof(float),
|
g_baseVerts.size() * sizeof(float),
|
||||||
verts.data(),
|
g_baseVerts.data(),
|
||||||
GL_DYNAMIC_DRAW
|
GL_DYNAMIC_DRAW
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -309,8 +447,8 @@ void initGPUObjects() {
|
|||||||
{
|
{
|
||||||
GLCALL(glBufferData(
|
GLCALL(glBufferData(
|
||||||
GL_ARRAY_BUFFER,
|
GL_ARRAY_BUFFER,
|
||||||
verts.size() * sizeof(float),
|
g_baseVerts.size() * sizeof(float),
|
||||||
verts.data(),
|
g_baseVerts.data(),
|
||||||
GL_DYNAMIC_DRAW
|
GL_DYNAMIC_DRAW
|
||||||
)); // Initial dummy UVs
|
)); // Initial dummy UVs
|
||||||
GLCALL(glEnableVertexAttribArray(g_shader->uniformLocations[SHADER_TEX_ATTRIB]));
|
GLCALL(glEnableVertexAttribArray(g_shader->uniformLocations[SHADER_TEX_ATTRIB]));
|
||||||
@ -347,10 +485,15 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
|||||||
|
|
||||||
initGPUObjects();
|
initGPUObjects();
|
||||||
|
|
||||||
|
for (auto&& window : g_pCompositor->m_windows)
|
||||||
|
registerWindow(window);
|
||||||
|
|
||||||
g_openWindow = 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) {
|
||||||
|
registerWindow(std::any_cast<PHLWINDOW>(data));
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
static const auto METHODS = HyprlandAPI::findFunctionsByName(PHANDLE, "renderWindow");
|
static const auto METHODS = HyprlandAPI::findFunctionsByName(PHANDLE, "renderWindow");
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user