diff --git a/src/plugins/sheet/sheet.cpp b/src/plugins/sheet/sheet.cpp index 0a556b96bf..aa2672f6ea 100644 --- a/src/plugins/sheet/sheet.cpp +++ b/src/plugins/sheet/sheet.cpp @@ -25,34 +25,6 @@ namespace KWin { -static QMatrix4x4 createPerspectiveMatrix(const QRectF &rect, const qreal scale) -{ - QMatrix4x4 ret; - - const float fovY = std::tan(qDegreesToRadians(60.0f) / 2); - const float aspect = 1.0f; - const float zNear = 0.1f; - const float zFar = 100.0f; - - const float yMax = zNear * fovY; - const float yMin = -yMax; - const float xMin = yMin * aspect; - const float xMax = yMax * aspect; - - ret.frustum(xMin, xMax, yMin, yMax, zNear, zFar); - - const auto deviceRect = scaledRect(rect, scale); - - const float scaleFactor = 1.1 * fovY / yMax; - ret.translate(xMin * scaleFactor, yMax * scaleFactor, -1.1); - ret.scale((xMax - xMin) * scaleFactor / deviceRect.width(), - -(yMax - yMin) * scaleFactor / deviceRect.height(), - 0.001); - ret.translate(-deviceRect.x(), -deviceRect.y()); - - return ret; -} - SheetEffect::SheetEffect() { SheetConfig::instance(effects->config()); @@ -73,13 +45,6 @@ void SheetEffect::reconfigure(ReconfigureFlags flags) m_duration = std::chrono::milliseconds(static_cast(d)); } -void SheetEffect::prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) -{ - data.mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS; - - effects->prePaintScreen(data, presentTime); -} - void SheetEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime) { auto animationIt = m_animations.find(w); @@ -91,42 +56,51 @@ void SheetEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std: effects->prePaintWindow(w, data, presentTime); } -void SheetEffect::paintWindow(const RenderTarget &renderTarget, const RenderViewport &viewport, EffectWindow *w, int mask, QRegion region, WindowPaintData &data) +void SheetEffect::apply(EffectWindow *window, int mask, WindowPaintData &data, WindowQuadList &quads) { - auto animationIt = m_animations.constFind(w); + auto animationIt = m_animations.constFind(window); if (animationIt == m_animations.constEnd()) { - effects->paintWindow(renderTarget, viewport, w, mask, region, data); return; } - // Perspective projection distorts objects near edges of the viewport - // in undesired way. To fix this, the center of the window will be - // moved to the origin, after applying perspective projection, the - // center is moved back to its "original" projected position. Overall, - // this is how the window will be transformed: - // [move to the origin] -> [scale] -> [rotate] -> [translate] -> - // -> [perspective projection] -> [reverse "move to the origin"] - const QMatrix4x4 oldProjMatrix = createPerspectiveMatrix(viewport.renderRect(), viewport.scale()); - const QRectF windowGeo = w->frameGeometry(); - const QVector3D invOffset = oldProjMatrix.map(QVector3D(windowGeo.center())); - QMatrix4x4 invOffsetMatrix; - invOffsetMatrix.translate(invOffset.x(), invOffset.y()); - data.setProjectionMatrix(invOffsetMatrix * oldProjMatrix); - - // Move the center of the window to the origin. - const QRectF screenGeo = effects->virtualScreenGeometry(); - const QPointF offset = screenGeo.center() - windowGeo.center(); - data.translate(offset.x(), offset.y()); - const qreal t = (*animationIt).timeLine.value(); - data.setRotationAxis(Qt::XAxis); - data.setRotationAngle(interpolate(60.0, 0.0, t)); - data *= QVector3D(1.0, t, t); - data.translate(0.0, -interpolate(w->y() - (*animationIt).parentY, 0.0, t)); + + const QRectF rect = window->expandedGeometry().translated(-window->pos()); + const float fovY = std::tan(qDegreesToRadians(60.0f) / 2); + const float aspect = rect.width() / rect.height(); + const float zNear = 0.1f; + const float zFar = 100.0f; + + const float yMax = zNear * fovY; + const float yMin = -yMax; + const float xMin = yMin * aspect; + const float xMax = yMax * aspect; + + const float scaleFactor = 1.1 * fovY / yMax; + + QMatrix4x4 matrix; + matrix.viewport(rect); + matrix.frustum(xMin, xMax, yMax, yMin, zNear, zFar); + matrix.translate(xMin * scaleFactor, yMax * scaleFactor, -1.1); + matrix.scale((xMax - xMin) * scaleFactor / rect.width(), -(yMax - yMin) * scaleFactor / rect.height(), 0.001); + matrix.translate(-rect.x(), -rect.y()); + + matrix.scale(1.0, t, t); + matrix.translate(0.0, -interpolate(window->y() - (*animationIt).parentY, 0.0, t)); + + matrix.translate(window->width() / 2, 0); + matrix.rotate(interpolate(60.0, 0.0, t), 1, 0, 0); + matrix.translate(-window->width() / 2, 0); + + for (WindowQuad &quad : quads) { + for (int i = 0; i < 4; ++i) { + const QPointF transformed = matrix.map(QPointF(quad[i].x(), quad[i].y())); + quad[i].setX(transformed.x()); + quad[i].setY(transformed.y()); + } + } data.multiplyOpacity(t); - - effects->paintWindow(renderTarget, viewport, w, mask, region, data); } void SheetEffect::postPaintWindow(EffectWindow *w) @@ -136,6 +110,7 @@ void SheetEffect::postPaintWindow(EffectWindow *w) EffectWindow *w = animationIt.key(); w->addRepaintFull(); if ((*animationIt).timeLine.done()) { + unredirect(w); animationIt = m_animations.erase(animationIt); } else { ++animationIt; @@ -188,6 +163,7 @@ void SheetEffect::slotWindowAdded(EffectWindow *w) w->setData(WindowAddedGrabRole, QVariant::fromValue(static_cast(this))); + redirect(w); w->addRepaintFull(); } @@ -220,6 +196,7 @@ void SheetEffect::slotWindowClosed(EffectWindow *w) w->setData(WindowClosedGrabRole, QVariant::fromValue(static_cast(this))); + redirect(w); w->addRepaintFull(); } diff --git a/src/plugins/sheet/sheet.h b/src/plugins/sheet/sheet.h index 69ed3c500f..1cf7df4a09 100644 --- a/src/plugins/sheet/sheet.h +++ b/src/plugins/sheet/sheet.h @@ -12,14 +12,14 @@ #pragma once // kwineffects -#include "effect/effect.h" #include "effect/effectwindow.h" +#include "effect/offscreeneffect.h" #include "effect/timeline.h" namespace KWin { -class SheetEffect : public Effect +class SheetEffect : public OffscreenEffect { Q_OBJECT Q_PROPERTY(int duration READ duration) @@ -29,9 +29,7 @@ public: void reconfigure(ReconfigureFlags flags) override; - void prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) override; void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime) override; - void paintWindow(const RenderTarget &renderTarget, const RenderViewport &viewport, EffectWindow *w, int mask, QRegion region, WindowPaintData &data) override; void postPaintWindow(EffectWindow *w) override; bool isActive() const override; @@ -41,6 +39,9 @@ public: int duration() const; +protected: + void apply(EffectWindow *window, int mask, WindowPaintData &data, WindowQuadList &quads) override; + private Q_SLOTS: void slotWindowAdded(EffectWindow *w); void slotWindowClosed(EffectWindow *w);