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:
Rivo Laks 2007-01-24 11:51:38 +00:00
parent 0ae5a772e7
commit c2830a6360
4 changed files with 177 additions and 31 deletions

View file

@ -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 );
}

View file

@ -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;

View file

@ -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 )
{

View file

@ -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