mirror of
https://git.allpurposem.at/mat/WiggleWobble.git
synced 2025-12-23 13:01:28 +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 <GLES3/gl32.h>
|
||||
#include <algorithm>
|
||||
#include <hyprgraphics/color/Color.hpp>
|
||||
// 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 <hyprland/src/Compositor.hpp>
|
||||
#include <hyprland/src/desktop/DesktopTypes.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/pass/PassElement.hpp>
|
||||
#include <hyprutils/math/Box.hpp>
|
||||
#include <hyprutils/math/Region.hpp>
|
||||
#include <hyprutils/math/Vector2D.hpp>
|
||||
@ -27,10 +30,11 @@ APICALL EXPORT std::string PLUGIN_API_VERSION() {
|
||||
|
||||
SShader* g_shader {};
|
||||
|
||||
constexpr unsigned int g_SUBDIVS = 2;
|
||||
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 {
|
||||
@ -66,6 +70,95 @@ class CBindOwnFramebufferPassElement final: public IPassElement {
|
||||
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 {
|
||||
public:
|
||||
explicit CRenderWobblyWindowPassElement(CFramebuffer* pOldFramebuffer, PHLWINDOWREF pWindow) :
|
||||
@ -102,6 +195,7 @@ class CRenderWobblyWindowPassElement final: public IPassElement {
|
||||
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}
|
||||
@ -126,6 +220,21 @@ class CRenderWobblyWindowPassElement final: public IPassElement {
|
||||
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: 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(glDrawElements(GL_TRIANGLE_STRIP, g_indexCount, GL_UNSIGNED_INT, 0));
|
||||
|
||||
@ -154,13 +263,10 @@ class CRenderWobblyWindowPassElement final: public IPassElement {
|
||||
PHLWINDOWREF m_pWindow;
|
||||
};
|
||||
|
||||
void onNewWindow(std::any data) {
|
||||
// data is guaranteed
|
||||
auto PWINDOW = std::any_cast<PHLWINDOW>(data);
|
||||
void registerWindow(PHLWINDOW pWindow) {
|
||||
g_windowPositions[pWindow] = pWindow->m_realPosition->value();
|
||||
}
|
||||
|
||||
inline std::map<PHLWINDOWREF, CFramebuffer> g_windowFramebuffers;
|
||||
|
||||
static SP<HOOK_CALLBACK_FN> g_openWindow = nullptr;
|
||||
inline CFunctionHook* g_pRenderWindowHook = nullptr;
|
||||
|
||||
@ -188,11 +294,40 @@ void hkRenderWindow(
|
||||
CHyprRenderer* pRenderer = (CHyprRenderer*)thisptr;
|
||||
|
||||
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 false;
|
||||
return true;
|
||||
}();
|
||||
|
||||
auto* const pOldFramebuffer = g_pHyprOpenGL->m_renderData.currentFB;
|
||||
@ -232,6 +367,10 @@ void hkRenderWindow(
|
||||
);
|
||||
|
||||
if (shouldWobble) {
|
||||
const bool shouldStop = g_wobblyWindows[pWindow].step(time);
|
||||
if (shouldStop)
|
||||
g_wobblyWindows.erase(pWindow);
|
||||
|
||||
pRenderer->m_renderPass.add(
|
||||
makeUnique<CRenderWobblyWindowPassElement>(pOldFramebuffer, pWindow)
|
||||
);
|
||||
@ -243,14 +382,13 @@ void initGPUObjects() {
|
||||
|
||||
// std::vector<float> finalVerts;
|
||||
const unsigned int vertsPerRow = g_SUBDIVS + 1;
|
||||
std::vector<float> verts;
|
||||
verts.reserve(vertsPerRow * vertsPerRow * 2);
|
||||
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) {
|
||||
verts.push_back(x * step);
|
||||
verts.push_back(y * step);
|
||||
g_baseVerts.push_back(x * step);
|
||||
g_baseVerts.push_back(y * step);
|
||||
}
|
||||
}
|
||||
|
||||
@ -289,8 +427,8 @@ void initGPUObjects() {
|
||||
{
|
||||
GLCALL(glBufferData(
|
||||
GL_ARRAY_BUFFER,
|
||||
verts.size() * sizeof(float),
|
||||
verts.data(),
|
||||
g_baseVerts.size() * sizeof(float),
|
||||
g_baseVerts.data(),
|
||||
GL_DYNAMIC_DRAW
|
||||
));
|
||||
|
||||
@ -309,8 +447,8 @@ void initGPUObjects() {
|
||||
{
|
||||
GLCALL(glBufferData(
|
||||
GL_ARRAY_BUFFER,
|
||||
verts.size() * sizeof(float),
|
||||
verts.data(),
|
||||
g_baseVerts.size() * sizeof(float),
|
||||
g_baseVerts.data(),
|
||||
GL_DYNAMIC_DRAW
|
||||
)); // Initial dummy UVs
|
||||
GLCALL(glEnableVertexAttribArray(g_shader->uniformLocations[SHADER_TEX_ATTRIB]));
|
||||
@ -347,10 +485,15 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
||||
|
||||
initGPUObjects();
|
||||
|
||||
for (auto&& window : g_pCompositor->m_windows)
|
||||
registerWindow(window);
|
||||
|
||||
g_openWindow = HyprlandAPI::registerCallbackDynamic(
|
||||
PHANDLE,
|
||||
"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");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user