diff options
author | Louis-Francis Ratté-Boulianne <lfrb@collabora.com> | 2014-11-11 15:54:03 -0500 |
---|---|---|
committer | Markus Mohrhard <markus.mohrhard@collabora.co.uk> | 2014-11-12 04:07:31 +0100 |
commit | e1e787d5e418a328f8023d3b777384b98441a9de (patch) | |
tree | 1021452c507f2a5cb5fbe5b581c3e51c94597717 | |
parent | vcl: Read back OpenGL FBO to create offscreen X11 pixmap (diff) | |
download | core-e1e787d5e418a328f8023d3b777384b98441a9de.tar.gz core-e1e787d5e418a328f8023d3b777384b98441a9de.zip |
vcl: Add support for radial gradients in OpenGL backend
Change-Id: Ie47fb18ae7d5286fe7559c7dffbc54b0856d4d8e
-rw-r--r-- | vcl/Package_opengl.mk | 1 | ||||
-rw-r--r-- | vcl/inc/openglgdiimpl.hxx | 9 | ||||
-rw-r--r-- | vcl/opengl/gdiimpl.cxx | 118 | ||||
-rw-r--r-- | vcl/opengl/radialGradientFragmentShader.glsl | 23 |
4 files changed, 132 insertions, 19 deletions
diff --git a/vcl/Package_opengl.mk b/vcl/Package_opengl.mk index da40d7130939..18c56fcd07b8 100644 --- a/vcl/Package_opengl.mk +++ b/vcl/Package_opengl.mk @@ -16,6 +16,7 @@ $(eval $(call gb_Package_add_files,vcl_opengl_shader,$(LIBO_ETC_FOLDER)/opengl,\ maskVertexShader.glsl \ maskedTextureFragmentShader.glsl \ maskedTextureVertexShader.glsl \ + radialGradientFragmentShader.glsl \ solidFragmentShader.glsl \ solidVertexShader.glsl \ textureFragmentShader.glsl \ diff --git a/vcl/inc/openglgdiimpl.hxx b/vcl/inc/openglgdiimpl.hxx index 535bc722a364..f80c9699a403 100644 --- a/vcl/inc/openglgdiimpl.hxx +++ b/vcl/inc/openglgdiimpl.hxx @@ -63,13 +63,18 @@ protected: GLuint mnLinearGradientProgram; GLuint mnLinearGradientStartColorUniform; GLuint mnLinearGradientEndColorUniform; - GLuint mnLinearGradientTransformUniform; + + GLuint mnRadialGradientProgram; + GLuint mnRadialGradientStartColorUniform; + GLuint mnRadialGradientEndColorUniform; + GLuint mnRadialGradientCenterUniform; bool CreateSolidProgram( void ); bool CreateTextureProgram( void ); bool CreateMaskedTextureProgram( void ); bool CreateMaskProgram( void ); bool CreateLinearGradientProgram( void ); + bool CreateRadialGradientProgram( void ); void BeginSolid( SalColor nColor, sal_uInt8 nTransparency ); void BeginSolid( SalColor nColor, double fTransparency ); @@ -84,6 +89,7 @@ protected: void DrawConvexPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ); void DrawConvexPolygon( const Polygon& rPolygon ); void DrawRect( long nX, long nY, long nWidth, long nHeight ); + void DrawRect( const Rectangle& rRect ); void DrawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ); void DrawPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPolygon ); void DrawTextureRect( const Size& rSize, const SalTwoRect& rPosAry, bool bInverted = false ); @@ -91,6 +97,7 @@ protected: void DrawTextureWithMask( GLuint nTexture, GLuint nMask, const Size& rSize, const SalTwoRect& rPosAry ); void DrawMask( GLuint nMask, SalColor nMaskColor, const SalTwoRect& rPosAry ); void DrawLinearGradient( const Gradient& rGradient, const Rectangle& rRect ); + void DrawRadialGradient( const Gradient& rGradient, const Rectangle& rRect ); protected: // get the width of the device diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx index 65c4f3089017..744aa7fa541b 100644 --- a/vcl/opengl/gdiimpl.cxx +++ b/vcl/opengl/gdiimpl.cxx @@ -75,6 +75,13 @@ OpenGLSalGraphicsImpl::OpenGLSalGraphicsImpl() , mnMaskProgram(0) , mnMaskUniform(0) , mnMaskColorUniform(0) + , mnLinearGradientProgram(0) + , mnLinearGradientStartColorUniform(0) + , mnLinearGradientEndColorUniform(0) + , mnRadialGradientProgram(0) + , mnRadialGradientStartColorUniform(0) + , mnRadialGradientEndColorUniform(0) + , mnRadialGradientCenterUniform(0) { } @@ -295,7 +302,20 @@ bool OpenGLSalGraphicsImpl::CreateLinearGradientProgram( void ) glBindAttribLocation( mnTextureProgram, GL_ATTRIB_TEX, "tex_coord_in" ); mnLinearGradientStartColorUniform = glGetUniformLocation( mnLinearGradientProgram, "start_color" ); mnLinearGradientEndColorUniform = glGetUniformLocation( mnLinearGradientProgram, "end_color" ); - mnLinearGradientTransformUniform = glGetUniformLocation( mnLinearGradientProgram, "transform" ); + return true; +} + +bool OpenGLSalGraphicsImpl::CreateRadialGradientProgram( void ) +{ + mnRadialGradientProgram = OpenGLHelper::LoadShaders( "textureVertexShader", "radialGradientFragmentShader" ); + if( mnRadialGradientProgram == 0 ) + return false; + + glBindAttribLocation( mnTextureProgram, GL_ATTRIB_POS, "position" ); + glBindAttribLocation( mnTextureProgram, GL_ATTRIB_TEX, "tex_coord_in" ); + mnRadialGradientStartColorUniform = glGetUniformLocation( mnRadialGradientProgram, "start_color" ); + mnRadialGradientEndColorUniform = glGetUniformLocation( mnRadialGradientProgram, "end_color" ); + mnRadialGradientCenterUniform = glGetUniformLocation( mnRadialGradientProgram, "center" ); return true; } @@ -455,6 +475,18 @@ void OpenGLSalGraphicsImpl::DrawRect( long nX, long nY, long nWidth, long nHeigh DrawConvexPolygon( 4, aPoints ); } +void OpenGLSalGraphicsImpl::DrawRect( const Rectangle& rRect ) +{ + long nX1( rRect.Left() ); + long nY1( GetHeight() - rRect.Top() ); + long nX2( rRect.Right() ); + long nY2( GetHeight() - rRect.Bottom() ); + const SalPoint aPoints[] = { { nX1, nY2 }, { nX1, nY1 }, + { nX2, nY1 }, { nX2, nY2 }}; + + DrawConvexPolygon( 4, aPoints ); +} + void OpenGLSalGraphicsImpl::DrawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) { ::basegfx::B2DPolygon aPolygon; @@ -601,18 +633,6 @@ void OpenGLSalGraphicsImpl::DrawMask( GLuint nMask, SalColor nMaskColor, const S void OpenGLSalGraphicsImpl::DrawLinearGradient( const Gradient& rGradient, const Rectangle& rRect ) { - if( rGradient.GetBorder() >= 100.0 ) - { - // border >= 100%, draw solid rectangle - Color aCol = rGradient.GetStartColor(); - long nF = rGradient.GetStartIntensity(); - BeginSolid( MAKE_SALCOLOR( aCol.GetRed() * nF / 100, - aCol.GetGreen() * nF / 100, - aCol.GetBlue() * nF / 100 ) ); - DrawRect( rRect.Left(), rRect.Top(), rRect.GetWidth(), rRect.GetHeight() ); - EndSolid(); - return; - } if( mnLinearGradientProgram == 0 ) { @@ -632,10 +652,6 @@ void OpenGLSalGraphicsImpl::DrawLinearGradient( const Gradient& rGradient, const Rectangle aBoundRect; Point aCenter; rGradient.GetBoundRect( rRect, aBoundRect, aCenter ); - aBoundRect.Left()--; - aBoundRect.Top()--; - aBoundRect.Right()++; - aBoundRect.Bottom()++; Polygon aPoly( aBoundRect ); aPoly.Rotate( aCenter, rGradient.GetAngle() % 3600 ); @@ -653,6 +669,43 @@ void OpenGLSalGraphicsImpl::DrawLinearGradient( const Gradient& rGradient, const glUseProgram( 0 ); } +void OpenGLSalGraphicsImpl::DrawRadialGradient( const Gradient& rGradient, const Rectangle& rRect ) +{ + if( mnRadialGradientProgram == 0 ) + { + if( !CreateRadialGradientProgram() ) + return; + } + + glUseProgram( mnRadialGradientProgram ); + + Color aStartCol = rGradient.GetStartColor(); + Color aEndCol = rGradient.GetEndColor(); + long nFactor = rGradient.GetStartIntensity(); + glUniformColorIntensity( mnRadialGradientStartColorUniform, aStartCol, nFactor ); + nFactor = rGradient.GetEndIntensity(); + glUniformColorIntensity( mnRadialGradientEndColorUniform, aEndCol, nFactor ); + + Rectangle aRect; + Point aCenter; + rGradient.GetBoundRect( rRect, aRect, aCenter ); + + // adjust coordinates so that radius has distance equals to 1.0 + double fRadius = aRect.GetWidth() / 2.0f; + GLfloat fWidth = rRect.GetWidth() / fRadius; + GLfloat fHeight = rRect.GetHeight() / fRadius; + glUniform2f( mnRadialGradientCenterUniform, (aCenter.X() -rRect.Left()) / fRadius, (aCenter.Y() - rRect.Top()) / fRadius ); + + GLfloat aTexCoord[8] = { 0, 0, 0, fHeight, fWidth, fHeight, fWidth, 0 }; + glEnableVertexAttribArray( GL_ATTRIB_TEX ); + glVertexAttribPointer( GL_ATTRIB_TEX, 2, GL_FLOAT, GL_FALSE, 0, aTexCoord ); + + DrawRect( rRect ); + + glDisableVertexAttribArray( GL_ATTRIB_TEX ); + glUseProgram( 0 ); +} + // draw --> LineColor and FillColor and RasterOp and ClipRegion void OpenGLSalGraphicsImpl::drawPixel( long nX, long nY ) @@ -1189,11 +1242,33 @@ bool OpenGLSalGraphicsImpl::drawAlphaRect( bool OpenGLSalGraphicsImpl::drawGradient(const tools::PolyPolygon& rPolyPoly, const Gradient& rGradient) { - const Rectangle aBoundRect( rPolyPoly.GetBoundRect() ); + Rectangle aBoundRect( rPolyPoly.GetBoundRect() ); + + SAL_INFO( "vcl.opengl", "::drawGradient" ); if( aBoundRect.IsEmpty() ) return true; + aBoundRect.Left()--; + aBoundRect.Top()--; + aBoundRect.Right()++; + aBoundRect.Bottom()++; + + // if border >= 100%, draw solid rectangle with start color + if( rGradient.GetBorder() >= 100.0 ) + { + Color aCol = rGradient.GetStartColor(); + long nF = rGradient.GetStartIntensity(); + PreDraw(); + BeginSolid( MAKE_SALCOLOR( aCol.GetRed() * nF / 100, + aCol.GetGreen() * nF / 100, + aCol.GetBlue() * nF / 100 ) ); + DrawRect( aBoundRect ); + EndSolid(); + PostDraw(); + return true; + } + //TODO: lfrb: some missing transformation with the polygon in outdev if( rGradient.GetStyle() == GradientStyle_LINEAR ) { @@ -1202,6 +1277,13 @@ bool OpenGLSalGraphicsImpl::drawGradient(const tools::PolyPolygon& rPolyPoly, PostDraw(); return true; } + else if( rGradient.GetStyle() == GradientStyle_RADIAL ) + { + PreDraw(); + DrawRadialGradient( rGradient, aBoundRect ); + PostDraw(); + return true; + } return false; } diff --git a/vcl/opengl/radialGradientFragmentShader.glsl b/vcl/opengl/radialGradientFragmentShader.glsl new file mode 100644 index 000000000000..94a86eb9510f --- /dev/null +++ b/vcl/opengl/radialGradientFragmentShader.glsl @@ -0,0 +1,23 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#version 120 + +uniform vec4 start_color; +uniform vec4 end_color; +uniform vec2 center; +varying vec2 tex_coord; + +void main(void) +{ + gl_FragColor = mix(end_color, start_color, + clamp(distance(tex_coord, center), 0.0, 1.0)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |