summaryrefslogtreecommitdiff
path: root/vcl/opengl
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/opengl')
-rw-r--r--vcl/opengl/LineRenderUtils.cxx185
-rw-r--r--vcl/opengl/RenderList.cxx314
-rw-r--r--vcl/opengl/combinedFragmentShader.glsl20
-rw-r--r--vcl/opengl/combinedVertexShader.glsl32
-rw-r--r--vcl/opengl/gdiimpl.cxx361
-rw-r--r--vcl/opengl/program.cxx28
6 files changed, 528 insertions, 412 deletions
diff --git a/vcl/opengl/LineRenderUtils.cxx b/vcl/opengl/LineRenderUtils.cxx
new file mode 100644
index 000000000000..1b7fb9919490
--- /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 aee6a0411d77..5c59002f95ff 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 b20060108965..ba4fe2eef665 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 8c6a856cd7d6..3337a085db6f 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 245c468b21fd..292a1ca0da84 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 8aadb9d89c67..692b61afb6d7 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 );