From 9f3656c917913fcd2fe092ace648d58b595cf68a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20L=C3=BCbking?= Date: Sun, 1 Feb 2015 04:29:50 +0100 Subject: [PATCH] Cover+Flip, multiscreen: fix matrix manipulation Moves calculation of projection and modelview matrix (aligned to new scene_opengl code) to effect start, caches the matrices in private members and sets them on WindowPaintData BUG: 343509 REVIEW: 122355 FIXED-IN: 5.3 --- effects/coverswitch/coverswitch.cpp | 134 +++++++++++++++------------- effects/coverswitch/coverswitch.h | 2 + effects/flipswitch/flipswitch.cpp | 127 +++++++++++++------------- effects/flipswitch/flipswitch.h | 3 + 4 files changed, 139 insertions(+), 127 deletions(-) diff --git a/effects/coverswitch/coverswitch.cpp b/effects/coverswitch/coverswitch.cpp index 56c1a8df93..022a494c85 100644 --- a/effects/coverswitch/coverswitch.cpp +++ b/effects/coverswitch/coverswitch.cpp @@ -139,61 +139,6 @@ void CoverSwitchEffect::paintScreen(int mask, QRegion region, ScreenPaintData& d effects->paintScreen(mask, region, data); if (mActivated || stop || stopRequested) { - QMatrix4x4 origProjection; - QMatrix4x4 origModelview; - ShaderManager *shaderManager = ShaderManager::instance(); - if (effects->numScreens() > 1) { - // unfortunatelly we have to change the projection matrix in dual screen mode - QRect fullRect = effects->clientArea(FullArea, activeScreen, effects->currentDesktop()); - float fovy = 60.0f; - float aspect = 1.0f; - float zNear = 0.1f; - float zFar = 100.0f; - float ymax = zNear * tan(fovy * M_PI / 360.0f); - float ymin = -ymax; - float xmin = ymin * aspect; - float xmax = ymax * aspect; - float xTranslate = 0.0; - float yTranslate = 0.0; - float xminFactor = 1.0; - float xmaxFactor = 1.0; - float yminFactor = 1.0; - float ymaxFactor = 1.0; - if (area.x() == 0 && area.width() != fullRect.width()) { - // horizontal layout: left screen - xminFactor = (float)area.width() / (float)fullRect.width(); - xmaxFactor = ((float)fullRect.width() - (float)area.width() * 0.5f) / ((float)fullRect.width() * 0.5f); - xTranslate = (float)fullRect.width() * 0.5f - (float)area.width() * 0.5f; - } - if (area.x() != 0 && area.width() != fullRect.width()) { - // horizontal layout: right screen - xminFactor = ((float)fullRect.width() - (float)area.width() * 0.5f) / ((float)fullRect.width() * 0.5f); - xmaxFactor = (float)area.width() / (float)fullRect.width(); - xTranslate = (float)fullRect.width() * 0.5f - (float)area.width() * 0.5f; - } - if (area.y() == 0 && area.height() != fullRect.height()) { - // vertical layout: top screen - yminFactor = ((float)fullRect.height() - (float)area.height() * 0.5f) / ((float)fullRect.height() * 0.5f); - ymaxFactor = (float)area.height() / (float)fullRect.height(); - yTranslate = (float)fullRect.height() * 0.5f - (float)area.height() * 0.5f; - } - if (area.y() != 0 && area.height() != fullRect.height()) { - // vertical layout: bottom screen - yminFactor = (float)area.height() / (float)fullRect.height(); - ymaxFactor = ((float)fullRect.height() - (float)area.height() * 0.5f) / ((float)fullRect.height() * 0.5f); - yTranslate = (float)fullRect.height() * 0.5f - (float)area.height() * 0.5f; - } - QMatrix4x4 projection; - projection.frustum(xmin * xminFactor, xmax * xmaxFactor, ymin * yminFactor, ymax * ymaxFactor, zNear, zFar); - QMatrix4x4 modelview; - modelview.translate(xTranslate, yTranslate, 0.0); - GLShader *shader = shaderManager->pushShader(ShaderManager::GenericShader); - origProjection = shader->getUniformMatrix4x4("projection"); - origModelview = shader->getUniformMatrix4x4("modelview"); - shader->setUniform("projection", projection); - shader->setUniform("modelview", origModelview * modelview); - shaderManager->popShader(); - } QList< EffectWindow* > tempList = currentWindowList; int index = tempList.indexOf(selected_window); @@ -296,7 +241,7 @@ void CoverSwitchEffect::paintScreen(int mask, QRegion region, ScreenPaintData& d glEnable(GL_SCISSOR_TEST); if (m_reflectionShader && m_reflectionShader->isValid()) { - shaderManager->pushShader(m_reflectionShader); + ShaderManager::instance()->pushShader(m_reflectionShader); QMatrix4x4 windowTransformation; windowTransformation.translate(area.x() + area.width() * 0.5f, 0.0, 0.0); m_reflectionShader->setUniform("windowTransformation", windowTransformation); @@ -324,20 +269,13 @@ void CoverSwitchEffect::paintScreen(int mask, QRegion region, ScreenPaintData& d vbo->setData(6, 3, verts.data(), texcoords.data()); vbo->render(GL_TRIANGLES); - shaderManager->popShader(); + ShaderManager::instance()->popShader(); } glDisable(GL_SCISSOR_TEST); glDisable(GL_BLEND); } paintScene(frontWindow, leftWindows, rightWindows); - if (effects->numScreens() > 1) { - GLShader *shader = shaderManager->pushShader(ShaderManager::GenericShader); - shader->setUniform("projection", origProjection); - shader->setUniform("modelview", origModelview); - shaderManager->popShader(); - } - // Render the caption frame if (windowTitle) { double opacity = 1.0; @@ -518,6 +456,62 @@ void CoverSwitchEffect::slotTabBoxAdded(int mode) } } + if (effects->numScreens() > 1) { + // unfortunatelly we have to change the projection matrix in dual screen mode + // code is adapted from SceneOpenGL2::createProjectionMatrix() + QRect fullRect = effects->clientArea(FullArea, activeScreen, effects->currentDesktop()); + float fovy = 60.0f; + float aspect = 1.0f; + float zNear = 0.1f; + float zFar = 100.0f; + + float ymax = zNear * std::tan(fovy * M_PI / 360.0f); + float ymin = -ymax; + float xmin = ymin * aspect; + float xmax = ymax * aspect; + + if (area.width() != fullRect.width()) { + if (area.x() == 0) { + // horizontal layout: left screen + xmin *= (float)area.width() / (float)fullRect.width(); + xmax *= (fullRect.width() - 0.5f * area.width()) / (0.5f * fullRect.width()); + } else { + // horizontal layout: right screen + xmin *= (fullRect.width() - 0.5f * area.width()) / (0.5f * fullRect.width()); + xmax *= (float)area.width() / (float)fullRect.width(); + } + } + if (area.height() != fullRect.height()) { + if (area.y() == 0) { + // vertical layout: top screen + ymin *= (fullRect.height() - 0.5f * area.height()) / (0.5f * fullRect.height()); + ymax *= (float)area.height() / (float)fullRect.height(); + } else { + // vertical layout: bottom screen + ymin *= (float)area.height() / (float)fullRect.height(); + ymax *= (fullRect.height() - 0.5f * area.height()) / (0.5f * fullRect.height()); + } + } + + m_projectionMatrix = QMatrix4x4(); + m_projectionMatrix.frustum(xmin, xmax, ymin, ymax, zNear, zFar); + + const float scaleFactor = 1.1f / zNear; + + // Create a second matrix that transforms screen coordinates + // to world coordinates. + QMatrix4x4 matrix; + matrix.translate(xmin * scaleFactor, ymax * scaleFactor, -1.1); + matrix.scale( (xmax - xmin) * scaleFactor / fullRect.width(), + -(ymax - ymin) * scaleFactor / fullRect.height(), + 0.001); + // Combine the matrices + m_projectionMatrix *= matrix; + + m_modelviewMatrix = QMatrix4x4(); + m_modelviewMatrix.translate(area.x(), area.y(), 0.0); + } + // Setup caption frame geometry if (windowTitle) { QRect frameRect = QRect(area.width() * 0.25f + area.x(), @@ -715,6 +709,10 @@ void CoverSwitchEffect::paintFrontWindow(EffectWindow* frontWindow, int width, i return; bool specialHandlingForward = false; WindowPaintData data(frontWindow); + if (effects->numScreens() > 1) { + data.setProjectionMatrix(m_projectionMatrix); + data.setModelViewMatrix(m_modelviewMatrix); + } data.setXTranslation(area.width() * 0.5 - frontWindow->geometry().x() - frontWindow->geometry().width() * 0.5); if (leftWindows == 0) { leftWindows = 1; @@ -773,6 +771,10 @@ void CoverSwitchEffect::paintWindows(const EffectWindowList& windows, bool left, // has to appear on this side after half of the time if (animation && timeLine.currentValue() >= 0.5 && additionalWindow != NULL) { WindowPaintData data(additionalWindow); + if (effects->numScreens() > 1) { + data.setProjectionMatrix(m_projectionMatrix); + data.setModelViewMatrix(m_modelviewMatrix); + } data.setRotationAxis(Qt::YAxis); data.setRotationAngle(angle * rotateFactor); if (left) { @@ -793,6 +795,10 @@ void CoverSwitchEffect::paintWindows(const EffectWindowList& windows, bool left, continue; } WindowPaintData data(window); + if (effects->numScreens() > 1) { + data.setProjectionMatrix(m_projectionMatrix); + data.setModelViewMatrix(m_modelviewMatrix); + } data.setRotationAxis(Qt::YAxis); data.setRotationAngle(angle); if (left) diff --git a/effects/coverswitch/coverswitch.h b/effects/coverswitch/coverswitch.h index 17307e4e49..b058db4d4d 100644 --- a/effects/coverswitch/coverswitch.h +++ b/effects/coverswitch/coverswitch.h @@ -157,6 +157,8 @@ private: bool secondaryTabBox; GLShader *m_reflectionShader; + QMatrix4x4 m_projectionMatrix; + QMatrix4x4 m_modelviewMatrix; }; } // namespace diff --git a/effects/flipswitch/flipswitch.cpp b/effects/flipswitch/flipswitch.cpp index cdd57896fc..fd39b5032e 100644 --- a/effects/flipswitch/flipswitch.cpp +++ b/effects/flipswitch/flipswitch.cpp @@ -192,62 +192,6 @@ void FlipSwitchEffect::paintScreen(int mask, QRegion region, ScreenPaintData& da } } - // multiscreen part taken from coverswitch.cpp - // TODO: move to kwinglutils - QMatrix4x4 origProjection; - QMatrix4x4 origModelview; - if (effects->numScreens() > 1) { - // unfortunatelly we have to change the projection matrix in dual screen mode - QRect fullRect = effects->clientArea(FullArea, effects->activeScreen(), effects->currentDesktop()); - float fovy = 60.0f; - float aspect = 1.0f; - float zNear = 0.1f; - float zFar = 100.0f; - float ymax = zNear * tan(fovy * M_PI / 360.0f); - float ymin = -ymax; - float xmin = ymin * aspect; - float xmax = ymax * aspect; - float xTranslate = 0.0; - float yTranslate = 0.0; - float xminFactor = 1.0; - float xmaxFactor = 1.0; - float yminFactor = 1.0; - float ymaxFactor = 1.0; - if (m_screenArea.x() == 0 && m_screenArea.width() != fullRect.width()) { - // horizontal layout: left screen - xminFactor = (float)m_screenArea.width() / (float)fullRect.width(); - xmaxFactor = ((float)fullRect.width() - (float)m_screenArea.width() * 0.5f) / ((float)fullRect.width() * 0.5f); - xTranslate = (float)fullRect.width() * 0.5f - (float)m_screenArea.width() * 0.5f; - } - if (m_screenArea.x() != 0 && m_screenArea.width() != fullRect.width()) { - // horizontal layout: right screen - xminFactor = ((float)fullRect.width() - (float)m_screenArea.width() * 0.5f) / ((float)fullRect.width() * 0.5f); - xmaxFactor = (float)m_screenArea.width() / (float)fullRect.width(); - xTranslate = (float)fullRect.width() * 0.5f - (float)m_screenArea.width() * 0.5f; - } - if (m_screenArea.y() == 0 && m_screenArea.height() != fullRect.height()) { - // vertical layout: top screen - yminFactor = ((float)fullRect.height() - (float)m_screenArea.height() * 0.5f) / ((float)fullRect.height() * 0.5f); - ymaxFactor = (float)m_screenArea.height() / (float)fullRect.height(); - yTranslate = (float)fullRect.height() * 0.5f - (float)m_screenArea.height() * 0.5f; - } - if (m_screenArea.y() != 0 && m_screenArea.height() != fullRect.height()) { - // vertical layout: bottom screen - yminFactor = (float)m_screenArea.height() / (float)fullRect.height(); - ymaxFactor = ((float)fullRect.height() - (float)m_screenArea.height() * 0.5f) / ((float)fullRect.height() * 0.5f); - yTranslate = (float)fullRect.height() * 0.5f - (float)m_screenArea.height() * 0.5f; - } - QMatrix4x4 projection; - projection.frustum(xmin * xminFactor, xmax * xmaxFactor, ymin * yminFactor, ymax * ymaxFactor, zNear, zFar); - QMatrix4x4 modelview; - modelview.translate(xTranslate, yTranslate, 0.0); - ShaderBinder binder(ShaderManager::GenericShader); - GLShader *shader = binder.shader(); - origProjection = shader->getUniformMatrix4x4("projection"); - origModelview = shader->getUniformMatrix4x4("modelview"); - shader->setUniform("projection", projection); - shader->setUniform("modelview", origModelview * modelview); - } int winMask = PAINT_WINDOW_TRANSFORMED | PAINT_WINDOW_TRANSLUCENT; // fade in/out one window at the end of the stack during animation @@ -255,6 +199,10 @@ void FlipSwitchEffect::paintScreen(int mask, QRegion region, ScreenPaintData& da EffectWindow* w = m_flipOrderedWindows.last(); if (ItemInfo *info = m_windows.value(w,0)) { WindowPaintData data(w); + if (effects->numScreens() > 1) { + data.setProjectionMatrix(m_projectionMatrix); + data.setModelViewMatrix(m_modelviewMatrix); + } data.setRotationAxis(Qt::YAxis); data.setRotationAngle(m_angle * m_startStopTimeLine.currentValue()); data.setOpacity(info->opacity); @@ -286,6 +234,10 @@ void FlipSwitchEffect::paintScreen(int mask, QRegion region, ScreenPaintData& da if (!info) continue; WindowPaintData data(w); + if (effects->numScreens() > 1) { + data.setProjectionMatrix(m_projectionMatrix); + data.setModelViewMatrix(m_modelviewMatrix); + } data.setRotationAxis(Qt::YAxis); data.setRotationAngle(m_angle * m_startStopTimeLine.currentValue()); data.setOpacity(info->opacity); @@ -342,13 +294,6 @@ void FlipSwitchEffect::paintScreen(int mask, QRegion region, ScreenPaintData& da effects->drawWindow(w, winMask, infiniteRegion(), data); } - if (effects->numScreens() > 1) { - ShaderBinder binder(ShaderManager::GenericShader); - GLShader *shader = binder.shader(); - shader->setUniform("projection", origProjection); - shader->setUniform("modelview", origModelview); - } - if (m_windowTitle) { // Render the caption frame if (m_animation) { @@ -581,6 +526,62 @@ void FlipSwitchEffect::setActive(bool activate, FlipSwitchMode mode) m_activeScreen = effects->activeScreen(); m_screenArea = effects->clientArea(ScreenArea, m_activeScreen, effects->currentDesktop()); + if (effects->numScreens() > 1) { + // unfortunatelly we have to change the projection matrix in dual screen mode + // code is copied from Coverswitch + QRect fullRect = effects->clientArea(FullArea, m_activeScreen, effects->currentDesktop()); + float fovy = 60.0f; + float aspect = 1.0f; + float zNear = 0.1f; + float zFar = 100.0f; + + float ymax = zNear * std::tan(fovy * M_PI / 360.0f); + float ymin = -ymax; + float xmin = ymin * aspect; + float xmax = ymax * aspect; + + if (m_screenArea.width() != fullRect.width()) { + if (m_screenArea.x() == 0) { + // horizontal layout: left screen + xmin *= (float)m_screenArea.width() / (float)fullRect.width(); + xmax *= (fullRect.width() - 0.5f * m_screenArea.width()) / (0.5f * fullRect.width()); + } else { + // horizontal layout: right screen + xmin *= (fullRect.width() - 0.5f * m_screenArea.width()) / (0.5f * fullRect.width()); + xmax *= (float)m_screenArea.width() / (float)fullRect.width(); + } + } + if (m_screenArea.height() != fullRect.height()) { + if (m_screenArea.y() == 0) { + // vertical layout: top screen + ymin *= (fullRect.height() - 0.5f * m_screenArea.height()) / (0.5f * fullRect.height()); + ymax *= (float)m_screenArea.height() / (float)fullRect.height(); + } else { + // vertical layout: bottom screen + ymin *= (float)m_screenArea.height() / (float)fullRect.height(); + ymax *= (fullRect.height() - 0.5f * m_screenArea.height()) / (0.5f * fullRect.height()); + } + } + + m_projectionMatrix = QMatrix4x4(); + m_projectionMatrix.frustum(xmin, xmax, ymin, ymax, zNear, zFar); + + const float scaleFactor = 1.1f / zNear; + + // Create a second matrix that transforms screen coordinates + // to world coordinates. + QMatrix4x4 matrix; + matrix.translate(xmin * scaleFactor, ymax * scaleFactor, -1.1); + matrix.scale( (xmax - xmin) * scaleFactor / fullRect.width(), + -(ymax - ymin) * scaleFactor / fullRect.height(), + 0.001); + // Combine the matrices + m_projectionMatrix *= matrix; + + m_modelviewMatrix = QMatrix4x4(); + m_modelviewMatrix.translate(m_screenArea.x(), m_screenArea.y(), 0.0); + } + if (m_stop) { // effect is still closing from last usage m_stop = false; diff --git a/effects/flipswitch/flipswitch.h b/effects/flipswitch/flipswitch.h index 058e6b3835..859f30c65f 100644 --- a/effects/flipswitch/flipswitch.h +++ b/effects/flipswitch/flipswitch.h @@ -22,6 +22,7 @@ along with this program. If not, see . #define KWIN_FLIPSWITCH_H #include +#include #include #include @@ -133,6 +134,8 @@ private: QFont m_captionFont; EffectWindowList m_flipOrderedWindows; QHash< const EffectWindow*, ItemInfo* > m_windows; + QMatrix4x4 m_projectionMatrix; + QMatrix4x4 m_modelviewMatrix; // options bool m_tabbox; bool m_tabboxAlternative;