summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
Diffstat (limited to 'vcl')
-rw-r--r--vcl/Package_opengl.mk2
-rw-r--r--vcl/inc/opengl/program.hxx4
-rw-r--r--vcl/inc/openglgdiimpl.hxx4
-rw-r--r--vcl/opengl/gdiimpl.cxx364
-rw-r--r--vcl/opengl/lineFragmentShader.glsl36
-rw-r--r--vcl/opengl/lineVertexShader.glsl37
-rw-r--r--vcl/opengl/program.cxx10
7 files changed, 407 insertions, 50 deletions
diff --git a/vcl/Package_opengl.mk b/vcl/Package_opengl.mk
index b8851df57625..a0f6e9a27128 100644
--- a/vcl/Package_opengl.mk
+++ b/vcl/Package_opengl.mk
@@ -21,6 +21,8 @@ $(eval $(call gb_Package_add_files,vcl_opengl_shader,$(LIBO_ETC_FOLDER)/opengl,\
invert50FragmentShader.glsl \
convolutionFragmentShader.glsl \
linearGradientFragmentShader.glsl \
+ lineFragmentShader.glsl \
+ lineVertexShader.glsl \
maskFragmentShader.glsl \
maskedTextureVertexShader.glsl \
maskedTextureFragmentShader.glsl \
diff --git a/vcl/inc/opengl/program.hxx b/vcl/inc/opengl/program.hxx
index 5de3c1bdbe5f..780cba72380f 100644
--- a/vcl/inc/opengl/program.hxx
+++ b/vcl/inc/opengl/program.hxx
@@ -37,6 +37,7 @@ private:
GLuint mnTexCoordAttrib;
GLuint mnAlphaCoordAttrib;
GLuint mnMaskCoordAttrib;
+ GLuint mnNormalAttrib;
TextureList maTextures;
bool mbBlending;
@@ -59,6 +60,7 @@ public:
void SetTextureCoord( const GLvoid* pData );
void SetAlphaCoord( const GLvoid* pData );
void SetMaskCoord(const GLvoid* pData);
+ void SetExtrusionVectors(const GLvoid* pData);
void SetUniform1f( const OString& rName, GLfloat v1 );
void SetUniform2f( const OString& rName, GLfloat v1, GLfloat v2 );
@@ -80,7 +82,7 @@ public:
bool DrawTexture( const OpenGLTexture& rTexture );
protected:
- void SetVertexAttrib( GLuint& rAttrib, const OString& rName, const GLvoid* pData );
+ void SetVertexAttrib( GLuint& rAttrib, const OString& rName, const GLvoid* pData, GLint nSize = 2 );
GLuint GetUniformLocation( const OString& rName );
};
diff --git a/vcl/inc/openglgdiimpl.hxx b/vcl/inc/openglgdiimpl.hxx
index 3b629005c712..f3247f9f8d22 100644
--- a/vcl/inc/openglgdiimpl.hxx
+++ b/vcl/inc/openglgdiimpl.hxx
@@ -113,6 +113,7 @@ public:
bool UseSolid( SalColor nColor );
bool UseSolidAA( SalColor nColor, double fTransparency );
bool UseSolidAA( SalColor nColor );
+ bool UseLine(SalColor nColor, double fTransparency, GLfloat fLineWidth, bool bUseAA);
bool UseInvert50();
bool UseInvert(SalInvert nFlags);
@@ -127,6 +128,9 @@ public:
void DrawRect( long nX, long nY, long nWidth, long nHeight );
void DrawRect( const Rectangle& rRect );
void DrawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry );
+ void DrawLineSegment(float x1, float y1, float x2, float y2);
+ void DrawLineCap(float x1, float y1, float x2, float y2, css::drawing::LineCap eLineCap, float fLineWidth);
+ void DrawPolyLine( const basegfx::B2DPolygon& rPolygon, float fLineWidth, basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap);
void DrawPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPolygon, bool blockAA = false );
void DrawRegionBand( const RegionBand& rRegion );
void DrawTextureRect( OpenGLTexture& rTexture, const SalTwoRect& rPosAry, bool bInverted = false );
diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx
index 6828efb9b49d..2efac9741908 100644
--- a/vcl/opengl/gdiimpl.cxx
+++ b/vcl/opengl/gdiimpl.cxx
@@ -37,6 +37,9 @@
#include <vector>
+#include <glm/gtc/type_ptr.hpp>
+#include <glm/gtx/norm.hpp>
+
#include <stdlib.h>
class OpenGLFlushIdle : public Idle
@@ -624,6 +627,311 @@ void OpenGLSalGraphicsImpl::DrawLine( double nX1, double nY1, double nX2, double
CHECK_GL_ERROR();
}
+namespace
+{
+
+inline void addVertex(std::vector<GLfloat>& rVertices, std::vector<GLfloat>& rExtrusionVectors, glm::vec2 point, glm::vec2 extrusionVector, float length)
+{
+ rVertices.push_back(point.x);
+ rVertices.push_back(point.y);
+
+ rExtrusionVectors.push_back(extrusionVector.x);
+ rExtrusionVectors.push_back(extrusionVector.y);
+ rExtrusionVectors.push_back(length);
+}
+
+inline void addVertexPair(std::vector<GLfloat>& rVertices, std::vector<GLfloat>& rExtrusionVectors, glm::vec2 point, glm::vec2 extrusionVector, float length)
+{
+ addVertex(rVertices, rExtrusionVectors, point, -extrusionVector, -length);
+ addVertex(rVertices, rExtrusionVectors, point, extrusionVector, length);
+}
+
+inline glm::vec2 normalize(const glm::vec2& vector)
+{
+ if (glm::length(vector) > 0.0)
+ return glm::normalize(vector);
+ return vector;
+}
+
+} // end anonymous namespace
+
+void OpenGLSalGraphicsImpl::DrawLineCap(float x1, float y1, float x2, float y2, css::drawing::LineCap eLineCap, float fLineWidth)
+{
+ if (eLineCap != css::drawing::LineCap_ROUND && eLineCap != css::drawing::LineCap_SQUARE)
+ return;
+
+ OpenGLZone aZone;
+
+ const int nRoundCapIteration = 12;
+
+ std::vector<GLfloat> aVertices;
+ std::vector<GLfloat> aExtrusionVectors;
+
+ glm::vec2 p1(x1, y1);
+ glm::vec2 p2(x2, y2);
+ glm::vec2 lineVector = normalize(p2 - p1);
+ glm::vec2 normal = glm::vec2(-lineVector.y, lineVector.x);
+
+ if (eLineCap == css::drawing::LineCap_ROUND)
+ {
+ for (int nFactor = 0; nFactor <= nRoundCapIteration; nFactor++)
+ {
+ float angle = float(nFactor) * (M_PI / float(nRoundCapIteration));
+ glm::vec2 roundNormal(normal.x * glm::cos(angle) - normal.y * glm::sin(angle),
+ normal.x * glm::sin(angle) + normal.y * glm::cos(angle));
+
+ addVertexPair(aVertices, aExtrusionVectors, p1, roundNormal, 1.0f);
+ }
+ }
+ else if (eLineCap == css::drawing::LineCap_SQUARE)
+ {
+ glm::vec2 extrudedPoint = p1 + -lineVector * (fLineWidth / 2.0f);
+
+ addVertexPair(aVertices, aExtrusionVectors, extrudedPoint, normal, 1.0f);
+ addVertexPair(aVertices, aExtrusionVectors, p1, normal, 1.0f);
+ }
+
+ ApplyProgramMatrices(0.0f);
+ mpProgram->SetExtrusionVectors(aExtrusionVectors.data());
+ mpProgram->SetVertices(aVertices.data());
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, aVertices.size() / 2);
+
+ CHECK_GL_ERROR();
+}
+
+void OpenGLSalGraphicsImpl::DrawLineSegment(float x1, float y1, float x2, float y2)
+{
+ glm::vec2 p1(x1, y1);
+ glm::vec2 p2(x2, y2);
+
+ if (p1.x == p2.x && p1.y == p2.y)
+ return;
+
+ std::vector<GLfloat> aPoints;
+ std::vector<GLfloat> aExtrusionVectors;
+
+ OpenGLZone aZone;
+
+ glm::vec2 lineVector = normalize(p2 - p1);
+ glm::vec2 normal = glm::vec2(-lineVector.y, lineVector.x);
+
+ addVertexPair(aPoints, aExtrusionVectors, p1, normal, 1.0f);
+ addVertexPair(aPoints, aExtrusionVectors, p2, normal, 1.0f);
+
+ ApplyProgramMatrices(0.0f);
+ mpProgram->SetExtrusionVectors(aExtrusionVectors.data());
+ mpProgram->SetVertices(aPoints.data());
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, aPoints.size() / 2);
+
+ CHECK_GL_ERROR();
+}
+
+/** Draw a simple (non bezier) polyline
+ *
+ * OpenGL polyline drawing algorithm inspired by:
+ * - http://mattdesl.svbtle.com/drawing-lines-is-hard
+ * - https://www.mapbox.com/blog/drawing-antialiased-lines/
+ * - https://cesiumjs.org/2013/04/22/Robust-Polyline-Rendering-with-WebGL/
+ * - http://artgrammer.blogspot.si/2011/05/drawing-nearly-perfect-2d-line-segments.html
+ * - http://artgrammer.blogspot.si/2011/07/drawing-polylines-by-tessellation.html
+ *
+ */
+void OpenGLSalGraphicsImpl::DrawPolyLine(const basegfx::B2DPolygon& rPolygon, float fLineWidth, basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap)
+{
+ sal_uInt32 nPoints = rPolygon.count();
+ bool bClosed = rPolygon.isClosed();
+
+ if (!bClosed && nPoints >= 2)
+ {
+ // draw begin cap
+ {
+ glm::vec2 p1(rPolygon.getB2DPoint(0).getX(), rPolygon.getB2DPoint(0).getY());
+ glm::vec2 p2(rPolygon.getB2DPoint(1).getX(), rPolygon.getB2DPoint(1).getY());
+ DrawLineCap(p1.x, p1.y, p2.x, p2.y, eLineCap, fLineWidth);
+ }
+
+ // draw end cap
+ {
+ glm::vec2 p1(rPolygon.getB2DPoint(nPoints - 1).getX(), rPolygon.getB2DPoint(nPoints - 1).getY());
+ glm::vec2 p2(rPolygon.getB2DPoint(nPoints - 2).getX(), rPolygon.getB2DPoint(nPoints - 2).getY());
+ DrawLineCap(p1.x, p1.y, p2.x, p2.y, eLineCap, fLineWidth);
+ }
+ }
+
+ if (nPoints == 2 || eLineJoin == basegfx::B2DLineJoin::NONE)
+ {
+ // If line joint is NONE or a simple line with 2 points, draw the polyline
+ // each line segment separatly.
+ for (int i = 0; i < int(nPoints) - 1; ++i)
+ {
+ glm::vec2 p1(rPolygon.getB2DPoint(i+0).getX(), rPolygon.getB2DPoint(i+0).getY());
+ glm::vec2 p2(rPolygon.getB2DPoint(i+1).getX(), rPolygon.getB2DPoint(i+1).getY());
+ DrawLineSegment(p1.x, p1.y, p2.x, p2.y);
+ }
+ if (bClosed)
+ {
+ glm::vec2 p1(rPolygon.getB2DPoint(nPoints - 1).getX(), rPolygon.getB2DPoint(nPoints - 1).getY());
+ glm::vec2 p2(rPolygon.getB2DPoint(0).getX(), rPolygon.getB2DPoint(0).getY());
+ DrawLineSegment(p1.x, p1.y, p2.x, p2.y);
+ }
+ }
+ else if (nPoints > 2)
+ {
+ OpenGLZone aZone;
+
+ int i = 0;
+ int lastPoint = int(nPoints);
+
+ std::vector<GLfloat> aVertices;
+ std::vector<GLfloat> aExtrusionVectors;
+
+ // First guess on the size, but we could know relatively exactly
+ // how much vertices we need.
+ aVertices.reserve(nPoints * 4);
+ aExtrusionVectors.reserve(nPoints * 6);
+
+ // Handle first point
+
+ glm::vec2 nextLineVector;
+ glm::vec2 previousLineVector;
+ glm::vec2 normal; // perpendicular to the line vector
+
+ glm::vec2 p0(rPolygon.getB2DPoint(nPoints - 1).getX(), rPolygon.getB2DPoint(nPoints - 1).getY());
+ glm::vec2 p1(rPolygon.getB2DPoint(0).getX(), rPolygon.getB2DPoint(0).getY());
+ glm::vec2 p2(rPolygon.getB2DPoint(1).getX(), rPolygon.getB2DPoint(1).getY());
+
+ nextLineVector = normalize(p2 - p1);
+
+ if (!bClosed)
+ {
+ normal = glm::vec2(-nextLineVector.y, nextLineVector.x); // make perpendicular
+ addVertexPair(aVertices, aExtrusionVectors, p1, normal, 1.0f);
+
+ i++; // first point done already
+ lastPoint--; // last point will be calculated separatly from the loop
+
+ p0 = p1;
+ previousLineVector = nextLineVector;
+ }
+ else
+ {
+ lastPoint++; // we need to connect last point to first point so one more line segment to calculate
+
+ previousLineVector = normalize(p1 - p0);
+ }
+
+ for (; i < lastPoint; ++i)
+ {
+ int index1 = (i + 0) % nPoints; // loop indices - important when polyline is closed
+ int index2 = (i + 1) % nPoints;
+
+ p1 = glm::vec2(rPolygon.getB2DPoint(index1).getX(), rPolygon.getB2DPoint(index1).getY());
+ p2 = glm::vec2(rPolygon.getB2DPoint(index2).getX(), rPolygon.getB2DPoint(index2).getY());
+
+ if (p1 == p2) // skip equal points, normals could div-by-0
+ continue;
+
+ nextLineVector = normalize(p2 - p1);
+
+ if (eLineJoin == basegfx::B2DLineJoin::Miter)
+ {
+ // With miter join we calculate the extrusion vector by adding normals of
+ // previous and next line segment. The vector shows the way but we also
+ // need the length (otherwise the line will be deformed). Length factor is
+ // calculated as dot product of extrusion vector and one of the normals.
+ // The value we get is the inverse length (used in the shader):
+ // length = line_width / dot(extrusionVector, normal)
+
+ normal = glm::vec2(-previousLineVector.y, previousLineVector.x);
+
+ glm::vec2 tangent = normalize(nextLineVector + previousLineVector);
+ glm::vec2 extrusionVector(-tangent.y, tangent.x);
+ GLfloat length = glm::dot(extrusionVector, normal);
+
+ addVertexPair(aVertices, aExtrusionVectors, p1, extrusionVector, length);
+ }
+ else if (eLineJoin == basegfx::B2DLineJoin::Bevel)
+ {
+ // For bevel join we just add 2 additional vertices and use previous
+ // line segment normal and next line segment normal as extrusion vector.
+ // All the magic is done by the fact that we draw triangle strips, so we
+ // cover the joins correctly.
+
+ glm::vec2 previousNormal = glm::vec2(-previousLineVector.y, previousLineVector.x);
+ glm::vec2 nextNormal = glm::vec2(-nextLineVector.y, nextLineVector.x);
+
+ addVertexPair(aVertices, aExtrusionVectors, p1, previousNormal, 1.0f);
+ addVertexPair(aVertices, aExtrusionVectors, p1, nextNormal, 1.0f);
+ }
+ else if (eLineJoin == basegfx::B2DLineJoin::Round)
+ {
+ // For round join we do a similar thing as in bevel, we add more intermediate
+ // vertices and add normals to get extrusion vectors in the between the
+ // both normals.
+
+ // 3 additional extrusion vectors + normals are enough to make most
+ // line joins look round. Ideally the number of vectors could be
+ // calculated.
+
+ glm::vec2 previousNormal = glm::vec2(-previousLineVector.y, previousLineVector.x);
+ glm::vec2 nextNormal = glm::vec2(-nextLineVector.y, nextLineVector.x);
+
+ glm::vec2 middle = normalize(previousNormal + nextNormal);
+ glm::vec2 middleLeft = normalize(previousNormal + middle);
+ glm::vec2 middleRight = normalize(middle + nextNormal);
+
+ addVertexPair(aVertices, aExtrusionVectors, p1, previousNormal, 1.0f);
+ addVertexPair(aVertices, aExtrusionVectors, p1, middleLeft, 1.0f);
+ addVertexPair(aVertices, aExtrusionVectors, p1, middle, 1.0f);
+ addVertexPair(aVertices, aExtrusionVectors, p1, middleRight, 1.0f);
+ addVertexPair(aVertices, aExtrusionVectors, p1, nextNormal, 1.0f);
+ }
+ p0 = p1;
+ previousLineVector = nextLineVector;
+ }
+
+ if (!bClosed)
+ {
+ // Create vertices for the last point. There is no line join so just
+ // use the last line segment normal as the extrusion vector.
+
+ p1 = glm::vec2(rPolygon.getB2DPoint(nPoints - 1).getX(), rPolygon.getB2DPoint(nPoints - 1).getY());
+
+ normal = glm::vec2(-previousLineVector.y, previousLineVector.x);
+
+ addVertexPair(aVertices, aExtrusionVectors, p1, normal, 1.0f);
+ }
+
+ ApplyProgramMatrices(0.0f);
+ mpProgram->SetExtrusionVectors(aExtrusionVectors.data());
+ mpProgram->SetVertices(aVertices.data());
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, aVertices.size() / 2);
+
+ CHECK_GL_ERROR();
+ }
+}
+
+bool OpenGLSalGraphicsImpl::UseLine(SalColor nColor, double fTransparency, GLfloat fLineWidth, bool bUseAA)
+{
+ if( nColor == SALCOLOR_NONE )
+ return false;
+ if( !UseProgram( "lineVertexShader", "lineFragmentShader" ) )
+ return false;
+ mpProgram->SetColorf("color", nColor, fTransparency);
+ mpProgram->SetUniform1f("line_width", fLineWidth);
+ // The width of the feather - area we make lineary transparent in VS.
+ // Good AA value is 0.5, 0.0 means the no AA will be done.
+ mpProgram->SetUniform1f("feather", bUseAA ? 0.5f : 0.0f);
+ // We need blending or AA won't work correctly
+ mpProgram->SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+#ifdef DBG_UTIL
+ mProgramIsSolidColor = true;
+#endif
+ mProgramSolidColor = nColor;
+ mProgramSolidTransparency = fTransparency;
+ return true;
+}
+
void OpenGLSalGraphicsImpl::DrawLineAA( double nX1, double nY1, double nX2, double nY2 )
{
OpenGLZone aZone;
@@ -1539,58 +1847,20 @@ bool OpenGLSalGraphicsImpl::drawPolyLine(
return true;
const bool bIsHairline = (rLineWidth.getX() == rLineWidth.getY()) && (rLineWidth.getX() <= 1.2);
+ const float fLineWidth = bIsHairline ? 1.0f : rLineWidth.getX();
- // #i101491#
- if( !bIsHairline && (rPolygon.count() > 1000) )
- {
- // the used basegfx::tools::createAreaGeometry is simply too
- // expensive with very big polygons; fallback to caller (who
- // should use ImplLineConverter normally)
- // AW: ImplLineConverter had to be removed since it does not even
- // know LineJoins, so the fallback will now prepare the line geometry
- // the same way.
- return false;
- }
-
- // shortcut for hairline drawing to improve performance
- if (bIsHairline)
- {
- // Let's just leave it to OutputDevice to do the bezier subdivision,
- // drawPolyLine(sal_uInt32 nPoints, const SalPoint* pPtAry) will be
- // called with the result.
- return false;
- }
-
- // #i11575#desc5#b adjust B2D tesselation result to raster positions
- basegfx::B2DPolygon aPolygon = rPolygon;
- const double fHalfWidth = 0.5 * rLineWidth.getX();
+ PreDraw(XOROption::IMPLEMENT_XOR);
- // get the area polygon for the line polygon
- if( (rLineWidth.getX() != rLineWidth.getY())
- && !basegfx::fTools::equalZero( rLineWidth.getY() ) )
+ if (UseLine(mnLineColor, 0.0f, fLineWidth, true))
{
- // prepare for createAreaGeometry() with anisotropic linewidth
- aPolygon.transform( basegfx::tools::createScaleB2DHomMatrix(1.0, rLineWidth.getX() / rLineWidth.getY()));
- }
-
- // create the area-polygon for the line
- const basegfx::B2DPolyPolygon aAreaPolyPoly( basegfx::tools::createAreaGeometry(aPolygon, fHalfWidth, eLineJoin, eLineCap) );
+ basegfx::B2DPolygon aPolygon(rPolygon);
- if( (rLineWidth.getX() != rLineWidth.getY())
- && !basegfx::fTools::equalZero( rLineWidth.getX() ) )
- {
- // postprocess createAreaGeometry() for anisotropic linewidth
- aPolygon.transform(basegfx::tools::createScaleB2DHomMatrix(1.0, rLineWidth.getY() / rLineWidth.getX()));
- }
+ if (aPolygon.areControlPointsUsed())
+ aPolygon = basegfx::tools::polygonSubdivide(aPolygon, 5 * F_PI180);
+ else
+ aPolygon.removeDoublePoints();
- PreDraw( XOROption::IMPLEMENT_XOR );
- if( UseSolid( mnLineColor, fTransparency ) )
- {
- for( sal_uInt32 i = 0; i < aAreaPolyPoly.count(); i++ )
- {
- const basegfx::B2DPolyPolygon aOnePoly( aAreaPolyPoly.getB2DPolygon( i ) );
- DrawPolyPolygon( aOnePoly );
- }
+ DrawPolyLine(aPolygon, fLineWidth, eLineJoin, eLineCap);
}
PostDraw();
diff --git a/vcl/opengl/lineFragmentShader.glsl b/vcl/opengl/lineFragmentShader.glsl
new file mode 100644
index 000000000000..a8c73d6b80cc
--- /dev/null
+++ b/vcl/opengl/lineFragmentShader.glsl
@@ -0,0 +1,36 @@
+/* -*- 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/.
+ */
+
+varying float fade_factor; // 0->1 fade factor used for AA
+uniform vec4 color;
+
+uniform float line_width;
+uniform float feather;
+
+void main()
+{
+ float start = (line_width / 2.0) - feather; // where we start to apply alpha
+ float end = (line_width / 2.0) + feather; // where we end to apply alpha
+
+ // Calculate the multiplier so we can transform the 0->1 fade factor
+ // to take feather and line width into account.
+ float multiplied = 1.0 / (1.0 - (start / end));
+
+ float dist = (1.0 - abs(fade_factor)) * multiplied;
+
+ float alpha = clamp(dist, 0.0, 1.0);
+
+ // modify the alpha chanel only
+ vec4 result_color = color;
+ result_color.a = result_color.a * alpha;
+
+ gl_FragColor = result_color;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/opengl/lineVertexShader.glsl b/vcl/opengl/lineVertexShader.glsl
new file mode 100644
index 000000000000..0adcb4908201
--- /dev/null
+++ b/vcl/opengl/lineVertexShader.glsl
@@ -0,0 +1,37 @@
+/* -*- 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/.
+ */
+
+attribute vec2 position;
+attribute vec4 extrusion_vectors;
+
+varying float fade_factor; // fade factor for anti-aliasing
+
+uniform float line_width;
+uniform float feather; // width where we fade the line
+
+uniform mat4 mvp;
+
+void main()
+{
+ vec2 extrusion_vector = extrusion_vectors.xy;
+ // miter factor to additionaly lenghten the distance of vertex (needed for miter)
+ // if 1.0 - miter_factor has no effect
+ float miter_factor = 1.0f / abs(extrusion_vectors.z);
+ // fade factor is always -1.0 or 1.0 -> we transport that info together with length
+ fade_factor = sign(extrusion_vectors.z);
+
+ float rendered_thickness = (line_width + feather * 2.0) * miter_factor;
+
+ // lengthen the vertex in directon of the extrusion vector by line width.
+ vec4 position = vec4(position + (extrusion_vector * (rendered_thickness / 2.0) ), 0.0, 1.0);
+
+ gl_Position = mvp * position;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/opengl/program.cxx b/vcl/opengl/program.cxx
index 588700b537d9..340b10f6bb8f 100644
--- a/vcl/opengl/program.cxx
+++ b/vcl/opengl/program.cxx
@@ -22,6 +22,7 @@ OpenGLProgram::OpenGLProgram() :
mnTexCoordAttrib( SAL_MAX_UINT32 ),
mnAlphaCoordAttrib( SAL_MAX_UINT32 ),
mnMaskCoordAttrib( SAL_MAX_UINT32 ),
+ mnNormalAttrib( SAL_MAX_UINT32 ),
mbBlending( false ),
mfLastWidth(0.0),
mfLastHeight(0.0),
@@ -100,7 +101,7 @@ bool OpenGLProgram::Clean()
return true;
}
-void OpenGLProgram::SetVertexAttrib( GLuint& rAttrib, const OString& rName, const GLvoid* pData )
+void OpenGLProgram::SetVertexAttrib( GLuint& rAttrib, const OString& rName, const GLvoid* pData, GLint nSize )
{
if( rAttrib == SAL_MAX_UINT32 )
{
@@ -113,7 +114,7 @@ void OpenGLProgram::SetVertexAttrib( GLuint& rAttrib, const OString& rName, cons
CHECK_GL_ERROR();
mnEnabledAttribs |= ( 1 << rAttrib );
}
- glVertexAttribPointer( rAttrib, 2, GL_FLOAT, GL_FALSE, 0, pData );
+ glVertexAttribPointer( rAttrib, nSize, GL_FLOAT, GL_FALSE, 0, pData );
CHECK_GL_ERROR();
}
@@ -137,6 +138,11 @@ void OpenGLProgram::SetMaskCoord(const GLvoid* pData)
SetVertexAttrib(mnMaskCoordAttrib, "mask_coord_in", pData);
}
+void OpenGLProgram::SetExtrusionVectors(const GLvoid* pData)
+{
+ SetVertexAttrib(mnNormalAttrib, "extrusion_vectors", pData, 3);
+}
+
GLuint OpenGLProgram::GetUniformLocation( const OString& rName )
{
auto it = maUniformLocations.find( rName );