diff options
Diffstat (limited to 'vcl/opengl/gdiimpl.cxx')
-rw-r--r-- | vcl/opengl/gdiimpl.cxx | 361 |
1 files changed, 55 insertions, 306 deletions
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; } |