diff options
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/Library_vcl.mk | 1 | ||||
-rw-r--r-- | vcl/inc/opengl/BufferObject.hxx | 89 | ||||
-rw-r--r-- | vcl/inc/opengl/LineRenderUtils.hxx | 54 | ||||
-rw-r--r-- | vcl/inc/opengl/RenderList.hxx | 30 | ||||
-rw-r--r-- | vcl/inc/opengl/VertexUtils.hxx | 112 | ||||
-rw-r--r-- | vcl/inc/opengl/program.hxx | 14 | ||||
-rw-r--r-- | vcl/inc/openglgdiimpl.hxx | 4 | ||||
-rw-r--r-- | vcl/opengl/LineRenderUtils.cxx | 185 | ||||
-rw-r--r-- | vcl/opengl/RenderList.cxx | 314 | ||||
-rw-r--r-- | vcl/opengl/combinedFragmentShader.glsl | 20 | ||||
-rw-r--r-- | vcl/opengl/combinedVertexShader.glsl | 32 | ||||
-rw-r--r-- | vcl/opengl/gdiimpl.cxx | 361 | ||||
-rw-r--r-- | vcl/opengl/program.cxx | 28 |
13 files changed, 750 insertions, 494 deletions
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index 06e315343058..40dd0cdbfcdf 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 000000000000..3cda66deed0e --- /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 000000000000..7c9018a67fa9 --- /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 f6f59f5fec6e..062971ec29f3 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 6de658e14d54..f9804ecd978f 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 c737c1250aaa..b32aa05f250e 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 2c8d47c9b33d..d0b5f9aa478a 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 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 ); |