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] / vertex redesign [Seli]
affects alpha clear hack affects alpha clear hack
- support applying opacity only to decoration
- not using ARGB visuals - not using ARGB visuals
- handling of window pixmaps for unmapped windows [Seli] - handling of window pixmaps for unmapped windows [Seli]
@ -302,9 +301,6 @@ Effects TODO
/ implements all effects Kompmgr could do / implements all effects Kompmgr could do
+ - all effects from the Opacity tab should be already doable + - 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 ! - not usign ARGB visuals
- just clear the alpha channel in the alpha clear hack - just clear the alpha channel in the alpha clear hack
- or do it while painting (see also the alpha clear hack todo entry) - 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 ) 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 ) 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_TRANSLUCENT;
data.mask &= ~PAINT_WINDOW_OPAQUE; 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 ) void MakeTransparentEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
{ {
if( w->isDialog()) if( decoration != 1.0 )
data.opacity *= 0.8; data.decoration_opacity *= decoration;
if( w->isUserMove() || w->isUserResize()) if( dialogs != 1.0 && w->isDialog())
data.opacity *= 0.5; data.opacity *= dialogs;
if( moveresize != 1.0 && ( w->isUserMove() || w->isUserResize()))
data.opacity *= moveresize;
effects->paintWindow( w, mask, region, data ); effects->paintWindow( w, mask, region, data );
} }
void MakeTransparentEffect::windowUserMovedResized( EffectWindow* w, bool first, bool last ) void MakeTransparentEffect::windowUserMovedResized( EffectWindow* w, bool first, bool last )
{ {
if( first || last ) if( moveresize != 1.0 && ( first || last ))
w->addRepaintFull(); w->addRepaintFull();
} }

View file

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

View file

@ -24,6 +24,8 @@ namespace KWin
WindowPaintData::WindowPaintData() WindowPaintData::WindowPaintData()
: opacity( 1.0 ) : opacity( 1.0 )
, contents_opacity( 1.0 )
, decoration_opacity( 1.0 )
, xScale( 1 ) , xScale( 1 )
, yScale( 1 ) , yScale( 1 )
, xTranslate( 0 ) , xTranslate( 0 )
@ -417,7 +419,7 @@ WindowQuadList WindowQuadList::makeGrid( int maxquadsize ) const
return ret; return ret;
} }
void WindowQuadList::makeArrays( float** vertices, float** texcoords ) void WindowQuadList::makeArrays( float** vertices, float** texcoords ) const
{ {
*vertices = new float[ count() * 4 * 2 ]; *vertices = new float[ count() * 4 * 2 ];
*texcoords = 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 WindowQuadList WindowQuadList::filterOut( WindowQuadType type ) const
{ {
foreach( WindowQuad q, *this ) foreach( WindowQuad q, *this )

View file

@ -415,9 +415,10 @@ class KWIN_EXPORT WindowQuadList
WindowQuadList splitAtX( float x ) const; WindowQuadList splitAtX( float x ) const;
WindowQuadList splitAtY( float y ) const; WindowQuadList splitAtY( float y ) const;
WindowQuadList makeGrid( int maxquadsize ) const; WindowQuadList makeGrid( int maxquadsize ) const;
WindowQuadList select( WindowQuadType type ) const;
WindowQuadList filterOut( WindowQuadType type ) const; WindowQuadList filterOut( WindowQuadType type ) const;
bool smoothNeeded() const; bool smoothNeeded() const;
void makeArrays( float** vertices, float** texcoords ); void makeArrays( float** vertices, float** texcoords ) const;
}; };
class KWIN_EXPORT WindowPrePaintData class KWIN_EXPORT WindowPrePaintData
@ -435,8 +436,12 @@ class KWIN_EXPORT WindowPaintData
WindowPaintData(); WindowPaintData();
/** /**
* Window opacity, in range 0 = transparent to 1 = fully opaque * 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 opacity;
double contents_opacity;
double decoration_opacity;
double xScale; double xScale;
double yScale; double yScale;
int xTranslate; int xTranslate;

View file

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

View file

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