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)