21static void ensureResources()
 
   24    Q_INIT_RESOURCE(screentransform);
 
   38        QStringLiteral(
":/effects/screentransform/shaders/crossfade.vert"),
 
   39        QStringLiteral(
":/effects/screentransform/shaders/crossfade.frag"));
 
   41    m_modelViewProjectioMatrixLocation = m_shader->uniformLocation(
"modelViewProjectionMatrix");
 
   42    m_blendFactorLocation = m_shader->uniformLocation(
"blendFactor");
 
   43    m_previousTextureLocation = m_shader->uniformLocation(
"previousTexture");
 
   44    m_currentTextureLocation = m_shader->uniformLocation(
"currentTexture");
 
   47    for (
auto screen : screens) {
 
 
   63    auto ensureShort = [](
int angle) {
 
   64        return angle > 180 ? angle - 360 : angle < -180 ? angle + 360
 
   68    return ensureShort((
int(current.
kind()) % 4 - 
int(old.
kind()) % 4) * 90);
 
 
   71void ScreenTransformEffect::addScreen(Output *screen)
 
   74        const OutputTransform transform = changeSet->transform.value_or(screen->transform());
 
   75        if (screen->transform() == transform) {
 
   80        RenderLayer layer(screen->renderLoop());
 
   81        SceneDelegate delegate(scene, screen);
 
   82        delegate.setLayer(&layer);
 
   86        auto resetCapturing = qScopeGuard([
this]() {
 
   90        scene->prePaint(&delegate);
 
   94            auto &state = m_states[screen];
 
   95            state.m_oldTransform = screen->transform();
 
   96            state.m_oldGeometry = screen->geometry();
 
   97            state.m_timeLine.setDuration(std::chrono::milliseconds(
long(
animationTime(250))));
 
   98            state.m_timeLine.setEasingCurve(QEasingCurve::InOutCubic);
 
   99            state.m_angle = 
transformAngle(changeSet->transform.value(), state.m_oldTransform);
 
  100            state.m_prev.texture = std::move(texture);
 
  101            state.m_prev.framebuffer = std::make_unique<GLFramebuffer>(state.m_prev.texture.get());
 
  103            RenderTarget renderTarget(state.m_prev.framebuffer.get());
 
  104            scene->paint(renderTarget, screen->geometry());
 
  106            m_states.remove(screen);
 
  113void ScreenTransformEffect::removeScreen(Output *screen)
 
  115    screen->disconnect(
this);
 
  116    if (
auto it = m_states.find(screen); it != m_states.end()) {
 
  124    auto it = m_states.find(data.
screen);
 
  125    if (it != m_states.end()) {
 
  126        it->m_timeLine.advance(presentTime);
 
  127        if (it->m_timeLine.done()) {
 
  128            m_states.remove(data.
screen);
 
 
  135static GLVertexBuffer *texturedRectVbo(
const QRectF &geometry, qreal scale)
 
  145    const auto map = *opt;
 
  147    auto deviceGeometry = 
scaledRect(geometry, scale);
 
  151        .position = QVector2D(deviceGeometry.left(), deviceGeometry.top()),
 
  152        .texcoord = QVector2D(0.0, 1.0),
 
  155        .position = QVector2D(deviceGeometry.right(), deviceGeometry.bottom()),
 
  156        .texcoord = QVector2D(1.0, 0.0),
 
  159        .position = QVector2D(deviceGeometry.left(), deviceGeometry.bottom()),
 
  160        .texcoord = QVector2D(0.0, 0.0),
 
  165        .position = QVector2D(deviceGeometry.left(), deviceGeometry.top()),
 
  166        .texcoord = QVector2D(0.0, 1.0),
 
  169        .position = QVector2D(deviceGeometry.right(), deviceGeometry.top()),
 
  170        .texcoord = QVector2D(1.0, 1.0),
 
  173        .position = QVector2D(deviceGeometry.right(), deviceGeometry.bottom()),
 
  174        .texcoord = QVector2D(1.0, 0.0),
 
  181static qreal lerp(qreal a, qreal b, qreal t)
 
  183    return (1 - t) * a + t * b;
 
  186static QRectF lerp(
const QRectF &a, 
const QRectF &b, qreal t)
 
  189    ret.setWidth(lerp(a.width(), b.width(), t));
 
  190    ret.setHeight(lerp(a.height(), b.height(), t));
 
  191    ret.moveCenter(b.center());
 
  197    auto it = m_states.find(screen);
 
  198    if (it == m_states.end()) {
 
  204    const QSize nativeSize = screen->
geometry().size() * screen->
scale();
 
  205    if (!it->m_current.texture || it->m_current.texture->size() != nativeSize) {
 
  207        if (!it->m_current.texture) {
 
  208            m_states.remove(screen);
 
  211        it->m_current.framebuffer = std::make_unique<GLFramebuffer>(it->m_current.texture.get());
 
  214    RenderTarget fboRenderTarget(it->m_current.framebuffer.get());
 
  221    const qreal blendFactor = it->m_timeLine.value();
 
  222    const QRectF screenRect = screen->
geometry();
 
  223    const qreal angle = it->m_angle * (1 - blendFactor);
 
  225    const auto scale = viewport.
scale();
 
  228    const QVector3D transformOrigin(screenRect.center());
 
  230    modelViewProjectionMatrix.translate(transformOrigin * scale);
 
  231    modelViewProjectionMatrix.rotate(angle, 0, 0, 1);
 
  232    modelViewProjectionMatrix.translate(-transformOrigin * scale);
 
  234    glActiveTexture(GL_TEXTURE1);
 
  235    it->m_prev.texture->bind();
 
  236    glActiveTexture(GL_TEXTURE0);
 
  237    it->m_current.texture->bind();
 
  240    glClearColor(0, 0, 0, 0);
 
  241    glClear(GL_COLOR_BUFFER_BIT);
 
  243    GLVertexBuffer *vbo = texturedRectVbo(lerp(it->m_oldGeometry, screenRect, blendFactor), scale);
 
  250    m_shader->setUniform(m_modelViewProjectioMatrixLocation, modelViewProjectionMatrix);
 
  251    m_shader->setUniform(m_blendFactorLocation, 
float(blendFactor));
 
  252    m_shader->setUniform(m_currentTextureLocation, 0);
 
  253    m_shader->setUniform(m_previousTextureLocation, 1);
 
  256    vbo->
draw(GL_TRIANGLES, 0, 6);
 
  260    glActiveTexture(GL_TEXTURE1);
 
  261    it->m_prev.texture->unbind();
 
  262    glActiveTexture(GL_TEXTURE0);
 
  263    it->m_current.texture->unbind();
 
 
  270    return !m_states.isEmpty() && !m_capturing;
 
 
  275#include "moc_screentransform.cpp" 
Base class for all KWin effects.
void screenAdded(KWin::Output *screen)
Display * waylandDisplay() const
bool animationsSupported() const
void paintScreen(const RenderTarget &renderTarget, const RenderViewport &viewport, int mask, const QRegion ®ion, Output *screen)
void screenRemoved(KWin::Output *screen)
bool makeOpenGLContextCurrent()
Makes the OpenGL compositing context current.
CompositingType compositingType
void prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime)
QList< Output * > screens() const
WorkspaceScene * scene() const
Q_SCRIPTABLE void addRepaintFull()
static GLFramebuffer * popFramebuffer()
static void pushFramebuffer(GLFramebuffer *fbo)
static std::unique_ptr< GLTexture > allocate(GLenum internalFormat, const QSize &size, int levels=1)
void draw(GLenum primitiveMode, int first, int count)
void setAttribLayout(std::span< const GLVertexAttrib > attribs, size_t stride)
static constexpr std::array GLVertex2DLayout
static GLVertexBuffer * streamingBuffer()
std::optional< std::span< T > > map(size_t count)
void aboutToChange(OutputChangeSet *changeSet)
QMatrix4x4 projectionMatrix() const
QRectF renderRect() const
std::unique_ptr< GLShader > generateShaderFromFile(ShaderTraits traits, const QString &vertexFile=QString(), const QString &fragmentFile=QString())
static ShaderManager * instance()
GLShader * pushShader(ShaderTraits traits)
static double animationTime(const KConfigGroup &cfg, const QString &key, int defaultTime)
qreal transformAngle(OutputTransform current, OutputTransform old)
KWIN_EXPORT QRectF scaledRect(const QRectF &rect, qreal scale)