From 2f9169f05f3bf0cec10929e341bfcfa10d3baa67 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Sat, 1 Aug 2026 17:01:50 +0100 Subject: [PATCH] renderer/wobble: fix wobble on transformed outputs (#15694) * renderer/wobble: fix wobble on transformed outputs * sc --- src/helpers/DeformableMesh.cpp | 36 +++++++++++--------- src/helpers/DeformableMesh.hpp | 3 +- src/render/ElementRenderer.cpp | 9 ++--- src/render/transformer/WobbleTransformer.cpp | 2 +- tests/helpers/DeformableMesh.cpp | 31 +++++++++++++++++ 5 files changed, 59 insertions(+), 22 deletions(-) diff --git a/src/helpers/DeformableMesh.cpp b/src/helpers/DeformableMesh.cpp index b6a51fe4d..b1fbb7e7c 100644 --- a/src/helpers/DeformableMesh.cpp +++ b/src/helpers/DeformableMesh.cpp @@ -1,5 +1,7 @@ #include "DeformableMesh.hpp" +#include "memory/Memory.hpp" + #include #include @@ -13,7 +15,7 @@ CDeformableMesh::CDeformableMesh(size_t verticesPerEdge) { } void CDeformableMesh::setSize(size_t verticesPerEdge) { - verticesPerEdge = std::clamp(verticesPerEdge, static_cast(2), static_cast(32)); + verticesPerEdge = std::clamp(verticesPerEdge, sc(2), sc(32)); if (m_verticesPerEdge == verticesPerEdge && m_points.size() == verticesPerEdge * verticesPerEdge) return; @@ -59,9 +61,9 @@ void CDeformableMesh::onPositionUpdate(const CBox& previous, const CBox& current const double GRABMAXDISTANCE = grabPoint ? std::max(std::hypot(std::max(grabPoint->x, 1.0 - grabPoint->x), std::max(grabPoint->y, 1.0 - grabPoint->y)), 0.001) : 1.0; for (size_t y = 0; y < m_verticesPerEdge; ++y) { - const double V = m_verticesPerEdge == 1 ? 0.0 : static_cast(y) / static_cast(m_verticesPerEdge - 1); + const double V = m_verticesPerEdge == 1 ? 0.0 : sc(y) / sc(m_verticesPerEdge - 1); for (size_t x = 0; x < m_verticesPerEdge; ++x) { - const double U = m_verticesPerEdge == 1 ? 0.0 : static_cast(x) / static_cast(m_verticesPerEdge - 1); + const double U = m_verticesPerEdge == 1 ? 0.0 : sc(x) / sc(m_verticesPerEdge - 1); const double MOVEWEIGHTX = 0.45 + 0.55 * std::sin(V * std::numbers::pi); const double MOVEWEIGHTY = 0.45 + 0.55 * std::sin(U * std::numbers::pi); @@ -89,10 +91,10 @@ void CDeformableMesh::onPositionUpdate(const CBox& previous, const CBox& current void CDeformableMesh::advance(const SSpringCurve& spring, std::chrono::duration elapsed) { for (auto& p : m_points) { - float valueX = 1.F + static_cast(p.displacement.x); - float valueY = 1.F + static_cast(p.displacement.y); - float velX = static_cast(p.velocity.x); - float velY = static_cast(p.velocity.y); + float valueX = 1.F + sc(p.displacement.x); + float valueY = 1.F + sc(p.displacement.y); + float velX = sc(p.velocity.x); + float velY = sc(p.velocity.y); advanceSpring(valueX, velX, spring, elapsed); advanceSpring(valueY, velY, spring, elapsed); @@ -132,7 +134,8 @@ CBox CDeformableMesh::transformedExtents(const CBox& box) const { return {minX, minY, maxX - minX, maxY - minY}; } -std::vector CDeformableMesh::verticesForBox(const CBox& box, const CBox& outputBox, const Vector2D& textureSize, double displacementScale) const { +std::vector CDeformableMesh::verticesForBox(const CBox& box, const CBox& outputBox, const Vector2D& textureSize, double displacementScale, + eTransform textureTransform) const { std::vector vertices; if (m_verticesPerEdge < 2 || outputBox.w <= 0.F || outputBox.h <= 0.F || textureSize.x <= 0.F || textureSize.y <= 0.F) return vertices; @@ -140,13 +143,14 @@ std::vector CDeformableMesh::verticesForBox(const CBox& box, vertices.reserve((m_verticesPerEdge - 1) * (m_verticesPerEdge - 1) * 6); const auto makeVertex = [&](size_t x, size_t y) -> SMeshRenderVertex { - const Vector2D REST = restPoint(box, x, y); - const Vector2D POS = REST + point(x, y).displacement * displacementScale; + const Vector2D REST = restPoint(box, x, y); + const Vector2D POS = REST + point(x, y).displacement * displacementScale; + const Vector2D TEXTUREPOS = REST.transform(textureTransform, textureSize); return { - .x = static_cast((POS.x - outputBox.x) / outputBox.w), - .y = static_cast((POS.y - outputBox.y) / outputBox.h), - .u = static_cast(REST.x / textureSize.x), - .v = static_cast(REST.y / textureSize.y), + .x = sc((POS.x - outputBox.x) / outputBox.w), + .y = sc((POS.y - outputBox.y) / outputBox.h), + .u = sc(TEXTUREPOS.x / textureSize.x), + .v = sc(TEXTUREPOS.y / textureSize.y), }; }; @@ -173,8 +177,8 @@ const CDeformableMesh::SPoint& CDeformableMesh::point(size_t x, size_t y) const } Vector2D CDeformableMesh::restPoint(const CBox& box, size_t x, size_t y) const { - const double U = m_verticesPerEdge == 1 ? 0.0 : static_cast(x) / static_cast(m_verticesPerEdge - 1); - const double V = m_verticesPerEdge == 1 ? 0.0 : static_cast(y) / static_cast(m_verticesPerEdge - 1); + const double U = m_verticesPerEdge == 1 ? 0.0 : sc(x) / sc(m_verticesPerEdge - 1); + const double V = m_verticesPerEdge == 1 ? 0.0 : sc(y) / sc(m_verticesPerEdge - 1); return {box.x + box.w * U, box.y + box.h * V}; } diff --git a/src/helpers/DeformableMesh.hpp b/src/helpers/DeformableMesh.hpp index 6bd1b2aa8..028d48328 100644 --- a/src/helpers/DeformableMesh.hpp +++ b/src/helpers/DeformableMesh.hpp @@ -28,7 +28,8 @@ class CDeformableMesh { bool stable(float positionEpsilon, float velocityEpsilon) const; CBox transformedExtents(const CBox& box) const; - std::vector verticesForBox(const CBox& box, const CBox& outputBox, const Vector2D& textureSize, double displacementScale = 1.0) const; + std::vector verticesForBox(const CBox& box, const CBox& outputBox, const Vector2D& textureSize, double displacementScale = 1.0, + eTransform textureTransform = HYPRUTILS_TRANSFORM_NORMAL) const; private: struct SPoint { diff --git a/src/render/ElementRenderer.cpp b/src/render/ElementRenderer.cpp index 0b89e8da9..dd9630719 100644 --- a/src/render/ElementRenderer.cpp +++ b/src/render/ElementRenderer.cpp @@ -668,10 +668,11 @@ void IElementRenderer::drawTransformedWindow(WP e outputBox = {0, 0, pMonitor->m_transformedSize.x, pMonitor->m_transformedSize.y}; CTexPassElement::SRenderData data; - data.tex = last->getTexture(); - data.box = outputBox; - data.a = 1.F; - data.motionBlur = motionBlur; + data.tex = last->getTexture(); + data.box = outputBox; + data.a = 1.F; + data.motionBlur = motionBlur; + data.flipEndFrame = !motionBlur.enabled; const CRegion drawDamage = damage.copy().intersect(outputBox); diff --git a/src/render/transformer/WobbleTransformer.cpp b/src/render/transformer/WobbleTransformer.cpp index e5c3d0938..ba325c338 100644 --- a/src/render/transformer/WobbleTransformer.cpp +++ b/src/render/transformer/WobbleTransformer.cpp @@ -87,7 +87,7 @@ SP CWobbleTransformer::transform(SP if (sourceBox.empty() || outputBox.empty()) return in; - const auto VERTICES = m_mesh.verticesForBox(sourceBox, sourceOutputBox, in->getTexture()->m_size, SCALE); + const auto VERTICES = m_mesh.verticesForBox(sourceBox, sourceOutputBox, in->getTexture()->m_size, SCALE, Math::wlTransformToHyprutils(context.monitor->m_transform)); if (VERTICES.empty()) return in; diff --git a/tests/helpers/DeformableMesh.cpp b/tests/helpers/DeformableMesh.cpp index 115270027..eb2175dfe 100644 --- a/tests/helpers/DeformableMesh.cpp +++ b/tests/helpers/DeformableMesh.cpp @@ -3,6 +3,7 @@ #include #include +#include #include TEST(Helpers, deformableMeshSetSizeClamps) { @@ -89,3 +90,33 @@ TEST(Helpers, deformableMeshVerticesForBoxBuildsTriangles) { EXPECT_FLOAT_EQ(VERTICES.back().u, 1.F); EXPECT_FLOAT_EQ(VERTICES.back().v, 1.F); } + +TEST(Helpers, deformableMeshVerticesForBoxTransformsUVs) { + struct STransformCase { + eTransform transform = HYPRUTILS_TRANSFORM_NORMAL; + Vector2D topLeft; + Vector2D bottomRight; + }; + + const CBox BOX = {100, 200, 300, 400}; + constexpr Vector2D TEXTURESIZE = {1920, 1080}; + const auto CASES = std::array{ + STransformCase{HYPRUTILS_TRANSFORM_NORMAL, {100, 200}, {400, 600}}, STransformCase{HYPRUTILS_TRANSFORM_90, {200, 980}, {600, 680}}, + STransformCase{HYPRUTILS_TRANSFORM_180, {1820, 880}, {1520, 480}}, STransformCase{HYPRUTILS_TRANSFORM_270, {1720, 100}, {1320, 400}}, + STransformCase{HYPRUTILS_TRANSFORM_FLIPPED, {1820, 200}, {1520, 600}}, STransformCase{HYPRUTILS_TRANSFORM_FLIPPED_90, {200, 100}, {600, 400}}, + STransformCase{HYPRUTILS_TRANSFORM_FLIPPED_180, {100, 880}, {400, 480}}, STransformCase{HYPRUTILS_TRANSFORM_FLIPPED_270, {1720, 980}, {1320, 680}}, + }; + + CDeformableMesh mesh(2); + for (const auto& test : CASES) { + SCOPED_TRACE(static_cast(test.transform)); + + const auto VERTICES = mesh.verticesForBox(BOX, BOX, TEXTURESIZE, 1.0, test.transform); + + ASSERT_EQ(VERTICES.size(), 6u); + EXPECT_FLOAT_EQ(VERTICES.front().u, static_cast(test.topLeft.x / TEXTURESIZE.x)); + EXPECT_FLOAT_EQ(VERTICES.front().v, static_cast(test.topLeft.y / TEXTURESIZE.y)); + EXPECT_FLOAT_EQ(VERTICES.back().u, static_cast(test.bottomRight.x / TEXTURESIZE.x)); + EXPECT_FLOAT_EQ(VERTICES.back().v, static_cast(test.bottomRight.y / TEXTURESIZE.y)); + } +}