mirror of
https://github.com/hyprwm/Hyprland.git
synced 2026-08-18 11:02:10 +00:00
renderer/wobble: fix wobble on transformed outputs (#15694)
* renderer/wobble: fix wobble on transformed outputs * sc
This commit is contained in:
@ -1,5 +1,7 @@
|
||||
#include "DeformableMesh.hpp"
|
||||
|
||||
#include "memory/Memory.hpp"
|
||||
|
||||
#include <hyprutils/animation/Spring.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
@ -13,7 +15,7 @@ CDeformableMesh::CDeformableMesh(size_t verticesPerEdge) {
|
||||
}
|
||||
|
||||
void CDeformableMesh::setSize(size_t verticesPerEdge) {
|
||||
verticesPerEdge = std::clamp(verticesPerEdge, static_cast<size_t>(2), static_cast<size_t>(32));
|
||||
verticesPerEdge = std::clamp(verticesPerEdge, sc<size_t>(2), sc<size_t>(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<double>(y) / static_cast<double>(m_verticesPerEdge - 1);
|
||||
const double V = m_verticesPerEdge == 1 ? 0.0 : sc<double>(y) / sc<double>(m_verticesPerEdge - 1);
|
||||
for (size_t x = 0; x < m_verticesPerEdge; ++x) {
|
||||
const double U = m_verticesPerEdge == 1 ? 0.0 : static_cast<double>(x) / static_cast<double>(m_verticesPerEdge - 1);
|
||||
const double U = m_verticesPerEdge == 1 ? 0.0 : sc<double>(x) / sc<double>(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<float> elapsed) {
|
||||
for (auto& p : m_points) {
|
||||
float valueX = 1.F + static_cast<float>(p.displacement.x);
|
||||
float valueY = 1.F + static_cast<float>(p.displacement.y);
|
||||
float velX = static_cast<float>(p.velocity.x);
|
||||
float velY = static_cast<float>(p.velocity.y);
|
||||
float valueX = 1.F + sc<float>(p.displacement.x);
|
||||
float valueY = 1.F + sc<float>(p.displacement.y);
|
||||
float velX = sc<float>(p.velocity.x);
|
||||
float velY = sc<float>(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<SMeshRenderVertex> CDeformableMesh::verticesForBox(const CBox& box, const CBox& outputBox, const Vector2D& textureSize, double displacementScale) const {
|
||||
std::vector<SMeshRenderVertex> CDeformableMesh::verticesForBox(const CBox& box, const CBox& outputBox, const Vector2D& textureSize, double displacementScale,
|
||||
eTransform textureTransform) const {
|
||||
std::vector<SMeshRenderVertex> 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<SMeshRenderVertex> 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<float>((POS.x - outputBox.x) / outputBox.w),
|
||||
.y = static_cast<float>((POS.y - outputBox.y) / outputBox.h),
|
||||
.u = static_cast<float>(REST.x / textureSize.x),
|
||||
.v = static_cast<float>(REST.y / textureSize.y),
|
||||
.x = sc<float>((POS.x - outputBox.x) / outputBox.w),
|
||||
.y = sc<float>((POS.y - outputBox.y) / outputBox.h),
|
||||
.u = sc<float>(TEXTUREPOS.x / textureSize.x),
|
||||
.v = sc<float>(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<double>(x) / static_cast<double>(m_verticesPerEdge - 1);
|
||||
const double V = m_verticesPerEdge == 1 ? 0.0 : static_cast<double>(y) / static_cast<double>(m_verticesPerEdge - 1);
|
||||
const double U = m_verticesPerEdge == 1 ? 0.0 : sc<double>(x) / sc<double>(m_verticesPerEdge - 1);
|
||||
const double V = m_verticesPerEdge == 1 ? 0.0 : sc<double>(y) / sc<double>(m_verticesPerEdge - 1);
|
||||
return {box.x + box.w * U, box.y + box.h * V};
|
||||
}
|
||||
|
||||
|
||||
@ -28,7 +28,8 @@ class CDeformableMesh {
|
||||
|
||||
bool stable(float positionEpsilon, float velocityEpsilon) const;
|
||||
CBox transformedExtents(const CBox& box) const;
|
||||
std::vector<SMeshRenderVertex> verticesForBox(const CBox& box, const CBox& outputBox, const Vector2D& textureSize, double displacementScale = 1.0) const;
|
||||
std::vector<SMeshRenderVertex> verticesForBox(const CBox& box, const CBox& outputBox, const Vector2D& textureSize, double displacementScale = 1.0,
|
||||
eTransform textureTransform = HYPRUTILS_TRANSFORM_NORMAL) const;
|
||||
|
||||
private:
|
||||
struct SPoint {
|
||||
|
||||
@ -668,10 +668,11 @@ void IElementRenderer::drawTransformedWindow(WP<CTransformedWindowPassElement> 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);
|
||||
|
||||
|
||||
@ -87,7 +87,7 @@ SP<Render::IFramebuffer> CWobbleTransformer::transform(SP<Render::IFramebuffer>
|
||||
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;
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
|
||||
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<int>(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<float>(test.topLeft.x / TEXTURESIZE.x));
|
||||
EXPECT_FLOAT_EQ(VERTICES.front().v, static_cast<float>(test.topLeft.y / TEXTURESIZE.y));
|
||||
EXPECT_FLOAT_EQ(VERTICES.back().u, static_cast<float>(test.bottomRight.x / TEXTURESIZE.x));
|
||||
EXPECT_FLOAT_EQ(VERTICES.back().v, static_cast<float>(test.bottomRight.y / TEXTURESIZE.y));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user