Separate rendering for decoration and window contents, they can have

different opacity (opacity only for decoration option).


svn path=/trunk/KDE/kdebase/workspace/; revision=689855
This commit is contained in:
Luboš Luňák 2007-07-19 10:07:49 +00:00
parent 6b71cd62db
commit e1c5f18414
7 changed files with 130 additions and 55 deletions

View file

@ -98,7 +98,6 @@ KDE 4.0 TODO
/ vertex redesign [Seli]
affects alpha clear hack
- support applying opacity only to decoration
- not using ARGB visuals
- handling of window pixmaps for unmapped windows [Seli]
@ -302,9 +301,6 @@ Effects TODO
/ implements all effects Kompmgr could do
+ - all effects from the Opacity tab should be already doable
! - applying translucency only to the decoration
- use clientSize() and clientPos() from Client
- see also the alpha clear hack todo entry
! - not usign ARGB visuals
- just clear the alpha channel in the alpha clear hack
- or do it while painting (see also the alpha clear hack todo entry)

View file

@ -15,9 +15,23 @@ namespace KWin
KWIN_EFFECT( maketransparent, MakeTransparentEffect )
MakeTransparentEffect::MakeTransparentEffect()
{
// TODO options
decoration = 0.7;
moveresize = 0.5;
dialogs = 1.0;
}
void MakeTransparentEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time )
{
if(( w->isUserMove() || w->isUserResize()) || w->isDialog())
if( decoration != 1.0 )
{
data.mask |= PAINT_WINDOW_TRANSLUCENT;
data.mask &= ~PAINT_WINDOW_OPAQUE;
}
if(( moveresize != 1.0 && ( w->isUserMove() || w->isUserResize()))
|| ( dialogs != 1.0 && w->isDialog()))
{
data.mask |= PAINT_WINDOW_TRANSLUCENT;
data.mask &= ~PAINT_WINDOW_OPAQUE;
@ -27,16 +41,18 @@ void MakeTransparentEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData&
void MakeTransparentEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
{
if( w->isDialog())
data.opacity *= 0.8;
if( w->isUserMove() || w->isUserResize())
data.opacity *= 0.5;
if( decoration != 1.0 )
data.decoration_opacity *= decoration;
if( dialogs != 1.0 && w->isDialog())
data.opacity *= dialogs;
if( moveresize != 1.0 && ( w->isUserMove() || w->isUserResize()))
data.opacity *= moveresize;
effects->paintWindow( w, mask, region, data );
}
void MakeTransparentEffect::windowUserMovedResized( EffectWindow* w, bool first, bool last )
{
if( first || last )
if( moveresize != 1.0 && ( first || last ))
w->addRepaintFull();
}

View file

@ -20,9 +20,14 @@ class MakeTransparentEffect
: public Effect
{
public:
MakeTransparentEffect();
virtual void windowUserMovedResized( EffectWindow* c, bool first, bool last );
virtual void prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time );
virtual void paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data );
private:
float decoration;
float moveresize;
float dialogs;
};
} // namespace

View file

@ -24,6 +24,8 @@ namespace KWin
WindowPaintData::WindowPaintData()
: opacity( 1.0 )
, contents_opacity( 1.0 )
, decoration_opacity( 1.0 )
, xScale( 1 )
, yScale( 1 )
, xTranslate( 0 )
@ -417,7 +419,7 @@ WindowQuadList WindowQuadList::makeGrid( int maxquadsize ) const
return ret;
}
void WindowQuadList::makeArrays( float** vertices, float** texcoords )
void WindowQuadList::makeArrays( float** vertices, float** texcoords ) const
{
*vertices = new float[ count() * 4 * 2 ];
*texcoords = new float[ count() * 4 * 2 ];
@ -437,6 +439,24 @@ void WindowQuadList::makeArrays( float** vertices, float** texcoords )
}
}
WindowQuadList WindowQuadList::select( WindowQuadType type ) const
{
foreach( WindowQuad q, *this )
{
if( q.type != type ) // something else than ones to select, make a copy and filter
{
WindowQuadList ret;
foreach( WindowQuad q, *this )
{
if( q.type == type )
ret.append( q );
}
return ret;
}
}
return *this; // nothing to filter out
}
WindowQuadList WindowQuadList::filterOut( WindowQuadType type ) const
{
foreach( WindowQuad q, *this )

View file

@ -415,9 +415,10 @@ class KWIN_EXPORT WindowQuadList
WindowQuadList splitAtX( float x ) const;
WindowQuadList splitAtY( float y ) const;
WindowQuadList makeGrid( int maxquadsize ) const;
WindowQuadList select( WindowQuadType type ) const;
WindowQuadList filterOut( WindowQuadType type ) const;
bool smoothNeeded() const;
void makeArrays( float** vertices, float** texcoords );
void makeArrays( float** vertices, float** texcoords ) const;
};
class KWIN_EXPORT WindowPrePaintData
@ -435,8 +436,12 @@ class KWIN_EXPORT WindowPaintData
WindowPaintData();
/**
* Window opacity, in range 0 = transparent to 1 = fully opaque
* Opacity for contents is opacity*contents_opacity, the same
* way for decoration.
*/
double opacity;
double contents_opacity;
double decoration_opacity;
double xScale;
double yScale;
int xTranslate;

View file

@ -1177,60 +1177,82 @@ void SceneOpenGL::Window::performPaint( int mask, QRegion region, WindowPaintDat
glTranslatef( x, y, 0 );
if(( mask & PAINT_WINDOW_TRANSFORMED ) && ( data.xScale != 1 || data.yScale != 1 ))
glScalef( data.xScale, data.yScale, 1 );
region.translate( toplevel->x(), toplevel->y() ); // Back to screen coords
if(shader)
prepareShaderRenderStates( mask, data );
else
prepareRenderStates( mask, data );
texture.bind();
texture.enableUnnormalizedTexCoords();
WindowQuadList decoration = data.quads.select( WindowQuadDecoration );
if( data.contents_opacity != data.decoration_opacity && !decoration.isEmpty())
{
prepareStates( data.opacity * data.contents_opacity, data.brightness, data.saturation );
renderQuads( mask, region, data.quads.select( WindowQuadContents ));
restoreStates( data.opacity * data.contents_opacity, data.brightness, data.saturation );
prepareStates( data.opacity * data.decoration_opacity, data.brightness, data.saturation );
renderQuads( mask, region, decoration );
restoreStates( data.opacity * data.decoration_opacity, data.brightness, data.saturation );
}
else
{
prepareStates( data.opacity * data.contents_opacity, data.brightness, data.saturation );
renderQuads( mask, region, data.quads.select( WindowQuadContents ));
renderQuads( mask, region, data.quads.select( WindowQuadDecoration ));
restoreStates( data.opacity * data.contents_opacity, data.brightness, data.saturation );
}
texture.disableUnnormalizedTexCoords();
texture.unbind();
glPopMatrix();
}
void SceneOpenGL::Window::renderQuads( int mask, const QRegion& region, const WindowQuadList& quads )
{
if( quads.isEmpty())
return;
// Render geometry
region.translate( toplevel->x(), toplevel->y() ); // Back to screen coords
float* vertices;
float* texcoords;
data.quads.makeArrays( &vertices, &texcoords );
renderGLGeometry( mask, region, data.quads.count() * 4,
quads.makeArrays( &vertices, &texcoords );
renderGLGeometry( mask, region, quads.count() * 4,
vertices, texcoords, NULL, 2, 0 );
delete[] vertices;
delete[] texcoords;
texture.disableUnnormalizedTexCoords();
glPopMatrix();
}
void SceneOpenGL::Window::prepareStates( double opacity, double brightness, double saturation )
{
if(shader)
restoreShaderRenderStates( mask, data );
prepareShaderRenderStates( opacity, brightness, saturation );
else
restoreRenderStates( mask, data );
texture.unbind();
prepareRenderStates( opacity, brightness, saturation );
}
void SceneOpenGL::Window::prepareShaderRenderStates( int mask, WindowPaintData data )
void SceneOpenGL::Window::prepareShaderRenderStates( double opacity, double brightness, double saturation )
{
Q_UNUSED( mask );
// setup blending of transparent windows
glPushAttrib( GL_ENABLE_BIT );
bool opaque = isOpaque() && data.opacity == 1.0;
bool opaque = isOpaque() && opacity == 1.0;
if( !opaque )
{
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
}
shader->setUniform("opacity", (float)data.opacity);
shader->setUniform("saturation", (float)data.saturation);
shader->setUniform("brightness", (float)data.brightness);
shader->setUniform("opacity", (float)opacity);
shader->setUniform("saturation", (float)saturation);
shader->setUniform("brightness", (float)brightness);
}
void SceneOpenGL::Window::prepareRenderStates( int mask, WindowPaintData data )
void SceneOpenGL::Window::prepareRenderStates( double opacity, double brightness, double saturation )
{
Q_UNUSED( mask );
// setup blending of transparent windows
glPushAttrib( GL_ENABLE_BIT );
bool opaque = isOpaque() && data.opacity == 1.0;
bool opaque = isOpaque() && opacity == 1.0;
if( !opaque )
{
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
}
if( data.saturation != 1.0 && texture.saturationSupported())
if( saturation != 1.0 && texture.saturationSupported())
{
// First we need to get the color from [0; 1] range to [0.5; 1] range
glActiveTexture( GL_TEXTURE0 );
@ -1252,7 +1274,7 @@ void SceneOpenGL::Window::prepareRenderStates( int mask, WindowPaintData data )
// Note that both operands have to be in range [0.5; 1] since opengl
// automatically substracts 0.5 from them
glActiveTexture( GL_TEXTURE1 );
float saturation_constant[] = { 0.5 + 0.5*0.30, 0.5 + 0.5*0.59, 0.5 + 0.5*0.11, data.saturation };
float saturation_constant[] = { 0.5 + 0.5*0.30, 0.5 + 0.5*0.59, 0.5 + 0.5*0.11, saturation };
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB );
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS );
@ -1279,10 +1301,10 @@ void SceneOpenGL::Window::prepareRenderStates( int mask, WindowPaintData data )
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PRIMARY_COLOR );
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA );
// And make primary color contain the wanted opacity
glColor4f( data.opacity, data.opacity, data.opacity, data.opacity );
glColor4f( opacity, opacity, opacity, opacity );
texture.bind();
if( toplevel->hasAlpha() || data.brightness != 1.0f )
if( toplevel->hasAlpha() || brightness != 1.0f )
{
glActiveTexture( GL_TEXTURE3 );
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
@ -1294,8 +1316,8 @@ void SceneOpenGL::Window::prepareRenderStates( int mask, WindowPaintData data )
if( toplevel->hasAlpha() )
{
// The color has to be multiplied by both opacity and brightness
float opacityByBrightness = data.opacity * data.brightness;
glColor4f( opacityByBrightness, opacityByBrightness, opacityByBrightness, data.opacity );
float opacityByBrightness = opacity * brightness;
glColor4f( opacityByBrightness, opacityByBrightness, opacityByBrightness, opacity );
// Also multiply original texture's alpha by our opacity
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE );
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE0 );
@ -1306,7 +1328,7 @@ void SceneOpenGL::Window::prepareRenderStates( int mask, WindowPaintData data )
else
{
// Color has to be multiplied only by brightness
glColor4f( data.brightness, data.brightness, data.brightness, data.opacity );
glColor4f( brightness, brightness, brightness, opacity );
// Alpha will be taken from previous stage
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE );
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS );
@ -1317,21 +1339,21 @@ void SceneOpenGL::Window::prepareRenderStates( int mask, WindowPaintData data )
glActiveTexture(GL_TEXTURE0 );
}
else if( data.opacity != 1.0 || data.brightness != 1.0 )
else if( opacity != 1.0 || brightness != 1.0 )
{
// the window is additionally configured to have its opacity adjusted,
// do it
if( toplevel->hasAlpha())
{
float opacityByBrightness = data.opacity * data.brightness;
float opacityByBrightness = opacity * brightness;
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glColor4f( opacityByBrightness, opacityByBrightness, opacityByBrightness,
data.opacity);
opacity);
}
else
{
// Multiply color by brightness and replace alpha by opacity
float constant[] = { data.brightness, data.brightness, data.brightness, data.opacity };
float constant[] = { brightness, brightness, brightness, opacity };
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE );
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE );
@ -1345,19 +1367,27 @@ void SceneOpenGL::Window::prepareRenderStates( int mask, WindowPaintData data )
}
}
void SceneOpenGL::Window::restoreShaderRenderStates( int mask, WindowPaintData data )
void SceneOpenGL::Window::restoreStates( double opacity, double brightness, double saturation )
{
Q_UNUSED( mask );
Q_UNUSED( data );
if(shader)
restoreShaderRenderStates( opacity, brightness, saturation );
else
restoreRenderStates( opacity, brightness, saturation );
}
void SceneOpenGL::Window::restoreShaderRenderStates( double opacity, double brightness, double saturation )
{
Q_UNUSED( opacity );
Q_UNUSED( brightness );
Q_UNUSED( saturation );
glPopAttrib(); // ENABLE_BIT
}
void SceneOpenGL::Window::restoreRenderStates( int mask, WindowPaintData data )
void SceneOpenGL::Window::restoreRenderStates( double opacity, double brightness, double saturation )
{
Q_UNUSED( mask );
if( data.opacity != 1.0 || data.saturation != 1.0 || data.brightness != 1.0f )
if( opacity != 1.0 || saturation != 1.0 || brightness != 1.0f )
{
if( data.saturation != 1.0 && texture.saturationSupported())
if( saturation != 1.0 && texture.saturationSupported())
{
glActiveTexture(GL_TEXTURE3);
glDisable( texture.target());

View file

@ -125,10 +125,13 @@ class SceneOpenGL::Window
void setShader( GLShader* s ) { shader = s; }
protected:
void prepareRenderStates( int mask, WindowPaintData data );
void prepareShaderRenderStates( int mask, WindowPaintData data );
void restoreRenderStates( int mask, WindowPaintData data );
void restoreShaderRenderStates( int mask, WindowPaintData data );
void renderQuads( int mask, const QRegion& region, const WindowQuadList& quads );
void prepareStates( double opacity, double brightness, double saturation );
void prepareRenderStates( double opacity, double brightness, double saturation );
void prepareShaderRenderStates( double opacity, double brightness, double saturation );
void restoreStates( double opacity, double brightness, double saturation );
void restoreRenderStates( double opacity, double brightness, double saturation );
void restoreShaderRenderStates( double opacity, double brightness, double saturation );
private:
Texture texture;