1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
11 #include <opengl/LineRenderUtils.hxx>
16 LineBuilder::LineBuilder(std::vector
<Vertex
>& rVertices
, std::vector
<GLuint
>& rIndices
,
17 Color nColor
, GLfloat fTransparency
,
18 GLfloat fLineWidth
, bool bUseAA
)
19 : mrVertices(rVertices
)
22 , mG(nColor
.GetGreen())
23 , mB(nColor
.GetBlue())
24 , mA((1.0f
- fTransparency
) * 255.0f
)
25 , mfLineWidth(fLineWidth
)
26 , mfLineWidthAndAA(bUseAA
? fLineWidth
: -fLineWidth
)
27 , mnInitialIndexSize(rIndices
.size())
32 void LineBuilder::appendLineSegment(const glm::vec2
& rPoint1
, const glm::vec2
& rNormal1
, GLfloat aExtrusion1
,
33 const glm::vec2
& rPoint2
, const glm::vec2
& rNormal2
, GLfloat aExtrusion2
)
35 GLuint zero
= mrVertices
.size();
37 mrVertices
.insert(mrVertices
.end(), {
38 {rPoint1
, glm::vec4
{mR
, mG
, mB
, mA
}, glm::vec4
{-rNormal1
.x
, -rNormal1
.y
, -aExtrusion1
, mfLineWidthAndAA
}},
39 {rPoint1
, glm::vec4
{mR
, mG
, mB
, mA
}, glm::vec4
{ rNormal1
.x
, rNormal1
.y
, aExtrusion1
, mfLineWidthAndAA
}},
40 {rPoint2
, glm::vec4
{mR
, mG
, mB
, mA
}, glm::vec4
{-rNormal2
.x
, -rNormal2
.y
, -aExtrusion2
, mfLineWidthAndAA
}},
41 {rPoint2
, glm::vec4
{mR
, mG
, mB
, mA
}, glm::vec4
{ rNormal2
.x
, rNormal2
.y
, aExtrusion2
, mfLineWidthAndAA
}},
44 mrIndices
.insert(mrIndices
.end(), {
45 zero
+ 0, zero
+ 1, zero
+ 2,
46 zero
+ 2, zero
+ 1, zero
+ 3
51 void LineBuilder::appendLine(const glm::vec2
& rPoint1
, const glm::vec2
& rPoint2
)
53 glm::vec2 aLineVector
= vcl::vertex::normalize(rPoint2
- rPoint1
);
54 glm::vec2 aNormal
= vcl::vertex::perpendicular(aLineVector
);
56 appendLineSegment(rPoint1
, aNormal
, 1.0f
,
57 rPoint2
, aNormal
, 1.0f
);
60 void LineBuilder::appendAndConnectLinePoint(const glm::vec2
& rPoint
, const glm::vec2
& aNormal
, GLfloat aExtrusion
)
62 GLuint zero
= mrVertices
.size();
64 mrVertices
.insert(mrVertices
.end(), {
65 {rPoint
, glm::vec4
{mR
, mG
, mB
, mA
}, glm::vec4
{-aNormal
.x
, -aNormal
.y
, -aExtrusion
, mfLineWidthAndAA
}},
66 {rPoint
, glm::vec4
{mR
, mG
, mB
, mA
}, glm::vec4
{ aNormal
.x
, aNormal
.y
, aExtrusion
, mfLineWidthAndAA
}},
69 if (mnInitialIndexSize
== mrIndices
.size())
71 mrIndices
.insert(mrIndices
.end(), {
80 mrIndices
.insert(mrIndices
.end(), {
82 zero
+ 0, zero
- 1, zero
+ 1
88 mrIndices
.insert(mrIndices
.end(), {
89 zero
- 2, zero
- 1, zero
+ 0,
90 zero
+ 0, zero
- 1, zero
+ 1
96 void LineBuilder::appendMiterJoint(glm::vec2
const& point
, const glm::vec2
& prevLineVector
,
97 glm::vec2
const& nextLineVector
)
99 // With miter join we calculate the extrusion vector by adding normals of
100 // previous and next line segment. The vector shows the way but we also
101 // need the length (otherwise the line will be deformed). Length factor is
102 // calculated as dot product of extrusion vector and one of the normals.
103 // The value we get is the inverse length (used in the shader):
104 // length = line_width / dot(extrusionVector, normal)
106 glm::vec2
normal(-prevLineVector
.y
, prevLineVector
.x
);
108 glm::vec2 tangent
= vcl::vertex::normalize(nextLineVector
+ prevLineVector
);
109 glm::vec2
extrusionVector(-tangent
.y
, tangent
.x
);
110 GLfloat length
= glm::dot(extrusionVector
, normal
);
112 appendAndConnectLinePoint(point
, extrusionVector
, length
);
115 void LineBuilder::appendBevelJoint(glm::vec2
const& point
, const glm::vec2
& prevLineVector
,
116 const glm::vec2
& nextLineVector
)
118 // For bevel join we just add 2 additional vertices and use previous
119 // line segment normal and next line segment normal as extrusion vector.
120 // All the magic is done by the fact that we draw triangle strips, so we
121 // cover the joins correctly.
123 glm::vec2 prevNormal
= glm::vec2(-prevLineVector
.y
, prevLineVector
.x
);
124 glm::vec2 nextNormal
= glm::vec2(-nextLineVector
.y
, nextLineVector
.x
);
126 appendAndConnectLinePoint(point
, prevNormal
, 1.0f
);
127 appendAndConnectLinePoint(point
, nextNormal
, 1.0f
);
130 void LineBuilder::appendRoundJoint(glm::vec2
const& point
, const glm::vec2
& prevLineVector
,
131 const glm::vec2
& nextLineVector
)
133 // For round join we do a similar thing as in bevel, we add more intermediate
134 // vertices and add normals to get extrusion vectors in the between the
137 // 3 additional extrusion vectors + normals are enough to make most
138 // line joins look round. Ideally the number of vectors could be
141 glm::vec2 prevNormal
= glm::vec2(-prevLineVector
.y
, prevLineVector
.x
);
142 glm::vec2 nextNormal
= glm::vec2(-nextLineVector
.y
, nextLineVector
.x
);
144 glm::vec2 middle
= vcl::vertex::normalize(prevNormal
+ nextNormal
);
145 glm::vec2 middleLeft
= vcl::vertex::normalize(prevNormal
+ middle
);
146 glm::vec2 middleRight
= vcl::vertex::normalize(middle
+ nextNormal
);
148 appendAndConnectLinePoint(point
, prevNormal
, 1.0f
);
149 appendAndConnectLinePoint(point
, middleLeft
, 1.0f
);
150 appendAndConnectLinePoint(point
, middle
, 1.0f
);
151 appendAndConnectLinePoint(point
, middleRight
, 1.0f
);
152 appendAndConnectLinePoint(point
, nextNormal
, 1.0f
);
155 void LineBuilder::appendRoundLineCapVertices(const glm::vec2
& rPoint1
, const glm::vec2
& rPoint2
)
157 constexpr int nRoundCapIteration
= 12;
159 glm::vec2 lineVector
= vcl::vertex::normalize(rPoint2
- rPoint1
);
160 glm::vec2 normal
= glm::vec2(-lineVector
.y
, lineVector
.x
);
161 glm::vec2 previousRoundNormal
= normal
;
163 for (int nFactor
= 1; nFactor
<= nRoundCapIteration
; nFactor
++)
165 float angle
= float(nFactor
) * (M_PI
/ float(nRoundCapIteration
));
166 glm::vec2
roundNormal(normal
.x
* glm::cos(angle
) - normal
.y
* glm::sin(angle
),
167 normal
.x
* glm::sin(angle
) + normal
.y
* glm::cos(angle
));
169 appendLineSegment(rPoint1
, previousRoundNormal
, 1.0f
,
170 rPoint1
, roundNormal
, 1.0f
);
171 previousRoundNormal
= roundNormal
;
175 void LineBuilder::appendSquareLineCapVertices(const glm::vec2
& rPoint1
, const glm::vec2
& rPoint2
)
177 glm::vec2 lineVector
= vcl::vertex::normalize(rPoint2
- rPoint1
);
178 glm::vec2 normal
= glm::vec2(-lineVector
.y
, lineVector
.x
);
180 glm::vec2 extrudedPoint
= rPoint1
+ -lineVector
* (mfLineWidth
/ 2.0f
);
182 appendLineSegment(extrudedPoint
, normal
, 1.0f
,
183 rPoint1
, normal
, 1.0f
);
188 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */