Effects can now request windows to be subdivided into multiple quads.
Effects also get access to window's vertices. This can be used to change shape of the window, e.g. for wobble effect svn path=/branches/work/kwin_composite/; revision=626706
This commit is contained in:
parent
0ae5a772e7
commit
c2830a6360
4 changed files with 177 additions and 31 deletions
|
@ -223,6 +223,7 @@ void Scene::paintWindow( Window* w, int mask, QRegion region )
|
|||
{
|
||||
WindowPaintData data;
|
||||
data.opacity = w->window()->opacity();
|
||||
w->prepareForPainting();
|
||||
effects->paintWindow( effectWindow( w ), mask, region, data );
|
||||
}
|
||||
|
||||
|
|
1
scene.h
1
scene.h
|
@ -118,6 +118,7 @@ class Scene::Window
|
|||
virtual void free();
|
||||
// perform the actual painting of the window
|
||||
virtual void performPaint( int mask, QRegion region, WindowPaintData data ) = 0;
|
||||
virtual void prepareForPainting() {}
|
||||
int x() const;
|
||||
int y() const;
|
||||
int width() const;
|
||||
|
|
157
scene_opengl.cpp
157
scene_opengl.cpp
|
@ -65,6 +65,7 @@ Sources and other compositing managers:
|
|||
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <math.h>
|
||||
|
||||
namespace KWinInternal
|
||||
{
|
||||
|
@ -620,6 +621,11 @@ SceneOpenGL::Window::Window( Toplevel* c )
|
|||
, texture( 0 )
|
||||
, texture_y_inverted( false )
|
||||
, bound_glxpixmap( None )
|
||||
, currentXResolution( -1 )
|
||||
, currentYResolution( -1 )
|
||||
, requestedXResolution( 0 )
|
||||
, requestedYResolution( 0 )
|
||||
, verticesDirty( false )
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -628,6 +634,86 @@ void SceneOpenGL::Window::free()
|
|||
discardTexture();
|
||||
}
|
||||
|
||||
void SceneOpenGL::Window::requestVertexGrid(int maxquadsize)
|
||||
{
|
||||
requestedXResolution = (requestedXResolution <= 0) ? maxquadsize : qMin(maxquadsize, requestedXResolution);
|
||||
requestedYResolution = (requestedYResolution <= 0) ? maxquadsize : qMin(maxquadsize, requestedYResolution);
|
||||
}
|
||||
|
||||
void SceneOpenGL::Window::createVertexGrid(int xres, int yres)
|
||||
{
|
||||
int oldcount = verticeslist.count();
|
||||
verticeslist.clear();
|
||||
// FIXME: this creates a QRegion out of rectangles just to get the list of
|
||||
// rectangles. Maybe the QRegion construction can be bypassed?
|
||||
QRegion region = shape();
|
||||
foreach( QRect r, region.rects())
|
||||
{
|
||||
// First calculate number of columns/rows that this rect will be
|
||||
// divided into
|
||||
int cols = (xres <= 0) ? 1 : (int)ceilf( r.width() / (float)xres );
|
||||
int rows = (yres <= 0) ? 1 : (int)ceilf( r.height() / (float)yres );
|
||||
// Now calculate actual size of each cell
|
||||
int cellw = r.width() / cols;
|
||||
int cellh = r.height() / rows;
|
||||
int maxx = r.x() + r.width();
|
||||
int maxy = r.y() + r.height();
|
||||
for( int x1 = r.x(); x1 < maxx; x1 += cellw )
|
||||
{
|
||||
int x2 = qMin(x1 + cellw, maxx);
|
||||
for( int y1 = r.y(); y1 < maxy; y1 += cellh )
|
||||
{
|
||||
int y2 = qMin(y1 + cellh, maxy);
|
||||
// Add this quad to vertices' list
|
||||
verticeslist.append( Vertex( x1, y1 ));
|
||||
verticeslist.append( Vertex( x1, y2 ));
|
||||
verticeslist.append( Vertex( x2, y2 ));
|
||||
verticeslist.append( Vertex( x2, y1 ));
|
||||
}
|
||||
}
|
||||
}
|
||||
Client* c = qobject_cast<Client *>(window());
|
||||
kDebug() << k_funcinfo << "'" << (c ? c->caption() : "") << "': Resized vertex grid from " <<
|
||||
oldcount/4 << " quads (minreso: " << currentXResolution << "x" << currentYResolution <<
|
||||
") to " << verticeslist.count()/4 << " quads (minreso: " << xres << "x" << yres << ")" << endl;
|
||||
|
||||
currentXResolution = xres;
|
||||
currentYResolution = yres;
|
||||
verticesDirty = false;
|
||||
}
|
||||
|
||||
void SceneOpenGL::Window::resetVertices()
|
||||
{
|
||||
// This assumes that texcoords of the vertices are unchanged. If they are,
|
||||
// we need to do this in some other way (or maybe the effects should then
|
||||
// clean things up themselves)
|
||||
for(int i = 0; i < verticeslist.count(); i++)
|
||||
{
|
||||
verticeslist[i].pos[0] = verticeslist[i].texcoord[0];
|
||||
verticeslist[i].pos[1] = verticeslist[i].texcoord[1];
|
||||
}
|
||||
verticesDirty = false;
|
||||
}
|
||||
|
||||
void SceneOpenGL::Window::prepareVertices()
|
||||
{
|
||||
if( requestedXResolution != currentXResolution || requestedYResolution != currentYResolution )
|
||||
createVertexGrid( requestedXResolution, requestedYResolution );
|
||||
else if( verticesDirty )
|
||||
resetVertices();
|
||||
|
||||
// Reset requests for the next painting
|
||||
requestedXResolution = 0;
|
||||
requestedYResolution = 0;
|
||||
}
|
||||
|
||||
void SceneOpenGL::Window::prepareForPainting()
|
||||
{
|
||||
prepareVertices();
|
||||
// We should also bind texture here so that effects could access it in the
|
||||
// paint pass
|
||||
}
|
||||
|
||||
// Bind the window pixmap to an OpenGL texture.
|
||||
void SceneOpenGL::Window::bindTexture()
|
||||
{
|
||||
|
@ -856,20 +942,6 @@ void SceneOpenGL::Window::discardTexture()
|
|||
texture = 0;
|
||||
}
|
||||
|
||||
// paint a quad (rectangle), ty1/ty2 are texture coordinates (for handling
|
||||
// swapped y coordinate, see below)
|
||||
static void quadPaint( int x1, int y1, int x2, int y2, int ty1, int ty2 )
|
||||
{
|
||||
glTexCoord2i( x1, ty1 );
|
||||
glVertex2i( x1, y1 );
|
||||
glTexCoord2i( x2, ty1 );
|
||||
glVertex2i( x2, y1 );
|
||||
glTexCoord2i( x2, ty2 );
|
||||
glVertex2i( x2, y2 );
|
||||
glTexCoord2i( x1, ty2 );
|
||||
glVertex2i( x1, y2 );
|
||||
}
|
||||
|
||||
// paint the window
|
||||
void SceneOpenGL::Window::performPaint( int mask, QRegion region, WindowPaintData data )
|
||||
{
|
||||
|
@ -1028,24 +1100,49 @@ void SceneOpenGL::Window::performPaint( int mask, QRegion region, WindowPaintDat
|
|||
}
|
||||
}
|
||||
enableTexture();
|
||||
// actually paint the window
|
||||
glBegin( GL_QUADS );
|
||||
foreach( QRect r, region.rects())
|
||||
if(verticeslist.isEmpty())
|
||||
createVertexGrid(0, 0);
|
||||
// Enable arrays
|
||||
glEnableClientState( GL_VERTEX_ARRAY );
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(Vertex), verticeslist[0].pos);
|
||||
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
|
||||
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), verticeslist[0].texcoord);
|
||||
if( !texture_y_inverted )
|
||||
{
|
||||
int y1 = r.y();
|
||||
int y2 = r.y() + r.height();
|
||||
int ty1 = y1;
|
||||
int ty2 = y2;
|
||||
// tfp can result in the texture having y coordinate inverted (because
|
||||
// of the internal format), so do the inversion if needed
|
||||
if( !texture_y_inverted ) // "!" because of converting to OpenGL coords
|
||||
{
|
||||
ty1 = height() - y1;
|
||||
ty2 = height() - y2;
|
||||
}
|
||||
quadPaint( r.x(), y1, r.x() + r.width(), y2, ty1, ty2 );
|
||||
// Modify texture matrix so that we could always use non-opengl
|
||||
// coordinates for textures
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glScalef(1, -1, 1);
|
||||
glTranslatef(0, -height(), 0);
|
||||
}
|
||||
glEnd();
|
||||
// Render
|
||||
if( mask & PAINT_WINDOW_TRANSFORMED )
|
||||
// Just draw the entire window, no clipping
|
||||
glDrawArrays( GL_QUADS, 0, verticeslist.count() );
|
||||
else
|
||||
{
|
||||
// Make sure there's only a single quad (no transformed vertices)
|
||||
// Clip using scissoring
|
||||
glEnable( GL_SCISSOR_TEST );
|
||||
region.translate( x, y); // Back to screen coords
|
||||
int dh = displayHeight();
|
||||
foreach( QRect r, region.rects())
|
||||
{
|
||||
// Scissor rect has to be given in OpenGL coords
|
||||
glScissor(r.x(), dh - r.y() - r.height(), r.width(), r.height());
|
||||
glDrawArrays( GL_QUADS, 0, verticeslist.count() );
|
||||
}
|
||||
glDisable( GL_SCISSOR_TEST );
|
||||
}
|
||||
// Restore texture matrix
|
||||
if( !texture_y_inverted )
|
||||
{
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
}
|
||||
// Disable arrays
|
||||
glDisableClientState( GL_VERTEX_ARRAY );
|
||||
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
|
||||
glPopMatrix();
|
||||
if( data.opacity != 1.0 || data.saturation != 1.0 || data.brightness != 1.0f )
|
||||
{
|
||||
|
|
|
@ -25,6 +25,7 @@ class SceneOpenGL
|
|||
: public Scene
|
||||
{
|
||||
public:
|
||||
class Window;
|
||||
SceneOpenGL( Workspace* ws );
|
||||
virtual ~SceneOpenGL();
|
||||
virtual void paint( QRegion damage, ToplevelList windows );
|
||||
|
@ -61,7 +62,6 @@ class SceneOpenGL
|
|||
static bool strict_binding;
|
||||
static bool copy_buffer_hack;
|
||||
static bool supports_saturation;
|
||||
class Window;
|
||||
QMap< Toplevel*, Window > windows;
|
||||
static XShmSegmentInfo shm;
|
||||
};
|
||||
|
@ -73,16 +73,63 @@ class SceneOpenGL::Window
|
|||
Window( Toplevel* c );
|
||||
virtual void free();
|
||||
virtual void performPaint( int mask, QRegion region, WindowPaintData data );
|
||||
virtual void prepareForPainting();
|
||||
void bindTexture();
|
||||
void enableTexture();
|
||||
void disableTexture();
|
||||
void discardTexture();
|
||||
Window() {} // QMap sucks even in Qt4
|
||||
|
||||
/**
|
||||
* @short Vertex class
|
||||
* Vertex has position and texture coordinate which are equal at first,
|
||||
* however effects can e.g. modify position to move the window or part of it.
|
||||
**/
|
||||
class Vertex
|
||||
{
|
||||
public:
|
||||
Vertex() {}
|
||||
Vertex(float x, float y)
|
||||
{
|
||||
pos[0] = texcoord[0] = x; pos[1] = texcoord[1] = y; pos[2] = 0.0f;
|
||||
}
|
||||
Vertex(float x, float y, float u, float v)
|
||||
{
|
||||
pos[0] = x; pos[1] = y; pos[2] = 0.0f; texcoord[0] = u; texcoord[1] = v;
|
||||
}
|
||||
float pos[3];
|
||||
float texcoord[2];
|
||||
};
|
||||
// Returns list of vertices
|
||||
QVector<Vertex>& vertices() { return verticeslist; }
|
||||
// Can be called in pre-paint pass. Makes sure that all quads that the
|
||||
// window consists of are not bigger than maxquadsize x maxquadsize
|
||||
// (in pixels) in the following paint pass.
|
||||
void requestVertexGrid(int maxquadsize);
|
||||
// Marks vertices of the window as dirty. Call this if you change
|
||||
// position of the vertices
|
||||
void markVerticesDirty() { verticesDirty = true; }
|
||||
protected:
|
||||
// Makes sure that vertex grid requests are fulfilled and that vertices
|
||||
// aren't dirty. Call this before paint pass
|
||||
void prepareVertices();
|
||||
void createVertexGrid(int xres, int yres);
|
||||
void resetVertices(); // Resets positions of vertices
|
||||
private:
|
||||
QRegion optimizeBindDamage( const QRegion& reg, int limit );
|
||||
Texture texture;
|
||||
bool texture_y_inverted; // texture has y inverted
|
||||
GLXPixmap bound_glxpixmap; // the glx pixmap the texture is bound to, only for tfp_mode
|
||||
|
||||
QVector<Vertex> verticeslist;
|
||||
// Maximum size of the biggest quad that window currently has, in pixels
|
||||
int currentXResolution;
|
||||
int currentYResolution;
|
||||
// Requested maximum size of the biggest quad that window would have
|
||||
// during the next paint pass, in pixels
|
||||
int requestedXResolution;
|
||||
int requestedYResolution;
|
||||
bool verticesDirty; // vertices have been modified in some way
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
Loading…
Reference in a new issue