[Libreoffice-commits] core.git: vcl/inc vcl/Library_vcl.mk vcl/opengl

Tomaž Vajngerl tomaz.vajngerl at collabora.co.uk
Wed Jun 8 08:13:32 UTC 2016


 vcl/Library_vcl.mk                     |    1 
 vcl/inc/opengl/BufferObject.hxx        |   89 ++++++++
 vcl/inc/opengl/LineRenderUtils.hxx     |   54 ++++
 vcl/inc/opengl/RenderList.hxx          |   30 +-
 vcl/inc/opengl/VertexUtils.hxx         |  112 ++++------
 vcl/inc/opengl/program.hxx             |   14 -
 vcl/inc/openglgdiimpl.hxx              |    4 
 vcl/opengl/LineRenderUtils.cxx         |  185 ++++++++++++++++
 vcl/opengl/RenderList.cxx              |  314 +++++++++++++++++++++-------
 vcl/opengl/combinedFragmentShader.glsl |   20 -
 vcl/opengl/combinedVertexShader.glsl   |   32 ++
 vcl/opengl/gdiimpl.cxx                 |  361 +++++----------------------------
 vcl/opengl/program.cxx                 |   28 +-
 13 files changed, 750 insertions(+), 494 deletions(-)

New commits:
commit ce72e34b359c323ef7ff96a70500810a9cd8703a
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
Date:   Tue Jun 7 20:45:14 2016 +0900

    opengl: batch drawing of polylines
    
    To get polylines to draw in a batch it was necessary to refactor
    the polyline code to work with GL_TRIANGLES instead of the previous
    used GL_TRIANGLE_STRIP. For this and to make the code easier to
    handle a new class was introduced: LineBuilder, which purpose is
    to assemble vertices for a polyline (line ends, line joints).
    
    In addition we need to know the line width, anti-aliasing (AA) per
    vertex basis (in addition to color, normal and extrusion) so we
    can draw many polylines with one draw call. This info is now
    stored in Vertex struct which is used when drawing lines or
    triangles (fills).
    
    Uploading of vertices has also been changed, previously we
    uploaded the vertices with the drawcall. a convention in Modern
    OpenGL is however to use VBO (Vertex Buffer Object) for this.
    With this we can upload the to the GPU vertices independently
    and not upload them if this is not needed (which is currently
    not used yet). A vector of Vertex structs is now uploaded to the
    GPU using a VBO which is handeled with a new VertexBufferObject
    class.
    
    In addition to reduce the ammount of duplicated vertices, we use
    a index vector (handled by IndexBufferObject class) where we only
    define the indices of the vertex buffer which should be drawn.
    
    Change-Id: I49dc9c6260b459f4f4ce3a5e4fa4c8ad05a7b878

diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index 06e3153..40dd0cd 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -622,6 +622,7 @@ else
 	vcl/opengl/FixedTextureAtlas \
 	vcl/opengl/PackedTextureAtlas \
 	vcl/opengl/RenderList \
+	vcl/opengl/LineRenderUtils \
     vcl/source/opengl/OpenGLContext \
     vcl/source/opengl/OpenGLHelper \
     vcl/source/window/openglwin \
diff --git a/vcl/inc/opengl/BufferObject.hxx b/vcl/inc/opengl/BufferObject.hxx
new file mode 100644
index 0000000..3cda66d
--- /dev/null
+++ b/vcl/inc/opengl/BufferObject.hxx
@@ -0,0 +1,89 @@
+/* -*- 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/.
+ *
+ */
+
+#ifndef INCLUDED_VCL_INC_OPENGL_BUFFEROBJECT_H
+#define INCLUDED_VCL_INC_OPENGL_BUFFEROBJECT_H
+
+namespace vcl
+{
+
+template<typename TYPE, GLenum BUFFER_TYPE>
+class BufferObject
+{
+private:
+    GLuint mId;
+
+public:
+    BufferObject()
+        : mId(0)
+    {
+        glGenBuffers(1, &mId);
+        CHECK_GL_ERROR();
+    }
+
+    virtual ~BufferObject()
+    {
+        dispose();
+    }
+
+    void bind()
+    {
+        if (mId)
+        {
+            glBindBuffer(BUFFER_TYPE, mId);
+            CHECK_GL_ERROR();
+        }
+    }
+
+    void unbind()
+    {
+        if (mId)
+        {
+            glBindBuffer(BUFFER_TYPE, 0);
+            CHECK_GL_ERROR();
+        }
+    }
+
+    void upload(const std::vector<TYPE>& rData)
+    {
+        if (mId)
+        {
+            bind();
+            glBufferData(BUFFER_TYPE, sizeof(TYPE) * rData.size(), rData.data(), GL_STATIC_DRAW);
+            CHECK_GL_ERROR();
+        }
+    }
+
+    void dispose()
+    {
+        if (mId)
+        {
+            glDeleteBuffers(1, &mId);
+            CHECK_GL_ERROR();
+            mId = 0;
+        }
+    }
+
+};
+
+template<typename TYPE>
+class VertexBufferObject : public BufferObject<TYPE, GL_ARRAY_BUFFER>
+{
+};
+
+class IndexBufferObject : public BufferObject<GLuint, GL_ELEMENT_ARRAY_BUFFER>
+{
+};
+
+} // end vcl
+
+#endif // INCLUDED_VCL_INC_OPENGL_BUFFEROBJECT_H
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/opengl/LineRenderUtils.hxx b/vcl/inc/opengl/LineRenderUtils.hxx
new file mode 100644
index 0000000..7c9018a
--- /dev/null
+++ b/vcl/inc/opengl/LineRenderUtils.hxx
@@ -0,0 +1,54 @@
+/* -*- 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/.
+ *
+ */
+
+#ifndef INCLUDED_VCL_INC_OPENGL_LINERENDERUTILS_H
+#define INCLUDED_VCL_INC_OPENGL_LINERENDERUTILS_H
+
+#include <GL/glew.h>
+#include "opengl/VertexUtils.hxx"
+#include "opengl/RenderList.hxx"
+
+namespace vcl
+{
+class LineBuilder
+{
+private:
+    std::vector<Vertex>& mrVertices;
+    std::vector<GLuint>& mrIndices;
+    GLubyte mR, mG, mB, mA;
+    GLfloat mfLineWidth;
+    GLfloat mfLineWidthAndAA;
+    size_t mnInitialIndexSize;
+    bool mbIncomplete;
+
+public:
+    LineBuilder(std::vector<Vertex>& rVertices, std::vector<GLuint>& rIndices,
+                SalColor nColor, GLfloat fTransparency,
+                GLfloat fLineWidth, bool bUseAA);
+
+    void appendLineSegment(const glm::vec2& rPoint1, const glm::vec2& rNormal1, GLfloat aExtrusion1,
+                           const glm::vec2& rPoint2, const glm::vec2& rNormal2, GLfloat aExtrusion2);
+
+    void appendLine(const glm::vec2& rPoint1, const glm::vec2& rPoint2);
+
+    void appendAndConnectLinePoint(const glm::vec2& rPoint, const glm::vec2& aNormal, GLfloat aExtrusion);
+
+    void appendMiterJoint(glm::vec2 point, glm::vec2 prevLineVector, glm::vec2 nextLineVector);
+    void appendBevelJoint(glm::vec2 point, glm::vec2 prevLineVector, glm::vec2 nextLineVector);
+    void appendRoundJoint(glm::vec2 point, glm::vec2 prevLineVector, glm::vec2 nextLineVector);
+    void appendRoundLineCapVertices(const glm::vec2& rPoint1, const glm::vec2& rPoint2);
+    void appendSquareLineCapVertices(const glm::vec2& rPoint1, const glm::vec2& rPoint2);
+};
+
+} // end vcl
+
+#endif // INCLUDED_VCL_INC_OPENGL_LINERENDERUTILS_H
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/opengl/RenderList.hxx b/vcl/inc/opengl/RenderList.hxx
index f6f59f5..062971e 100644
--- a/vcl/inc/opengl/RenderList.hxx
+++ b/vcl/inc/opengl/RenderList.hxx
@@ -21,18 +21,29 @@
 
 #include "opengl/texture.hxx"
 
+#include <com/sun/star/drawing/LineCap.hpp>
+
+struct Vertex
+{
+    glm::vec2 position;
+    glm::vec4 color;
+    glm::vec4 lineData;
+};
+
+static_assert(sizeof(Vertex) == (2*4 + 4*4 + 4*4), "Vertex struct has wrong size/alignment");
+
+
 struct RenderParameters
 {
-    std::vector<GLfloat>   maVertices;
-    std::vector<GLfloat>   maExtrusionVectors;
-    std::vector<glm::vec4> maColors;
+    std::vector<Vertex> maVertices;
+    std::vector<GLuint> maIndices;
 };
 
 struct RenderTextureParameters
 {
     std::vector<GLfloat>   maVertices;
-    std::vector<glm::vec4> maColors;
     std::vector<GLfloat>   maTextureCoords;
+    std::vector<GLubyte>   maColors;
     OpenGLTexture          maTexture;
 };
 
@@ -42,7 +53,6 @@ struct RenderEntry
 
     RenderParameters maTriangleParameters;
     RenderParameters maLineParameters;
-    RenderParameters maLineAAParameters;
 
     std::unordered_map<GLuint, RenderTextureParameters> maTextureParametersMap;
 
@@ -56,11 +66,6 @@ struct RenderEntry
         return !maLineParameters.maVertices.empty();
     }
 
-    bool hasLinesAA()
-    {
-        return !maLineAAParameters.maVertices.empty();
-    }
-
     bool hasTextures()
     {
         return !maTextureParametersMap.empty();
@@ -156,6 +161,11 @@ public:
 
     void addDrawPolyPolygon(const basegfx::B2DPolyPolygon& rPolyPolygon, double fTransparency,
                             SalColor nLineColor, SalColor nFillColor, bool bUseAA);
+
+    void addDrawPolyLine(const basegfx::B2DPolygon& rPolygon, double fTransparency,
+                         const basegfx::B2DVector& rLineWidth, basegfx::B2DLineJoin eLineJoin,
+                         css::drawing::LineCap eLineCap, double fMiterMinimumAngle,
+                         SalColor nLineColor, bool bUseAA);
 };
 
 #endif // INCLUDED_VCL_INC_OPENGL_RENDERLIST_H
diff --git a/vcl/inc/opengl/VertexUtils.hxx b/vcl/inc/opengl/VertexUtils.hxx
index 6de658e..f9804ec 100644
--- a/vcl/inc/opengl/VertexUtils.hxx
+++ b/vcl/inc/opengl/VertexUtils.hxx
@@ -11,7 +11,11 @@
 #ifndef INCLUDED_VCL_INC_OPENGL_VERTEXUTILS_H
 #define INCLUDED_VCL_INC_OPENGL_VERTEXUTILS_H
 
+#include <basegfx/numeric/ftools.hxx>
+#include <GL/glew.h>
 #include <glm/gtx/norm.hpp>
+#include <vcl/salgtype.hxx>
+#include <vector>
 
 namespace vcl
 {
@@ -39,96 +43,74 @@ inline void addRectangle<GL_TRIANGLE_FAN>(std::vector<GLfloat>& rVertices, GLflo
     });
 }
 
-template<GLenum TYPE>
-inline void addTrapezoid(std::vector<GLfloat>& rVertices, GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2,
-                                                          GLfloat x3, GLfloat y3, GLfloat x4, GLfloat y4);
-
-template<>
-inline void addTrapezoid<GL_TRIANGLES>(std::vector<GLfloat>& rVertices, GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2,
-                                                                        GLfloat x3, GLfloat y3, GLfloat x4, GLfloat y4)
+inline void createColor(SalColor nColor, GLfloat fTransparency, GLubyte& nR, GLubyte& nG, GLubyte& nB, GLubyte& nA)
 {
-    rVertices.insert(rVertices.end(), {
-        x1, y1, x2, y2, x3, y3,
-        x3, y3, x2, y2, x4, y4
-    });
-}
-
-inline glm::vec4 createGLColor(SalColor nColor, GLfloat rTransparency)
-{
-    return glm::vec4(SALCOLOR_RED(nColor)   / 255.0f,
-                     SALCOLOR_GREEN(nColor) / 255.0f,
-                     SALCOLOR_BLUE(nColor)  / 255.0f,
-                     1.0f - rTransparency);
+    nR = SALCOLOR_RED(nColor);
+    nG = SALCOLOR_GREEN(nColor);
+    nB = SALCOLOR_BLUE(nColor);
+    nA = (1.0f - fTransparency) * 255.0f;
 }
 
 template<GLenum TYPE>
-inline void addQuadColors(std::vector<glm::vec4>& rColors, SalColor nColor, GLfloat rTransparency);
+inline void addQuadColors(std::vector<GLubyte>& rColors, SalColor nColor, GLfloat fTransparency);
 
 template<>
-inline void addQuadColors<GL_TRIANGLES>(std::vector<glm::vec4>& rColors, SalColor nColor, GLfloat rTransparency)
+inline void addQuadColors<GL_TRIANGLES>(std::vector<GLubyte>& rColors, SalColor nColor, GLfloat fTransparency)
 {
-    glm::vec4 color = createGLColor(nColor, rTransparency);
+    GLubyte nR, nG, nB, nA;
+    createColor(nColor, fTransparency, nR, nG, nB, nA);
 
     rColors.insert(rColors.end(), {
-        color, color, color,
-        color, color, color
+        nR, nG, nB, nA,
+        nR, nG, nB, nA,
+        nR, nG, nB, nA,
+        nR, nG, nB, nA,
+        nR, nG, nB, nA,
+        nR, nG, nB, nA,
     });
 }
 
-template<GLenum TYPE>
-inline void addQuadEmptyExtrusionVectors(std::vector<GLfloat>& rExtrusions);
-
-template<>
-inline void addQuadEmptyExtrusionVectors<GL_TRIANGLES>(std::vector<GLfloat>& rExtrusions)
+inline void addLineSegmentVertices(std::vector<GLfloat>& rVertices, std::vector<GLfloat>& rExtrusionVectors,
+                                   glm::vec2 prevPoint, glm::vec2 prevExtrusionVector, GLfloat prevLength,
+                                   glm::vec2 currPoint, glm::vec2 currExtrusionVector, GLfloat currLength)
 {
-    rExtrusions.insert(rExtrusions.end(), {
-        0.0f, 0.0f, 0.0f,
-        0.0f, 0.0f, 0.0f,
-        0.0f, 0.0f, 0.0f,
-        0.0f, 0.0f, 0.0f,
-        0.0f, 0.0f, 0.0f,
-        0.0f, 0.0f, 0.0f,
+    rVertices.insert(rVertices.end(), {
+        prevPoint.x, prevPoint.y,
+        prevPoint.x, prevPoint.y,
+        currPoint.x, currPoint.y,
+        currPoint.x, currPoint.y,
+        prevPoint.x, prevPoint.y,
+        currPoint.x, currPoint.y,
     });
-}
 
-inline void addLineVertex(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);
+    rExtrusionVectors.insert(rExtrusionVectors.end(), {
+        -prevExtrusionVector.x, -prevExtrusionVector.y, -prevLength,
+         prevExtrusionVector.x,  prevExtrusionVector.y,  prevLength,
+        -currExtrusionVector.x, -currExtrusionVector.y, -currLength,
+        -currExtrusionVector.x, -currExtrusionVector.y, -currLength,
+         prevExtrusionVector.x,  prevExtrusionVector.y,  prevLength,
+         currExtrusionVector.x,  currExtrusionVector.y,  currLength,
+    });
 }
 
-inline void addLineVertexPair(std::vector<GLfloat>& rVertices, std::vector<GLfloat>& rExtrusionVectors, const glm::vec2& point, const glm::vec2& extrusionVector, float length)
+inline glm::vec2 normalize(const glm::vec2& vector)
 {
-    addLineVertex(rVertices, rExtrusionVectors, point, -extrusionVector, -length);
-    addLineVertex(rVertices, rExtrusionVectors, point,  extrusionVector,  length);
+    if (glm::length(vector) > 0.0)
+        return glm::normalize(vector);
+    return vector;
 }
 
-inline void addLinePointFirst(std::vector<GLfloat>& rVertices, std::vector<GLfloat>& rExtrusionVectors,
-                               glm::vec2 point, glm::vec2 extrusionVector, float length)
+inline glm::vec2 perpendicular(const glm::vec2& vector)
 {
-    addLineVertex(rVertices, rExtrusionVectors, point, -extrusionVector, -length);
-    addLineVertex(rVertices, rExtrusionVectors, point,  extrusionVector,  length);
+    return glm::vec2(-vector.y, vector.x);
 }
 
-inline void addLinePointNext(std::vector<GLfloat>& rVertices, std::vector<GLfloat>& rExtrusionVectors,
-                             glm::vec2 prevPoint, glm::vec2 prevExtrusionVector, float prevLength,
-                             glm::vec2 currPoint, glm::vec2 currExtrusionVector, float currLength)
+inline float lineVectorAngle(const glm::vec2& previous, const glm::vec2& next)
 {
-    addLineVertex(rVertices, rExtrusionVectors, currPoint, -currExtrusionVector, -currLength);
-    addLineVertex(rVertices, rExtrusionVectors, currPoint, -currExtrusionVector, -currLength);
-    addLineVertex(rVertices, rExtrusionVectors, prevPoint,  prevExtrusionVector,  prevLength);
-    addLineVertex(rVertices, rExtrusionVectors, currPoint,  currExtrusionVector,  currLength);
-}
+    float angle = std::atan2(previous.x * next.y - previous.y * next.x,
+                             previous.x * next.x + previous.y * next.y);
 
-inline glm::vec2 normalize(const glm::vec2& vector)
-{
-    if (glm::length(vector) > 0.0)
-        return glm::normalize(vector);
-    return vector;
+    return F_PI - std::fabs(angle);
 }
 
 }} // end vcl::vertex
diff --git a/vcl/inc/opengl/program.hxx b/vcl/inc/opengl/program.hxx
index c737c12..b32aa05 100644
--- a/vcl/inc/opengl/program.hxx
+++ b/vcl/inc/opengl/program.hxx
@@ -22,7 +22,6 @@
 #include <tools/color.hxx>
 #include <opengl/texture.hxx>
 
-#include <glm/glm.hpp>
 #include <unordered_map>
 
 typedef std::unordered_map< OString, GLuint, OStringHash > UniformCache;
@@ -82,7 +81,7 @@ public:
     void SetAlphaCoord( const GLvoid* pData );
     void SetMaskCoord(const GLvoid* pData);
     void SetExtrusionVectors(const GLvoid* pData);
-    void SetVertexColors(std::vector<glm::vec4>& rColorVector);
+    void SetVertexColors(std::vector<GLubyte>& rColorVector);
 
     void SetUniform1f( const OString& rName, GLfloat v1 );
     void SetUniform2f( const OString& rName, GLfloat v1, GLfloat v2 );
@@ -107,11 +106,16 @@ public:
 
     bool DrawTexture( const OpenGLTexture& rTexture );
 
-    void DrawArrays(GLenum GLenum, std::vector<GLfloat>& aVertices);
+    void DrawArrays(GLenum aMode, std::vector<GLfloat>& aVertices);
+    void DrawElements(GLenum aMode, GLuint nNumberOfVertices);
 
-protected:
     bool EnableVertexAttrib(GLuint& rAttrib, const OString& rName);
-    void SetVertexAttrib( GLuint& rAttrib, const OString& rName, const GLvoid* pData, GLint nSize = 2 );
+
+    void SetVertexAttrib(GLuint& rAttrib, const OString& rName, GLint nSize,
+                         GLenum eType, GLboolean bNormalized, GLsizei aStride,
+                         const GLvoid* pPointer);
+
+protected:
     GLuint GetUniformLocation( const OString& rName );
 };
 
diff --git a/vcl/inc/openglgdiimpl.hxx b/vcl/inc/openglgdiimpl.hxx
index 2c8d47c9..d0b5f9a 100644
--- a/vcl/inc/openglgdiimpl.hxx
+++ b/vcl/inc/openglgdiimpl.hxx
@@ -127,8 +127,6 @@ public:
     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, float fMiterMinimumAngle);
     void DrawPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPolygon, bool blockAA = false );
     void DrawRegionBand( const RegionBand& rRegion );
     void DrawTextureRect( OpenGLTexture& rTexture, const SalTwoRect& rPosAry, bool bInverted = false );
@@ -143,7 +141,9 @@ public:
     void DrawAxialGradient( const Gradient& rGradient, const Rectangle& rRect );
     void DrawRadialGradient( const Gradient& rGradient, const Rectangle& rRect );
     void DeferredTextDraw(OpenGLTexture& rTexture, const SalColor nMaskColor, const SalTwoRect& rPosAry);
+
     void FlushDeferredDrawing();
+    bool FlushLinesOrTriangles(DrawShaderType eType, RenderParameters& rParameters);
 
 public:
     // get the width of the device
diff --git a/vcl/opengl/LineRenderUtils.cxx b/vcl/opengl/LineRenderUtils.cxx
new file mode 100644
index 0000000..1b7fb99
--- /dev/null
+++ b/vcl/opengl/LineRenderUtils.cxx
@@ -0,0 +1,185 @@
+/* -*- 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/.
+ *
+ */
+
+#include "opengl/LineRenderUtils.hxx"
+
+namespace vcl
+{
+
+LineBuilder::LineBuilder(std::vector<Vertex>& rVertices, std::vector<GLuint>& rIndices,
+                SalColor nColor, GLfloat fTransparency,
+                GLfloat fLineWidth, bool bUseAA)
+    : mrVertices(rVertices)
+    , mrIndices(rIndices)
+    , mR(SALCOLOR_RED(nColor))
+    , mG(SALCOLOR_GREEN(nColor))
+    , mB(SALCOLOR_BLUE(nColor))
+    , mA((1.0f - fTransparency) * 255.0f)
+    , mfLineWidth(fLineWidth)
+    , mfLineWidthAndAA(bUseAA ? fLineWidth : -fLineWidth)
+    , mnInitialIndexSize(rIndices.size())
+    , mbIncomplete(false)
+{
+}
+
+void LineBuilder::appendLineSegment(const glm::vec2& rPoint1, const glm::vec2& rNormal1, GLfloat aExtrusion1,
+                                    const glm::vec2& rPoint2, const glm::vec2& rNormal2, GLfloat aExtrusion2)
+{
+    GLuint zero = mrVertices.size();
+
+    mrVertices.insert(mrVertices.end(), {
+        Vertex{rPoint1, glm::vec4{mR, mG, mB, mA}, glm::vec4{-rNormal1.x, -rNormal1.y, -aExtrusion1, mfLineWidthAndAA}},
+        Vertex{rPoint1, glm::vec4{mR, mG, mB, mA}, glm::vec4{ rNormal1.x,  rNormal1.y,  aExtrusion1, mfLineWidthAndAA}},
+        Vertex{rPoint2, glm::vec4{mR, mG, mB, mA}, glm::vec4{-rNormal2.x, -rNormal2.y, -aExtrusion2, mfLineWidthAndAA}},
+        Vertex{rPoint2, glm::vec4{mR, mG, mB, mA}, glm::vec4{ rNormal2.x,  rNormal2.y,  aExtrusion2, mfLineWidthAndAA}},
+    });
+
+    mrIndices.insert(mrIndices.end(), {
+        zero + 0, zero + 1, zero + 2,
+        zero + 2, zero + 1, zero + 3
+    });
+
+}
+
+void LineBuilder::appendLine(const glm::vec2& rPoint1, const glm::vec2& rPoint2)
+{
+    glm::vec2 aLineVector = vcl::vertex::normalize(rPoint2 - rPoint1);
+    glm::vec2 aNormal = vcl::vertex::perpendicular(aLineVector);
+
+    appendLineSegment(rPoint1, aNormal, 1.0f,
+                      rPoint2, aNormal, 1.0f);
+}
+
+void LineBuilder::appendAndConnectLinePoint(const glm::vec2& rPoint, const glm::vec2& aNormal, GLfloat aExtrusion)
+{
+    GLuint zero = mrVertices.size();
+
+    mrVertices.insert(mrVertices.end(), {
+        Vertex{rPoint, glm::vec4{mR, mG, mB, mA}, glm::vec4{-aNormal.x, -aNormal.y, -aExtrusion, mfLineWidthAndAA}},
+        Vertex{rPoint, glm::vec4{mR, mG, mB, mA}, glm::vec4{ aNormal.x,  aNormal.y,  aExtrusion, mfLineWidthAndAA}},
+    });
+
+    if (mnInitialIndexSize == mrIndices.size())
+    {
+        mrIndices.insert(mrIndices.end(), {
+            zero + 0, zero + 1
+        });
+        mbIncomplete = true;
+    }
+    else
+    {
+        if (mbIncomplete)
+        {
+            mrIndices.insert(mrIndices.end(), {
+                                    zero + 0,
+                zero + 0, zero - 1, zero + 1
+            });
+            mbIncomplete = false;
+        }
+        else
+        {
+            mrIndices.insert(mrIndices.end(), {
+                zero - 2, zero - 1, zero + 0,
+                zero + 0, zero - 1, zero + 1
+            });
+        }
+    }
+}
+
+void LineBuilder::appendMiterJoint(glm::vec2 point, glm::vec2 prevLineVector, glm::vec2 nextLineVector)
+{
+    // 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)
+
+    glm::vec2 normal(-prevLineVector.y, prevLineVector.x);
+
+    glm::vec2 tangent = vcl::vertex::normalize(nextLineVector + prevLineVector);
+    glm::vec2 extrusionVector(-tangent.y, tangent.x);
+    GLfloat length = glm::dot(extrusionVector, normal);
+
+    appendAndConnectLinePoint(point, extrusionVector, length);
+}
+
+void LineBuilder::appendBevelJoint(glm::vec2 point, glm::vec2 prevLineVector, glm::vec2 nextLineVector)
+{
+    // 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 prevNormal = glm::vec2(-prevLineVector.y, prevLineVector.x);
+    glm::vec2 nextNormal = glm::vec2(-nextLineVector.y, nextLineVector.x);
+
+    appendAndConnectLinePoint(point, prevNormal, 1.0f);
+    appendAndConnectLinePoint(point, nextNormal, 1.0f);
+}
+
+void LineBuilder::appendRoundJoint(glm::vec2 point, glm::vec2 prevLineVector, glm::vec2 nextLineVector)
+{
+    // 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 prevNormal = glm::vec2(-prevLineVector.y, prevLineVector.x);
+    glm::vec2 nextNormal = glm::vec2(-nextLineVector.y, nextLineVector.x);
+
+    glm::vec2 middle = vcl::vertex::normalize(prevNormal + nextNormal);
+    glm::vec2 middleLeft  = vcl::vertex::normalize(prevNormal + middle);
+    glm::vec2 middleRight = vcl::vertex::normalize(middle + nextNormal);
+
+    appendAndConnectLinePoint(point, prevNormal, 1.0f);
+    appendAndConnectLinePoint(point, middleLeft, 1.0f);
+    appendAndConnectLinePoint(point, middle, 1.0f);
+    appendAndConnectLinePoint(point, middleRight, 1.0f);
+    appendAndConnectLinePoint(point, nextNormal, 1.0f);
+}
+
+void LineBuilder::appendRoundLineCapVertices(const glm::vec2& rPoint1, const glm::vec2& rPoint2)
+{
+    SAL_CONSTEXPR const int nRoundCapIteration = 12;
+
+    glm::vec2 lineVector = vcl::vertex::normalize(rPoint2 - rPoint1);
+    glm::vec2 normal = glm::vec2(-lineVector.y, lineVector.x);
+    glm::vec2 previousRoundNormal = normal;
+
+    for (int nFactor = 1; 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));
+
+        appendLineSegment(rPoint1, previousRoundNormal, 1.0f,
+                          rPoint1, roundNormal, 1.0f);
+        previousRoundNormal = roundNormal;
+    }
+}
+
+void LineBuilder::appendSquareLineCapVertices(const glm::vec2& rPoint1, const glm::vec2& rPoint2)
+{
+    glm::vec2 lineVector = vcl::vertex::normalize(rPoint2 - rPoint1);
+    glm::vec2 normal = glm::vec2(-lineVector.y, lineVector.x);
+
+    glm::vec2 extrudedPoint = rPoint1 + -lineVector * (mfLineWidth / 2.0f);
+
+    appendLineSegment(extrudedPoint, normal, 1.0f,
+                      rPoint1,       normal, 1.0f);
+}
+
+} // end vcl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/opengl/RenderList.cxx b/vcl/opengl/RenderList.cxx
index aee6a04..5c59002 100644
--- a/vcl/opengl/RenderList.cxx
+++ b/vcl/opengl/RenderList.cxx
@@ -10,6 +10,7 @@
 
 #include "opengl/RenderList.hxx"
 #include "opengl/VertexUtils.hxx"
+#include "opengl/LineRenderUtils.hxx"
 
 #include <basegfx/polygon/b2dpolygontools.hxx>
 #include <basegfx/polygon/b2dpolygontriangulator.hxx>
@@ -19,22 +20,177 @@
 namespace
 {
 
-inline void lclAddLineSegmentVertices(RenderParameters& rRenderParameter, GLfloat fX1, GLfloat fY1, GLfloat fX2, GLfloat fY2,
-                                      SalColor nColor, double fTransparency)
+/** Append vertices for the 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 appendPolyLine(vcl::LineBuilder& rBuilder, const basegfx::B2DPolygon& rPolygon,
+                    basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap,
+                    double fMiterMinimumAngle)
 {
-    glm::vec2 aPoint1(fX1, fY1);
-    glm::vec2 aPoint2(fX2, fY2);
+    sal_uInt32 nPoints = rPolygon.count();
+    bool bClosed = rPolygon.isClosed();
+
+    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 (sal_uInt32 i = 0; i < (bClosed ? nPoints : nPoints - 1); ++i)
+        {
+            sal_uInt32 index1 = (i + 0) % nPoints; // loop indices - important when polyline is closed
+            sal_uInt32 index2 = (i + 1) % nPoints;
+
+            glm::vec2 aPoint1(rPolygon.getB2DPoint(index1).getX(), rPolygon.getB2DPoint(index1).getY());
+            glm::vec2 aPoint2(rPolygon.getB2DPoint(index2).getX(), rPolygon.getB2DPoint(index2).getY());
+
+            rBuilder.appendLine(aPoint1, aPoint2);
+        }
+    }
+    else if (nPoints > 2)
+    {
+        int i = 0;
+        int lastPoint = int(nPoints);
 
-    glm::vec2 aLineVector = vcl::vertex::normalize(aPoint2 - aPoint1);
-    glm::vec2 aNormal = glm::vec2(-aLineVector.y, aLineVector.x);
+        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());
 
-    vcl::vertex::addLinePointFirst(rRenderParameter.maVertices, rRenderParameter.maExtrusionVectors,
-                                   aPoint1, aNormal, 1.0f);
-    vcl::vertex::addLinePointNext (rRenderParameter.maVertices, rRenderParameter.maExtrusionVectors,
-                                   aPoint1, aNormal, 1.0f,
-                                   aPoint2, aNormal, 1.0f);
+        glm::vec2 nextLineVector;
+        glm::vec2 previousLineVector;
+        glm::vec2 normal; // perpendicular to the line vector
 
-    vcl::vertex::addQuadColors<GL_TRIANGLES>(rRenderParameter.maColors, nColor, fTransparency);
+        nextLineVector = vcl::vertex::normalize(p2 - p1);
+
+        if (!bClosed)
+        {
+            normal = glm::vec2(-nextLineVector.y, nextLineVector.x); // make perpendicular
+            rBuilder.appendAndConnectLinePoint(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 = vcl::vertex::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 = vcl::vertex::normalize(p2 - p1);
+
+            if (eLineJoin == basegfx::B2DLineJoin::Miter)
+            {
+                if (vcl::vertex::lineVectorAngle(previousLineVector, nextLineVector) < fMiterMinimumAngle)
+                    rBuilder.appendBevelJoint(p1, previousLineVector, nextLineVector);
+                else
+                    rBuilder.appendMiterJoint(p1, previousLineVector, nextLineVector);
+            }
+            else if (eLineJoin == basegfx::B2DLineJoin::Bevel)
+            {
+                rBuilder.appendBevelJoint(p1, previousLineVector, nextLineVector);
+            }
+            else if (eLineJoin == basegfx::B2DLineJoin::Round)
+            {
+                rBuilder.appendRoundJoint(p1, previousLineVector, nextLineVector);
+            }
+            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);
+            rBuilder.appendAndConnectLinePoint(p1, normal, 1.0f);
+        }
+    }
+
+    if (!bClosed && nPoints >= 2 && (eLineCap == css::drawing::LineCap_ROUND || eLineCap == css::drawing::LineCap_SQUARE))
+    {
+        glm::vec2 aBeginCapPoint1(rPolygon.getB2DPoint(0).getX(), rPolygon.getB2DPoint(0).getY());
+        glm::vec2 aBeginCapPoint2(rPolygon.getB2DPoint(1).getX(), rPolygon.getB2DPoint(1).getY());
+
+        glm::vec2 aEndCapPoint1(rPolygon.getB2DPoint(nPoints - 1).getX(), rPolygon.getB2DPoint(nPoints - 1).getY());
+        glm::vec2 aEndCapPoint2(rPolygon.getB2DPoint(nPoints - 2).getX(), rPolygon.getB2DPoint(nPoints - 2).getY());
+
+        if (eLineCap == css::drawing::LineCap_ROUND)
+        {
+            rBuilder.appendRoundLineCapVertices(aBeginCapPoint1, aBeginCapPoint2);
+            rBuilder.appendRoundLineCapVertices(aEndCapPoint1, aEndCapPoint2);
+        }
+        else if (eLineCap == css::drawing::LineCap_SQUARE)
+        {
+            rBuilder.appendSquareLineCapVertices(aBeginCapPoint1, aBeginCapPoint2);
+            rBuilder.appendSquareLineCapVertices(aEndCapPoint1, aEndCapPoint2);
+        }
+    }
+}
+
+inline void appendTrapezoid(std::vector<Vertex>& rVertices, std::vector<GLuint>& rIndices,
+                       GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2,
+                       GLfloat x3, GLfloat y3, GLfloat x4, GLfloat y4,
+                       SalColor nColor, GLfloat fTransparency)
+{
+    GLubyte nR, nG, nB, nA;
+    vcl::vertex::createColor(nColor, fTransparency, nR, nG, nB, nA);
+
+    GLuint zero = rVertices.size();
+
+    rVertices.insert(rVertices.end(), {
+        Vertex{glm::vec2{x1, y1}, glm::vec4{nR, nG, nB, nA}, glm::vec4{0.0f, 0.0f, 0.0f, 0.0f}},
+        Vertex{glm::vec2{x2, y2}, glm::vec4{nR, nG, nB, nA}, glm::vec4{0.0f, 0.0f, 0.0f, 0.0f}},
+        Vertex{glm::vec2{x3, y3}, glm::vec4{nR, nG, nB, nA}, glm::vec4{0.0f, 0.0f, 0.0f, 0.0f}},
+        Vertex{glm::vec2{x4, y4}, glm::vec4{nR, nG, nB, nA}, glm::vec4{0.0f, 0.0f, 0.0f, 0.0f}},
+    });
+
+    rIndices.insert(rIndices.end(), {
+        zero + 0, zero + 1, zero + 2,
+        zero + 2, zero + 1, zero + 3
+    });
+}
+
+void appendRectangle(std::vector<Vertex>& rVertices, std::vector<GLuint>& rIndices,
+                     GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2,
+                     SalColor nColor, GLfloat fTransparency)
+{
+    GLubyte nR, nG, nB, nA;
+    vcl::vertex::createColor(nColor, fTransparency, nR, nG, nB, nA);
+
+    GLuint zero = rVertices.size();
+
+    rVertices.insert(rVertices.end(), {
+        Vertex{glm::vec2{x1, y1}, glm::vec4{nR, nG, nB, nA}, glm::vec4{0.0f, 0.0f, 0.0f, 0.0f}},
+        Vertex{glm::vec2{x2, y1}, glm::vec4{nR, nG, nB, nA}, glm::vec4{0.0f, 0.0f, 0.0f, 0.0f}},
+        Vertex{glm::vec2{x1, y2}, glm::vec4{nR, nG, nB, nA}, glm::vec4{0.0f, 0.0f, 0.0f, 0.0f}},
+        Vertex{glm::vec2{x2, y2}, glm::vec4{nR, nG, nB, nA}, glm::vec4{0.0f, 0.0f, 0.0f, 0.0f}},
+    });
+
+    rIndices.insert(rIndices.end(), {
+        zero + 0, zero + 1, zero + 2,
+        zero + 2, zero + 1, zero + 3
+    });
 }
 
 } // end anonymous namespace
@@ -47,9 +203,8 @@ void RenderList::addDrawPixel(long nX, long nY, SalColor nColor)
     checkOverlapping(basegfx::B2DRange(nX, nY, nX, nY));
 
     RenderParameters& rRenderParameter = maRenderEntries.back().maTriangleParameters;
-    vcl::vertex::addRectangle<GL_TRIANGLES>(rRenderParameter.maVertices, nX - 0.5f, nY - 0.5f, nX + 0.5f, nY + 0.5f);
-    vcl::vertex::addQuadColors<GL_TRIANGLES>(rRenderParameter.maColors, nColor, 0.0f);
-    vcl::vertex::addQuadEmptyExtrusionVectors<GL_TRIANGLES>(rRenderParameter.maExtrusionVectors);
+    appendRectangle(rRenderParameter.maVertices, rRenderParameter.maIndices,
+                    nX - 0.5f, nY - 0.5f, nX + 0.5f, nY + 0.5f, nColor, 0.0f);
 }
 
 void RenderList::addDrawRectangle(long nX, long nY, long nWidth, long nHeight, double fTransparency,
@@ -72,46 +227,32 @@ void RenderList::addDrawRectangle(long nX, long nY, long nWidth, long nHeight, d
     // Draw rectangle stroke with line color
     if (nLineColor != SALCOLOR_NONE)
     {
-        vcl::vertex::addRectangle<GL_TRIANGLES>(rRenderParameter.maVertices, fX1 - 0.5f, fY1 - 0.5f, fX1 + 0.5f, fY2 + 0.5f);
-        vcl::vertex::addRectangle<GL_TRIANGLES>(rRenderParameter.maVertices, fX1 - 0.5f, fY1 - 0.5f, fX2 + 0.5f, fY1 + 0.5f);
-        vcl::vertex::addRectangle<GL_TRIANGLES>(rRenderParameter.maVertices, fX2 - 0.5f, fY1 - 0.5f, fX2 + 0.5f, fY2 + 0.5f);
-        vcl::vertex::addRectangle<GL_TRIANGLES>(rRenderParameter.maVertices, fX1 - 0.5f, fY2 - 0.5f, fX2 + 0.5f, fY2 + 0.5f);
-
-        vcl::vertex::addQuadColors<GL_TRIANGLES>(rRenderParameter.maColors, nLineColor, fTransparency);
-        vcl::vertex::addQuadColors<GL_TRIANGLES>(rRenderParameter.maColors, nLineColor, fTransparency);
-        vcl::vertex::addQuadColors<GL_TRIANGLES>(rRenderParameter.maColors, nLineColor, fTransparency);
-        vcl::vertex::addQuadColors<GL_TRIANGLES>(rRenderParameter.maColors, nLineColor, fTransparency);
-
-        vcl::vertex::addQuadEmptyExtrusionVectors<GL_TRIANGLES>(rRenderParameter.maExtrusionVectors);
-        vcl::vertex::addQuadEmptyExtrusionVectors<GL_TRIANGLES>(rRenderParameter.maExtrusionVectors);
-        vcl::vertex::addQuadEmptyExtrusionVectors<GL_TRIANGLES>(rRenderParameter.maExtrusionVectors);
-        vcl::vertex::addQuadEmptyExtrusionVectors<GL_TRIANGLES>(rRenderParameter.maExtrusionVectors);
+        appendRectangle(rRenderParameter.maVertices, rRenderParameter.maIndices,
+                    fX1 - 0.5f, fY1 - 0.5f, fX1 + 0.5f, fY2 + 0.5f, nLineColor, fTransparency);
+        appendRectangle(rRenderParameter.maVertices, rRenderParameter.maIndices,
+                    fX1 - 0.5f, fY1 - 0.5f, fX2 + 0.5f, fY1 + 0.5f, nLineColor, fTransparency);
+        appendRectangle(rRenderParameter.maVertices, rRenderParameter.maIndices,
+                    fX2 - 0.5f, fY1 - 0.5f, fX2 + 0.5f, fY2 + 0.5f, nLineColor, fTransparency);
+        appendRectangle(rRenderParameter.maVertices, rRenderParameter.maIndices,
+                    fX1 - 0.5f, fY2 - 0.5f, fX2 + 0.5f, fY2 + 0.5f, nLineColor, fTransparency);
     }
 
     if (nFillColor != SALCOLOR_NONE)
     {
         if (nLineColor == SALCOLOR_NONE)
         {
-            // Draw rectangle stroke with fill color
-            vcl::vertex::addRectangle<GL_TRIANGLES>(rRenderParameter.maVertices, fX1 - 0.5f, fY1 - 0.5f, fX1 + 0.5f, fY2 + 0.5f);
-            vcl::vertex::addRectangle<GL_TRIANGLES>(rRenderParameter.maVertices, fX1 - 0.5f, fY1 - 0.5f, fX2 + 0.5f, fY1 + 0.5f);
-            vcl::vertex::addRectangle<GL_TRIANGLES>(rRenderParameter.maVertices, fX2 - 0.5f, fY1 - 0.5f, fX2 + 0.5f, fY2 + 0.5f);
-            vcl::vertex::addRectangle<GL_TRIANGLES>(rRenderParameter.maVertices, fX1 - 0.5f, fY2 - 0.5f, fX2 + 0.5f, fY2 + 0.5f);
-
-            vcl::vertex::addQuadColors<GL_TRIANGLES>(rRenderParameter.maColors, nFillColor, fTransparency);
-            vcl::vertex::addQuadColors<GL_TRIANGLES>(rRenderParameter.maColors, nFillColor, fTransparency);
-            vcl::vertex::addQuadColors<GL_TRIANGLES>(rRenderParameter.maColors, nFillColor, fTransparency);
-            vcl::vertex::addQuadColors<GL_TRIANGLES>(rRenderParameter.maColors, nFillColor, fTransparency);
-
-            vcl::vertex::addQuadEmptyExtrusionVectors<GL_TRIANGLES>(rRenderParameter.maExtrusionVectors);
-            vcl::vertex::addQuadEmptyExtrusionVectors<GL_TRIANGLES>(rRenderParameter.maExtrusionVectors);
-            vcl::vertex::addQuadEmptyExtrusionVectors<GL_TRIANGLES>(rRenderParameter.maExtrusionVectors);
-            vcl::vertex::addQuadEmptyExtrusionVectors<GL_TRIANGLES>(rRenderParameter.maExtrusionVectors);
+            appendRectangle(rRenderParameter.maVertices, rRenderParameter.maIndices,
+                        fX1 - 0.5f, fY1 - 0.5f, fX1 + 0.5f, fY2 + 0.5f, nFillColor, fTransparency);
+            appendRectangle(rRenderParameter.maVertices, rRenderParameter.maIndices,
+                        fX1 - 0.5f, fY1 - 0.5f, fX2 + 0.5f, fY1 + 0.5f, nFillColor, fTransparency);
+            appendRectangle(rRenderParameter.maVertices, rRenderParameter.maIndices,
+                        fX2 - 0.5f, fY1 - 0.5f, fX2 + 0.5f, fY2 + 0.5f, nFillColor, fTransparency);
+            appendRectangle(rRenderParameter.maVertices, rRenderParameter.maIndices,
+                        fX1 - 0.5f, fY2 - 0.5f, fX2 + 0.5f, fY2 + 0.5f, nFillColor, fTransparency);
         }
         // Draw rectangle fill with fill color
-        vcl::vertex::addRectangle<GL_TRIANGLES>(rRenderParameter.maVertices, fX1 + 0.5f, fY1 + 0.5f, fX2 - 0.5f, fY2 - 0.5f);
-        vcl::vertex::addQuadColors<GL_TRIANGLES>(rRenderParameter.maColors, nFillColor, fTransparency);
-        vcl::vertex::addQuadEmptyExtrusionVectors<GL_TRIANGLES>(rRenderParameter.maExtrusionVectors);
+        appendRectangle(rRenderParameter.maVertices, rRenderParameter.maIndices,
+                        fX1 + 0.5f, fY1 + 0.5f, fX2 - 0.5f, fY2 - 0.5f, nFillColor, fTransparency);
     }
 }
 
@@ -122,9 +263,13 @@ void RenderList::addDrawLine(long nX1, long nY1, long nX2, long nY2, SalColor nL
 
     checkOverlapping(basegfx::B2DRange(nX1, nY1, nX2, nY2));
 
-    RenderParameters& rRenderParameter = bUseAA ? maRenderEntries.back().maLineAAParameters :
-                                                  maRenderEntries.back().maLineParameters;
-    lclAddLineSegmentVertices(rRenderParameter, nX1, nY1, nX2, nY2, nLineColor, 0.0f);
+    RenderParameters& rRenderParameter = maRenderEntries.back().maLineParameters;
+
+    glm::vec2 aPoint1(nX1, nY1);
+    glm::vec2 aPoint2(nX2, nY2);
+
+    vcl::LineBuilder aBuilder(rRenderParameter.maVertices, rRenderParameter.maIndices, nLineColor, 0.0f, 1.0f, bUseAA);
+    aBuilder.appendLine(aPoint1, aPoint2);
 }
 
 void RenderList::addDrawPolyPolygon(const basegfx::B2DPolyPolygon& rPolyPolygon, double fTransparency,
@@ -139,16 +284,13 @@ void RenderList::addDrawPolyPolygon(const basegfx::B2DPolyPolygon& rPolyPolygon,
 
     checkOverlapping(rPolyPolygon.getB2DRange());
 
-    RenderParameters& rLineParameter = maRenderEntries.back().maLineParameters;
-    RenderParameters& rLineAAParameter = maRenderEntries.back().maLineAAParameters;
+    RenderParameters& rLineRenderParameter = maRenderEntries.back().maLineParameters;
+    RenderParameters& rTriangleRenderParameter = maRenderEntries.back().maTriangleParameters;
 
     if (nFillColor != SALCOLOR_NONE)
     {
-        RenderParameters& rTriangleParameter = maRenderEntries.back().maTriangleParameters;
-
-        const basegfx::B2DPolyPolygon& aSimplePolyPolygon = ::basegfx::tools::solveCrossovers(rPolyPolygon);
         basegfx::B2DTrapezoidVector aTrapezoidVector;
-        basegfx::tools::trapezoidSubdivide(aTrapezoidVector, aSimplePolyPolygon);
+        basegfx::tools::trapezoidSubdivide(aTrapezoidVector, rPolyPolygon);
 
         if (!aTrapezoidVector.empty())
         {
@@ -162,24 +304,18 @@ void RenderList::addDrawPolyPolygon(const basegfx::B2DPolyPolygon& rPolyPolygon,
                 GLfloat bottomX2 = rTrapezoid.getBottomXRight();
                 GLfloat bottomY  = rTrapezoid.getBottomY();
 
-                vcl::vertex::addTrapezoid<GL_TRIANGLES>(rTriangleParameter.maVertices,
-                                                         topX1,    topY,
-                                                         topX2,    topY,
-                                                         bottomX1, bottomY,
-                                                         bottomX2, bottomY);
-                vcl::vertex::addQuadColors<GL_TRIANGLES>(rTriangleParameter.maColors, nFillColor, fTransparency);
-                vcl::vertex::addQuadEmptyExtrusionVectors<GL_TRIANGLES>(rTriangleParameter.maExtrusionVectors);
-
+                appendTrapezoid(rTriangleRenderParameter.maVertices, rTriangleRenderParameter.maIndices,
+                                topX1,    topY, topX2,    topY,
+                                bottomX1, bottomY, bottomX2, bottomY,
+                                nFillColor, fTransparency);
                 if (bUseAA)
                 {
-                    lclAddLineSegmentVertices(rLineAAParameter, topX1, topY, topX2, topY,
-                                              nFillColor, fTransparency);
-                    lclAddLineSegmentVertices(rLineAAParameter, topX2, topY, bottomX2, bottomY,
-                                              nFillColor, fTransparency);
-                    lclAddLineSegmentVertices(rLineAAParameter, bottomX2, bottomY, bottomX1, bottomY,
-                                              nFillColor, fTransparency);
-                    lclAddLineSegmentVertices(rLineAAParameter, bottomX1, bottomY, topX1, topY,
-                                              nFillColor, fTransparency);
+                    vcl::LineBuilder aBuilder(rLineRenderParameter.maVertices, rLineRenderParameter.maIndices,
+                                         nFillColor, fTransparency, 1.0f, true);
+                    aBuilder.appendLine(glm::vec2(topX1, topY), glm::vec2(topX2, topY));
+                    aBuilder.appendLine(glm::vec2(topX2, topY), glm::vec2(bottomX2, bottomY));
+                    aBuilder.appendLine(glm::vec2(bottomX2, bottomY), glm::vec2(bottomX1, bottomY));
+                    aBuilder.appendLine(glm::vec2(bottomX1, bottomY), glm::vec2(topX1, topY));
                 }
             }
         }
@@ -187,7 +323,8 @@ void RenderList::addDrawPolyPolygon(const basegfx::B2DPolyPolygon& rPolyPolygon,
 
     if (nLineColor != SALCOLOR_NONE && nLineColor != nFillColor)
     {
-        RenderParameters& rParameter = bUseAA ? rLineAAParameter : rLineParameter;
+        vcl::LineBuilder aBuilder(rLineRenderParameter.maVertices, rLineRenderParameter.maIndices,
+                             nLineColor, fTransparency, 1.0f, bUseAA);
 
         for (const basegfx::B2DPolygon& rPolygon : rPolyPolygon)
         {
@@ -210,7 +347,7 @@ void RenderList::addDrawPolyPolygon(const basegfx::B2DPolyPolygon& rPolyPolygon,
                 x2 = aPolygon.getB2DPoint(index2).getX();
                 y2 = aPolygon.getB2DPoint(index2).getY();
 
-                lclAddLineSegmentVertices(rParameter, x1, y1, x2, y2, nLineColor, fTransparency);
+                aBuilder.appendLine(glm::vec2(x1, y1), glm::vec2(x2, y2));
             }
         }
     }
@@ -241,4 +378,33 @@ bool RenderList::addDrawTextureWithMaskColor(OpenGLTexture& rTexture, SalColor n
     return true;
 }
 
+void RenderList::addDrawPolyLine(const basegfx::B2DPolygon& rPolygon, double fTransparency,
+                                 const basegfx::B2DVector& rLineWidth, basegfx::B2DLineJoin eLineJoin,
+                                 css::drawing::LineCap eLineCap, double fMiterMinimumAngle,
+                                 SalColor nLineColor, bool bUseAA)
+{
+    if (rPolygon.count() <= 1)
+        return;
+    if (nLineColor == SALCOLOR_NONE)
+        return;
+    if (fTransparency == 1.0)
+        return;
+
+    const bool bIsHairline = (rLineWidth.getX() == rLineWidth.getY()) && (rLineWidth.getX() <= 1.2);
+    const float fLineWidth = bIsHairline ? 1.0f : rLineWidth.getX();
+
+    basegfx::B2DPolygon aPolygon(rPolygon);
+    if (rPolygon.areControlPointsUsed())
+        aPolygon = rPolygon.getDefaultAdaptiveSubdivision();
+
+    checkOverlapping(aPolygon.getB2DRange());
+
+    RenderParameters& rParameter = maRenderEntries.back().maLineParameters;
+
+    vcl::LineBuilder aBuilder(rParameter.maVertices, rParameter.maIndices,
+                              nLineColor, fTransparency, fLineWidth, bUseAA);
+
+    appendPolyLine(aBuilder, aPolygon, eLineJoin, eLineCap, fMiterMinimumAngle);
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/opengl/combinedFragmentShader.glsl b/vcl/opengl/combinedFragmentShader.glsl
index b200601..ba4fe2e 100644
--- a/vcl/opengl/combinedFragmentShader.glsl
+++ b/vcl/opengl/combinedFragmentShader.glsl
@@ -8,14 +8,13 @@
  */
 
 varying float fade_factor; // 0->1 fade factor used for AA
+varying float multiply;
 
 #ifdef USE_VERTEX_COLORS
 varying vec4 vertex_color;
 #endif
 
 uniform vec4 color;
-uniform float line_width;
-uniform float feather;
 
 #define TYPE_NORMAL 0
 #define TYPE_LINE   1
@@ -24,8 +23,6 @@ uniform int type;
 
 void main()
 {
-    float alpha = 1.0;
-
 #ifdef USE_VERTEX_COLORS
     vec4 result = vertex_color;
 #else
@@ -34,20 +31,11 @@ void main()
 
     if (type == TYPE_LINE)
     {
-        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 = start == end ? 1.0 : 1.0 / (1.0 - (start / end));
-
-        float dist = (1.0 - abs(fade_factor)) * multiplied;
-
-        alpha = clamp(dist, 0.0, 1.0);
+        float dist = (1.0 - abs(fade_factor)) * multiply;
+        float alpha = clamp(dist, 0.0, 1.0);
+        result.a = result.a * alpha;
     }
 
-    result.a = result.a * alpha;
-
     gl_FragColor = result;
 }
 
diff --git a/vcl/opengl/combinedVertexShader.glsl b/vcl/opengl/combinedVertexShader.glsl
index 8c6a856..3337a08 100644
--- a/vcl/opengl/combinedVertexShader.glsl
+++ b/vcl/opengl/combinedVertexShader.glsl
@@ -14,6 +14,8 @@ attribute vec4 vertex_color_in;
 #endif
 
 varying float fade_factor; // fade factor for anti-aliasing
+varying float multiply;
+
 #ifdef USE_VERTEX_COLORS
 varying vec4 vertex_color;
 #endif
@@ -30,26 +32,42 @@ uniform int type;
 
 void main()
 {
-   vec4 final_position = vec4(position, 0.0, 1.0);
+   vec2 extrusion_vector = extrusion_vectors.xy;
+
+   float render_thickness = 0.0;
 
    if (type == TYPE_LINE)
    {
-      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);
+      float miter_factor = 1.0 / 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);
+#ifdef USE_VERTEX_COLORS
+      float the_feather = (1.0 + sign(extrusion_vectors.w)) / 4.0;
+      float the_line_width = abs(extrusion_vectors.w);
+#else
+      float the_feather = feather;
+      float the_line_width = line_width;
+#endif
+      render_thickness = (the_line_width * miter_factor + the_feather * 2.0 * miter_factor);
 
-      float rendered_thickness = (line_width + feather * 2.0) * miter_factor;
+      // Calculate the multiplier so we can transform the 0->1 fade factor
+      // to take feather and line width into account.
 
-      // lengthen the vertex in directon of the extrusion vector by line width.
-      final_position = vec4(position + (extrusion_vector * (rendered_thickness / 2.0) ), 0.0, 1.0);
+      float start = mix(0.0, (the_line_width / 2.0) - the_feather, the_feather * 2.0);
+      float end   = mix(1.0, (the_line_width / 2.0) + the_feather, the_feather * 2.0);
+
+      multiply = 1.0 / (1.0 - (start / end));
    }
 
+   // lengthen the vertex in directon of the extrusion vector by line width.
+   vec4 final_position = vec4(position + (extrusion_vector * (render_thickness / 2.0) ), 0.0, 1.0);
+
    gl_Position = mvp * final_position;
+
 #ifdef USE_VERTEX_COLORS
-   vertex_color = vertex_color_in;
+   vertex_color = vertex_color_in / 255.0;
 #endif
 }
 
diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx
index 245c468..292a1ca 100644
--- a/vcl/opengl/gdiimpl.cxx
+++ b/vcl/opengl/gdiimpl.cxx
@@ -36,6 +36,7 @@
 #include "opengl/salbmp.hxx"
 #include "opengl/RenderState.hxx"
 #include "opengl/VertexUtils.hxx"
+#include "opengl/BufferObject.hxx"
 
 #include <vector>
 
@@ -616,64 +617,22 @@ bool OpenGLSalGraphicsImpl::UseInvert( SalInvert nFlags )
     return true;
 }
 
-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 = vcl::vertex::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));
-
-            vcl::vertex::addLineVertexPair(aVertices, aExtrusionVectors, p1, roundNormal, 1.0f);
-        }
-    }
-    else if (eLineCap == css::drawing::LineCap_SQUARE)
-    {
-        glm::vec2 extrudedPoint = p1 + -lineVector * (fLineWidth / 2.0f);
-
-        vcl::vertex::addLineVertexPair(aVertices, aExtrusionVectors, extrudedPoint, normal, 1.0f);
-        vcl::vertex::addLineVertexPair(aVertices, aExtrusionVectors, p1, normal, 1.0f);
-    }
-
-    ApplyProgramMatrices(0.5f);
-    mpProgram->SetExtrusionVectors(aExtrusionVectors.data());
-    mpProgram->DrawArrays(GL_TRIANGLE_STRIP, aVertices);
-
-    CHECK_GL_ERROR();
-}
-
 void OpenGLSalGraphicsImpl::DrawLineSegment(float x1, float y1, float x2, float y2)
 {
-    glm::vec2 p1(x1, y1);
-    glm::vec2 p2(x2, y2);
-
     std::vector<GLfloat> aVertices;
     std::vector<GLfloat> aExtrusionVectors;
 
     OpenGLZone aZone;
 
-    glm::vec2 lineVector = vcl::vertex::normalize(p2 - p1);
-    glm::vec2 normal = glm::vec2(-lineVector.y, lineVector.x);
+    glm::vec2 aPoint1(x1, y1);
+    glm::vec2 aPoint2(x2, y2);
 
-    vcl::vertex::addLinePointFirst(aVertices, aExtrusionVectors, p1, normal, 1.0f);
-    vcl::vertex::addLinePointNext (aVertices, aExtrusionVectors, p1, normal, 1.0f, p2, normal, 1.0f);
+    glm::vec2 aLineVector = vcl::vertex::normalize(aPoint2 - aPoint1);
+    glm::vec2 aNormal = glm::vec2(-aLineVector.y, aLineVector.x);
+
+    vcl::vertex::addLineSegmentVertices(aVertices, aExtrusionVectors,
+                                        aPoint1, aNormal, 1.0f,
+                                        aPoint2, aNormal, 1.0f);
 
     ApplyProgramMatrices(0.5f);
     mpProgram->SetExtrusionVectors(aExtrusionVectors.data());
@@ -682,201 +641,6 @@ void OpenGLSalGraphicsImpl::DrawLineSegment(float x1, float y1, float x2, float
     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, float fMiterMinimumAngle)
-{
-    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 = vcl::vertex::normalize(p2 - p1);
-
-        if (!bClosed)
-        {
-            normal = glm::vec2(-nextLineVector.y, nextLineVector.x); // make perpendicular
-            vcl::vertex::addLineVertexPair(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 = vcl::vertex::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 = vcl::vertex::normalize(p2 - p1);
-
-            if (eLineJoin == basegfx::B2DLineJoin::Miter)
-            {
-                float angle = std::atan2(previousLineVector.x * nextLineVector.y - previousLineVector.y * nextLineVector.x,
-                                         previousLineVector.x * nextLineVector.x + previousLineVector.y * nextLineVector.y);
-
-                angle = F_PI - std::fabs(angle);
-
-                if (angle < fMiterMinimumAngle)
-                    eLineJoin = basegfx::B2DLineJoin::Bevel;
-            }
-
-            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 = vcl::vertex::normalize(nextLineVector + previousLineVector);
-                glm::vec2 extrusionVector(-tangent.y, tangent.x);
-                GLfloat length = glm::dot(extrusionVector, normal);
-
-                vcl::vertex::addLineVertexPair(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);
-
-                vcl::vertex::addLineVertexPair(aVertices, aExtrusionVectors, p1, previousNormal, 1.0f);
-                vcl::vertex::addLineVertexPair(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 = vcl::vertex::normalize(previousNormal + nextNormal);
-                glm::vec2 middleLeft  = vcl::vertex::normalize(previousNormal + middle);
-                glm::vec2 middleRight = vcl::vertex::normalize(middle + nextNormal);
-
-                vcl::vertex::addLineVertexPair(aVertices, aExtrusionVectors, p1, previousNormal, 1.0f);
-                vcl::vertex::addLineVertexPair(aVertices, aExtrusionVectors, p1, middleLeft, 1.0f);
-                vcl::vertex::addLineVertexPair(aVertices, aExtrusionVectors, p1, middle, 1.0f);
-                vcl::vertex::addLineVertexPair(aVertices, aExtrusionVectors, p1, middleRight, 1.0f);
-                vcl::vertex::addLineVertexPair(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);
-
-            vcl::vertex::addLineVertexPair(aVertices, aExtrusionVectors, p1, normal, 1.0f);
-        }
-
-        ApplyProgramMatrices(0.5f);
-        mpProgram->SetExtrusionVectors(aExtrusionVectors.data());
-        mpProgram->DrawArrays(GL_TRIANGLE_STRIP, aVertices);
-
-        CHECK_GL_ERROR();
-    }
-}
-
 bool OpenGLSalGraphicsImpl::UseLine(SalColor nColor, double fTransparency, GLfloat fLineWidth, bool bUseAA)
 {
     if( nColor == SALCOLOR_NONE )
@@ -1503,6 +1267,42 @@ void OpenGLSalGraphicsImpl::DeferredTextDraw(OpenGLTexture& rTexture, SalColor a
     mpRenderList->addDrawTextureWithMaskColor(rTexture, aMaskColor, rPosAry);
 }
 
+bool OpenGLSalGraphicsImpl::FlushLinesOrTriangles(DrawShaderType eType, RenderParameters& rParameters)
+{
+    if (!UseProgram("combinedVertexShader", "combinedFragmentShader", "#define USE_VERTEX_COLORS"))
+        return false;
+
+    mpProgram->SetShaderType(eType);
+    mpProgram->SetBlendMode(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    ApplyProgramMatrices(0.5f);
+
+    vcl::VertexBufferObject<Vertex> vbo;
+    vbo.upload(rParameters.maVertices);
+
+    GLuint positionAttrib = SAL_MAX_UINT32;
+    GLuint colorAttrib = SAL_MAX_UINT32;
+    GLuint lineDataAttrib = SAL_MAX_UINT32;
+
+    mpProgram->SetVertexAttrib(positionAttrib, "position", 2, GL_FLOAT, GL_FALSE,
+                               sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, position)));
+
+    mpProgram->SetVertexAttrib(colorAttrib, "vertex_color_in", 4, GL_FLOAT, GL_FALSE,
+                               sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, color)));
+
+    mpProgram->SetVertexAttrib(lineDataAttrib, "extrusion_vectors", 4, GL_FLOAT, GL_FALSE,
+                               sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, lineData)));
+
+    vcl::IndexBufferObject ibo;
+    ibo.upload(rParameters.maIndices);
+    ibo.bind();
+
+    mpProgram->DrawElements(GL_TRIANGLES, rParameters.maIndices.size());
+    CHECK_GL_ERROR();
+
+    mpProgram->Clean();
+    return true;
+}
+
 void OpenGLSalGraphicsImpl::FlushDeferredDrawing()
 {
     if (mpRenderList->empty())
@@ -1515,48 +1315,17 @@ void OpenGLSalGraphicsImpl::FlushDeferredDrawing()
     OpenGLZone aZone;
     for (RenderEntry& rRenderEntry : mpRenderList->getEntries())
     {
-        if (rRenderEntry.hasTriangles() && UseProgram("combinedVertexShader", "combinedFragmentShader", "#define USE_VERTEX_COLORS"))
+        if (rRenderEntry.hasTriangles())
         {
             RenderParameters& rParameters = rRenderEntry.maTriangleParameters;
             VCL_GL_INFO("Flush Triangles: " << rParameters.maVertices.size());
-            mpProgram->SetShaderType(DrawShaderType::Normal);
-            mpProgram->SetBlendMode(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-            ApplyProgramMatrices(0.5f);
-            mpProgram->SetExtrusionVectors(rParameters.maExtrusionVectors.data());
-            mpProgram->SetVertexColors(rParameters.maColors);
-            mpProgram->DrawArrays(GL_TRIANGLES, rParameters.maVertices);
-            CHECK_GL_ERROR();
-            mpProgram->Clean();
+            FlushLinesOrTriangles(DrawShaderType::Normal, rParameters);
         }
-        if (rRenderEntry.hasLines() && UseProgram("combinedVertexShader", "combinedFragmentShader", "#define USE_VERTEX_COLORS"))
+        if (rRenderEntry.hasLines())
         {
             RenderParameters& rParameters = rRenderEntry.maLineParameters;
             VCL_GL_INFO("Flush Lines: " << rParameters.maVertices.size());
-            mpProgram->SetShaderType(DrawShaderType::Line);
-            mpProgram->SetUniform1f("line_width", 1.0f);
-            mpProgram->SetUniform1f("feather", 0.0f); // Anti-Aliasing disabled
-            mpProgram->SetBlendMode(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-            ApplyProgramMatrices(0.5f);
-            mpProgram->SetExtrusionVectors(rParameters.maExtrusionVectors.data());
-            mpProgram->SetVertexColors(rParameters.maColors);
-            mpProgram->DrawArrays(GL_TRIANGLES, rParameters.maVertices);
-            CHECK_GL_ERROR();
-            mpProgram->Clean();
-        }
-        if (rRenderEntry.hasLinesAA() && UseProgram("combinedVertexShader", "combinedFragmentShader", "#define USE_VERTEX_COLORS"))
-        {
-            RenderParameters& rParameters = rRenderEntry.maLineAAParameters;
-            VCL_GL_INFO("Flush Lines AA: " << rParameters.maVertices.size());
-            mpProgram->SetShaderType(DrawShaderType::Line);
-            mpProgram->SetUniform1f("line_width", 1.0f);
-            mpProgram->SetUniform1f("feather", 0.5f); // Anti-Aliasing enabled
-            mpProgram->SetBlendMode(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-            ApplyProgramMatrices(0.5f);
-            mpProgram->SetExtrusionVectors(rParameters.maExtrusionVectors.data());
-            mpProgram->SetVertexColors(rParameters.maColors);
-            mpProgram->DrawArrays(GL_TRIANGLES, rParameters.maVertices);
-            CHECK_GL_ERROR();
-            mpProgram->Clean();
+            FlushLinesOrTriangles(DrawShaderType::Line, rParameters);
         }
         if (rRenderEntry.hasTextures() && UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader", "#define USE_VERTEX_COLORS"))
         {
@@ -1769,34 +1538,14 @@ bool OpenGLSalGraphicsImpl::drawPolyPolygon(const basegfx::B2DPolyPolygon& rPoly
     return true;
 }
 
-bool OpenGLSalGraphicsImpl::drawPolyLine(
-            const basegfx::B2DPolygon& rPolygon,
-            double fTransparency,
-            const basegfx::B2DVector& rLineWidth,
-            basegfx::B2DLineJoin eLineJoin,
-            css::drawing::LineCap eLineCap,
-            double fMiterMinimumAngle)
+bool OpenGLSalGraphicsImpl::drawPolyLine(const basegfx::B2DPolygon& rPolygon, double fTransparency,
+                                         const basegfx::B2DVector& rLineWidth, basegfx::B2DLineJoin eLineJoin,
+                                         css::drawing::LineCap eLineCap, double fMiterMinimumAngle)
 {
-    VCL_GL_INFO( "::drawPolyLine trans " << fTransparency );
-    if( mnLineColor == SALCOLOR_NONE )
-        return true;
-
-    const bool bIsHairline = (rLineWidth.getX() == rLineWidth.getY()) && (rLineWidth.getX() <= 1.2);
-    const float fLineWidth = bIsHairline ? 1.0f : rLineWidth.getX();
-
-    PreDraw(XOROption::IMPLEMENT_XOR);
-
-    if (UseLine(mnLineColor, 0.0f, fLineWidth, mrParent.getAntiAliasB2DDraw()))
-    {
-        basegfx::B2DPolygon aPolygon(rPolygon);
-
-        if (aPolygon.areControlPointsUsed())
-            aPolygon = aPolygon.getDefaultAdaptiveSubdivision();
-
-        DrawPolyLine(aPolygon, fLineWidth, eLineJoin, eLineCap, fMiterMinimumAngle);
-    }
-    PostDraw();
+    VCL_GL_INFO("::drawPolyLine " << rPolygon.getB2DRange());
 
+    mpRenderList->addDrawPolyLine(rPolygon, fTransparency, rLineWidth, eLineJoin, eLineCap,
+                                  fMiterMinimumAngle, mnLineColor, mrParent.getAntiAliasB2DDraw());
     return true;
 }
 
diff --git a/vcl/opengl/program.cxx b/vcl/opengl/program.cxx
index 8aadb9d..692b61a 100644
--- a/vcl/opengl/program.cxx
+++ b/vcl/opengl/program.cxx
@@ -113,11 +113,13 @@ bool OpenGLProgram::EnableVertexAttrib(GLuint& rAttrib, const OString& rName)
     return true;
 }
 
-void OpenGLProgram::SetVertexAttrib( GLuint& rAttrib, const OString& rName, const GLvoid* pData, GLint nSize )
+void OpenGLProgram::SetVertexAttrib(GLuint& rAttrib, const OString& rName, GLint nSize,
+                                    GLenum eType, GLboolean bNormalized, GLsizei aStride,
+                                    const GLvoid* pPointer)
 {
     if (EnableVertexAttrib(rAttrib, rName))
     {
-        glVertexAttribPointer( rAttrib, nSize, GL_FLOAT, GL_FALSE, 0, pData );
+        glVertexAttribPointer(rAttrib, nSize, eType, bNormalized, aStride, pPointer);
         CHECK_GL_ERROR();
     }
     else
@@ -128,32 +130,32 @@ void OpenGLProgram::SetVertexAttrib( GLuint& rAttrib, const OString& rName, cons
 
 void OpenGLProgram::SetVertices( const GLvoid* pData )
 {
-    SetVertexAttrib( mnPositionAttrib, "position", pData );
+    SetVertexAttrib(mnPositionAttrib, "position", 2, GL_FLOAT, GL_FALSE, 0, pData);
 }
 
 void OpenGLProgram::SetTextureCoord( const GLvoid* pData )
 {
-    SetVertexAttrib( mnTexCoordAttrib, "tex_coord_in", pData );
+    SetVertexAttrib(mnTexCoordAttrib, "tex_coord_in", 2, GL_FLOAT, GL_FALSE, 0, pData);
 }
 
 void OpenGLProgram::SetAlphaCoord( const GLvoid* pData )
 {
-    SetVertexAttrib( mnAlphaCoordAttrib, "alpha_coord_in", pData );
+    SetVertexAttrib(mnAlphaCoordAttrib, "alpha_coord_in", 2, GL_FLOAT, GL_FALSE, 0, pData);
 }
 
 void OpenGLProgram::SetMaskCoord(const GLvoid* pData)
 {
-    SetVertexAttrib(mnMaskCoordAttrib, "mask_coord_in", pData);
+    SetVertexAttrib(mnMaskCoordAttrib, "mask_coord_in", 2, GL_FLOAT, GL_FALSE, 0, pData);
 }
 
 void OpenGLProgram::SetExtrusionVectors(const GLvoid* pData)
 {
-    SetVertexAttrib(mnExtrusionVectorsAttrib, "extrusion_vectors", pData, 3);
+    SetVertexAttrib(mnExtrusionVectorsAttrib, "extrusion_vectors", 3, GL_FLOAT, GL_FALSE, 0, pData);
 }
 
-void OpenGLProgram::SetVertexColors(std::vector<glm::vec4>& rColorVector)
+void OpenGLProgram::SetVertexColors(std::vector<GLubyte>& rColorVector)
 {
-    SetVertexAttrib(mnVertexColorsAttrib, "vertex_color_in", glm::value_ptr(rColorVector[0]), 4);
+    SetVertexAttrib(mnVertexColorsAttrib, "vertex_color_in", 4, GL_UNSIGNED_BYTE, GL_FALSE, 0, rColorVector.data());
 }
 
 void OpenGLProgram::SetShaderType(TextureShaderType eTextureShaderType)
@@ -189,6 +191,14 @@ void OpenGLProgram::DrawArrays(GLenum aMode, std::vector<GLfloat>& aVertices)
     glDrawArrays(aMode, 0, aVertices.size() / 2);
 }
 
+void OpenGLProgram::DrawElements(GLenum aMode, GLuint nNumberOfVertices)
+{
+    if (!mbBlending)
+        OpenGLContext::getVCLContext()->state()->blend().disable();
+
+    glDrawElements(aMode, nNumberOfVertices, GL_UNSIGNED_INT, nullptr);
+}
+
 void OpenGLProgram::SetUniform1f( const OString& rName, GLfloat v1 )
 {
     GLuint nUniform = GetUniformLocation( rName );


More information about the Libreoffice-commits mailing list