blob: 91317ee2d72ca78f72dbeedb86bec6fd019533c1 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qsgbasicinternalrectanglenode_p.h"
#include <QtCore/qmath.h>
QT_BEGIN_NAMESPACE
namespace
{
struct Color4ub
{
unsigned char r, g, b, a;
};
Color4ub operator *(Color4ub c, float t) { c.a *= t; c.r *= t; c.g *= t; c.b *= t; return c; }
Color4ub operator +(Color4ub a, Color4ub b) { a.a += b.a; a.r += b.r; a.g += b.g; a.b += b.b; return a; }
inline Color4ub colorToColor4ub(const QColor &c)
{
Color4ub color = { uchar(qRound(c.redF() * c.alphaF() * 255)),
uchar(qRound(c.greenF() * c.alphaF() * 255)),
uchar(qRound(c.blueF() * c.alphaF() * 255)),
uchar(qRound(c.alphaF() * 255))
};
return color;
}
// Same layout as QSGGeometry::ColoredPoint2D, but uses Color4ub for convenience.
struct Vertex
{
float x, y;
Color4ub color;
void set(float primary, float secondary, Color4ub ncolor, bool vertical)
{
if (vertical) {
x = secondary; y = primary;
} else {
x = primary; y = secondary;
}
color = ncolor;
}
};
struct SmoothVertex : public Vertex
{
float dx, dy;
void set(float primary, float secondary, Color4ub ncolor, float dPrimary, float dSecondary, bool vertical)
{
Vertex::set(primary, secondary, ncolor, vertical);
if (vertical) {
dx = dSecondary; dy = dPrimary;
} else {
dx = dPrimary; dy = dSecondary;
}
}
};
const QSGGeometry::AttributeSet &smoothAttributeSet()
{
static QSGGeometry::Attribute data[] = {
QSGGeometry::Attribute::createWithAttributeType(0, 2, QSGGeometry::FloatType, QSGGeometry::PositionAttribute),
QSGGeometry::Attribute::createWithAttributeType(1, 4, QSGGeometry::UnsignedByteType, QSGGeometry::ColorAttribute),
QSGGeometry::Attribute::createWithAttributeType(2, 2, QSGGeometry::FloatType, QSGGeometry::TexCoordAttribute)
};
static QSGGeometry::AttributeSet attrs = { 3, sizeof(SmoothVertex), data };
return attrs;
}
}
QSGBasicInternalRectangleNode::QSGBasicInternalRectangleNode()
: m_radius(0)
, m_pen_width(0)
, m_aligned(true)
, m_antialiasing(false)
, m_gradient_is_opaque(true)
, m_dirty_geometry(false)
, m_gradient_is_vertical(true)
, m_geometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), 0)
{
setGeometry(&m_geometry);
#ifdef QSG_RUNTIME_DESCRIPTION
qsgnode_set_description(this, QLatin1String("internalrectangle"));
#endif
}
void QSGBasicInternalRectangleNode::setRect(const QRectF &rect)
{
if (rect == m_rect)
return;
m_rect = rect;
m_dirty_geometry = true;
}
void QSGBasicInternalRectangleNode::setColor(const QColor &color)
{
if (color == m_color)
return;
m_color = color;
if (m_gradient_stops.isEmpty())
m_dirty_geometry = true;
}
void QSGBasicInternalRectangleNode::setPenColor(const QColor &color)
{
if (color == m_border_color)
return;
m_border_color = color;
if (m_pen_width > 0)
m_dirty_geometry = true;
}
void QSGBasicInternalRectangleNode::setPenWidth(qreal width)
{
if (width == m_pen_width)
return;
m_pen_width = width;
m_dirty_geometry = true;
}
void QSGBasicInternalRectangleNode::setGradientStops(const QGradientStops &stops)
{
if (stops.constData() == m_gradient_stops.constData())
return;
m_gradient_stops = stops;
m_gradient_is_opaque = true;
for (int i = 0; i < stops.size(); ++i)
m_gradient_is_opaque &= stops.at(i).second.alpha() == 0xff;
m_dirty_geometry = true;
}
void QSGBasicInternalRectangleNode::setGradientVertical(bool vertical)
{
if (vertical == m_gradient_is_vertical)
return;
m_gradient_is_vertical = vertical;
m_dirty_geometry = true;
}
void QSGBasicInternalRectangleNode::setRadius(qreal radius)
{
if (radius == m_radius)
return;
m_radius = radius;
m_dirty_geometry = true;
}
void QSGBasicInternalRectangleNode::setAntialiasing(bool antialiasing)
{
if (!supportsAntialiasing())
return;
if (antialiasing == m_antialiasing)
return;
m_antialiasing = antialiasing;
if (m_antialiasing) {
setGeometry(new QSGGeometry(smoothAttributeSet(), 0));
setFlag(OwnsGeometry, true);
} else {
setGeometry(&m_geometry);
setFlag(OwnsGeometry, false);
}
updateMaterialAntialiasing();
m_dirty_geometry = true;
}
void QSGBasicInternalRectangleNode::setAligned(bool aligned)
{
if (aligned == m_aligned)
return;
m_aligned = aligned;
m_dirty_geometry = true;
}
void QSGBasicInternalRectangleNode::update()
{
if (m_dirty_geometry) {
updateGeometry();
m_dirty_geometry = false;
QSGNode::DirtyState state = QSGNode::DirtyGeometry;
updateMaterialBlending(&state);
markDirty(state);
}
}
void QSGBasicInternalRectangleNode::updateGeometry()
{
float width = float(m_rect.width());
float height = float(m_rect.height());
float penWidth = qMin(qMin(width, height) * 0.5f, float(m_pen_width));
if (m_aligned)
penWidth = qRound(penWidth);
QSGGeometry *g = geometry();
g->setDrawingMode(QSGGeometry::DrawTriangleStrip);
int vertexStride = g->sizeOfVertex();
union {
Vertex *vertices;
SmoothVertex *smoothVertices;
};
Color4ub fillColor = colorToColor4ub(m_color);
Color4ub borderColor = colorToColor4ub(m_border_color);
Color4ub transparent = { 0, 0, 0, 0 };
const QGradientStops &stops = m_gradient_stops;
float length = (m_gradient_is_vertical ? height : width);
float secondaryLength = (m_gradient_is_vertical ? width : height);
int nextGradientStop = 0;
float gradientPos = penWidth / length;
while (nextGradientStop < stops.size() && stops.at(nextGradientStop).first <= gradientPos)
++nextGradientStop;
int lastGradientStop = stops.size() - 1;
float lastGradientPos = 1.0f - penWidth / length;
while (lastGradientStop >= nextGradientStop && stops.at(lastGradientStop).first >= lastGradientPos)
--lastGradientStop;
int gradientIntersections = (lastGradientStop - nextGradientStop + 1);
if (m_radius > 0) {
// Rounded corners.
// Radius should never exceeds half of the width or half of the height
float radius = qMin(qMin(width, height) * 0.5f, float(m_radius));
QRectF innerRect = m_rect;
innerRect.adjust(radius, radius, -radius, -radius);
float innerRadius = radius - penWidth * 1.0f;
float outerRadius = radius;
float delta = qMin(width, height) * 0.5f;
// Number of segments per corner, approximately one per 3 pixels.
int segments = qBound(3, qCeil(outerRadius * (M_PI / 6)), 18);
/*
--+--__
--+--__--__
| --__--__
| seg --__--+
--+-__ ment _+ \
--+-__--__ - \ \
--__--+ se \ \
+ \ g \ \
\ \ m \ \
-----------+--+ e \ \ <- gradient line
\ \ nt\ \
fill +--+----+--+
| | | |
border
inner AA outer AA (AA = antialiasing)
*/
int innerVertexCount = (segments + 1) * 4 + gradientIntersections * 2;
int outerVertexCount = (segments + 1) * 4;
int vertexCount = innerVertexCount;
if (m_antialiasing || penWidth)
vertexCount += innerVertexCount;
if (penWidth)
vertexCount += outerVertexCount;
if (m_antialiasing && penWidth)
vertexCount += outerVertexCount;
int fillIndexCount = innerVertexCount;
int innerAAIndexCount = innerVertexCount * 2 + 2;
int borderIndexCount = innerVertexCount * 2 + 2;
int outerAAIndexCount = outerVertexCount * 2 + 2;
int indexCount = 0;
int fillHead = 0;
int innerAAHead = 0;
int innerAATail = 0;
int borderHead = 0;
int borderTail = 0;
int outerAAHead = 0;
int outerAATail = 0;
bool hasFill = m_color.alpha() > 0 || !stops.isEmpty();
if (hasFill)
indexCount += fillIndexCount;
if (m_antialiasing) {
innerAATail = innerAAHead = indexCount + (innerAAIndexCount >> 1) + 1;
indexCount += innerAAIndexCount;
}
if (penWidth) {
borderTail = borderHead = indexCount + (borderIndexCount >> 1) + 1;
indexCount += borderIndexCount;
}
if (m_antialiasing && penWidth) {
outerAATail = outerAAHead = indexCount + (outerAAIndexCount >> 1) + 1;
indexCount += outerAAIndexCount;
}
g->allocate(vertexCount, indexCount);
vertices = reinterpret_cast<Vertex *>(g->vertexData());
memset(vertices, 0, vertexCount * vertexStride);
quint16 *indices = g->indexDataAsUShort();
quint16 index = 0;
float pp = 0; // previous inner primary coordinate.
float pss = 0; // previous inner secondary start coordinate.
float pse = 0; // previous inner secondary end coordinate.
float angle = 0.5f * float(M_PI) / segments;
float cosStep = qFastCos(angle);
float sinStep = qFastSin(angle);
float innerStart = (m_gradient_is_vertical ? innerRect.top() : innerRect.left());
float innerEnd = (m_gradient_is_vertical ? innerRect.bottom() : innerRect.right());
float innerLength = (m_gradient_is_vertical ? innerRect.height() : innerRect.width());
float innerSecondaryStart = (m_gradient_is_vertical ? innerRect.left() : innerRect.top());
float innerSecondaryEnd = (m_gradient_is_vertical ? innerRect.right() : innerRect.bottom());
for (int part = 0; part < 2; ++part) {
float c = 1 - part;
float s = part;
for (int i = 0; i <= segments; ++i) {
float p, ss, se;
if (innerRadius > 0) {
p = (part ? innerEnd : innerStart) - innerRadius * c; // current inner primary coordinate.
ss = innerSecondaryStart - innerRadius * s; // current inner secondary start coordinate.
se = innerSecondaryEnd + innerRadius * s; // current inner secondary end coordinate.
gradientPos = ((part ? innerLength : 0) + radius - innerRadius * c) / length;
} else {
p = (part ? innerEnd + innerRadius : innerStart - innerRadius); // current inner primary coordinate.
ss = innerSecondaryStart - innerRadius; // current inner secondary start coordinate.
se = innerSecondaryEnd + innerRadius; // current inner secondary end coordinate.
gradientPos = ((part ? innerLength + innerRadius : -innerRadius) + radius) / length;
}
float outerEdge = (part ? innerEnd : innerStart) - outerRadius * c; // current outer primary coordinate.
float outerSecondaryStart = innerSecondaryStart - outerRadius * s; // current outer secondary start coordinate.
float outerSecondaryEnd = innerSecondaryEnd + outerRadius * s; // current outer secondary end coordinate.
while (nextGradientStop <= lastGradientStop && stops.at(nextGradientStop).first <= gradientPos) {
// Insert vertices at gradient stops.
float gp = (innerStart - radius) + stops.at(nextGradientStop).first * length;
float t = (gp - pp) / (p - pp);
float gis = pss * (1 - t) + t * ss; // gradient inner start
float gie = pse * (1 - t) + t * se; // gradient inner end
fillColor = colorToColor4ub(stops.at(nextGradientStop).second);
if (hasFill) {
indices[fillHead++] = index;
indices[fillHead++] = index + 1;
}
if (penWidth) {
--borderHead;
indices[borderHead] = indices[borderHead + 2];
indices[--borderHead] = index + 2;
indices[borderTail++] = index + 3;
indices[borderTail] = indices[borderTail - 2];
++borderTail;
}
if (m_antialiasing) {
indices[--innerAAHead] = index + 2;
indices[--innerAAHead] = index;
indices[innerAATail++] = index + 1;
indices[innerAATail++] = index + 3;
bool lower = stops.at(nextGradientStop).first > 0.5f;
float dp = lower ? qMin(0.0f, length - gp - delta) : qMax(0.0f, delta - gp);
smoothVertices[index++].set(gp, gie, fillColor, dp, secondaryLength - gie - delta, m_gradient_is_vertical);
smoothVertices[index++].set(gp, gis, fillColor, dp, delta - gis, m_gradient_is_vertical);
if (penWidth) {
smoothVertices[index++].set(gp, gie, borderColor, -0.49f * penWidth * c, 0.49f * penWidth * s, m_gradient_is_vertical);
smoothVertices[index++].set(gp, gis, borderColor, -0.49f * penWidth * c, -0.49f * penWidth * s, m_gradient_is_vertical);
} else {
dp = lower ? delta : -delta;
smoothVertices[index++].set(gp, gie, transparent, dp, delta, m_gradient_is_vertical);
smoothVertices[index++].set(gp, gis, transparent, dp, -delta, m_gradient_is_vertical);
}
} else {
vertices[index++].set(gp, gie, fillColor, m_gradient_is_vertical);
vertices[index++].set(gp, gis, fillColor, m_gradient_is_vertical);
if (penWidth) {
vertices[index++].set(gp, gie, borderColor, m_gradient_is_vertical);
vertices[index++].set(gp, gis, borderColor, m_gradient_is_vertical);
}
}
++nextGradientStop;
}
if (!stops.isEmpty()) {
if (nextGradientStop == 0) {
fillColor = colorToColor4ub(stops.at(0).second);
} else if (nextGradientStop == stops.size()) {
fillColor = colorToColor4ub(stops.last().second);
} else {
const QGradientStop &prev = stops.at(nextGradientStop - 1);
const QGradientStop &next = stops.at(nextGradientStop);
float t = (gradientPos - prev.first) / (next.first - prev.first);
fillColor = colorToColor4ub(prev.second) * (1 - t) + colorToColor4ub(next.second) * t;
}
}
if (hasFill) {
indices[fillHead++] = index;
indices[fillHead++] = index + 1;
}
if (penWidth) {
indices[--borderHead] = index + 4;
indices[--borderHead] = index + 2;
indices[borderTail++] = index + 3;
indices[borderTail++] = index + 5;
}
if (m_antialiasing) {
indices[--innerAAHead] = index + 2;
indices[--innerAAHead] = index;
indices[innerAATail++] = index + 1;
indices[innerAATail++] = index + 3;
float dp = part ? qMin(0.0f, length - p - delta) : qMax(0.0f, delta - p);
smoothVertices[index++].set(p, se, fillColor, dp, secondaryLength - se - delta, m_gradient_is_vertical);
smoothVertices[index++].set(p, ss, fillColor, dp, delta - ss, m_gradient_is_vertical);
dp = part ? delta : -delta;
if (penWidth) {
smoothVertices[index++].set(p, se, borderColor, -0.49f * penWidth * c, 0.49f * penWidth * s, m_gradient_is_vertical);
smoothVertices[index++].set(p, ss, borderColor, -0.49f * penWidth * c, -0.49f * penWidth * s, m_gradient_is_vertical);
smoothVertices[index++].set(outerEdge, outerSecondaryEnd, borderColor, 0.49f * penWidth * c, -0.49f * penWidth * s, m_gradient_is_vertical);
smoothVertices[index++].set(outerEdge, outerSecondaryStart, borderColor, 0.49f * penWidth * c, 0.49f * penWidth * s, m_gradient_is_vertical);
smoothVertices[index++].set(outerEdge, outerSecondaryEnd, transparent, dp, delta, m_gradient_is_vertical);
smoothVertices[index++].set(outerEdge, outerSecondaryStart, transparent, dp, -delta, m_gradient_is_vertical);
indices[--outerAAHead] = index - 2;
indices[--outerAAHead] = index - 4;
indices[outerAATail++] = index - 3;
indices[outerAATail++] = index - 1;
} else {
smoothVertices[index++].set(p, se, transparent, dp, delta, m_gradient_is_vertical);
smoothVertices[index++].set(p, ss, transparent, dp, -delta, m_gradient_is_vertical);
}
} else {
vertices[index++].set(p, se, fillColor, m_gradient_is_vertical);
vertices[index++].set(p, ss, fillColor, m_gradient_is_vertical);
if (penWidth) {
vertices[index++].set(p, se, borderColor, m_gradient_is_vertical);
vertices[index++].set(p, ss, borderColor, m_gradient_is_vertical);
vertices[index++].set(outerEdge, outerSecondaryEnd, borderColor, m_gradient_is_vertical);
vertices[index++].set(outerEdge, outerSecondaryStart, borderColor, m_gradient_is_vertical);
}
}
pp = p;
pss = ss;
pse = se;
// Rotate
qreal tmp = c;
c = c * cosStep - s * sinStep;
s = s * cosStep + tmp * sinStep;
}
}
Q_ASSERT(index == vertexCount);
// Close the triangle strips.
if (m_antialiasing) {
indices[--innerAAHead] = indices[innerAATail - 1];
indices[--innerAAHead] = indices[innerAATail - 2];
Q_ASSERT(innerAATail <= indexCount);
}
if (penWidth) {
indices[--borderHead] = indices[borderTail - 1];
indices[--borderHead] = indices[borderTail - 2];
Q_ASSERT(borderTail <= indexCount);
}
if (m_antialiasing && penWidth) {
indices[--outerAAHead] = indices[outerAATail - 1];
indices[--outerAAHead] = indices[outerAATail - 2];
Q_ASSERT(outerAATail == indexCount);
}
} else {
// Straight corners.
QRectF innerRect = m_rect;
QRectF outerRect = m_rect;
if (penWidth)
innerRect.adjust(1.0f * penWidth, 1.0f * penWidth, -1.0f * penWidth, -1.0f * penWidth);
float delta = qMin(width, height) * 0.5f;
int innerVertexCount = 4 + gradientIntersections * 2;
int outerVertexCount = 4;
int vertexCount = innerVertexCount;
if (m_antialiasing || penWidth)
vertexCount += innerVertexCount;
if (penWidth)
vertexCount += outerVertexCount;
if (m_antialiasing && penWidth)
vertexCount += outerVertexCount;
int fillIndexCount = innerVertexCount;
int innerAAIndexCount = innerVertexCount * 2 + 2;
int borderIndexCount = innerVertexCount * 2 + 2;
int outerAAIndexCount = outerVertexCount * 2 + 2;
int indexCount = 0;
int fillHead = 0;
int innerAAHead = 0;
int innerAATail = 0;
int borderHead = 0;
int borderTail = 0;
int outerAAHead = 0;
int outerAATail = 0;
bool hasFill = m_color.alpha() > 0 || !stops.isEmpty();
if (hasFill)
indexCount += fillIndexCount;
if (m_antialiasing) {
innerAATail = innerAAHead = indexCount + (innerAAIndexCount >> 1) + 1;
indexCount += innerAAIndexCount;
}
if (penWidth) {
borderTail = borderHead = indexCount + (borderIndexCount >> 1) + 1;
indexCount += borderIndexCount;
}
if (m_antialiasing && penWidth) {
outerAATail = outerAAHead = indexCount + (outerAAIndexCount >> 1) + 1;
indexCount += outerAAIndexCount;
}
g->allocate(vertexCount, indexCount);
vertices = reinterpret_cast<Vertex *>(g->vertexData());
memset(vertices, 0, vertexCount * vertexStride);
quint16 *indices = g->indexDataAsUShort();
quint16 index = 0;
float innerStart = (m_gradient_is_vertical ? innerRect.top() : innerRect.left());
float innerEnd = (m_gradient_is_vertical ? innerRect.bottom() : innerRect.right());
float outerStart = (m_gradient_is_vertical ? outerRect.top() : outerRect.left());
float outerEnd = (m_gradient_is_vertical ? outerRect.bottom() : outerRect.right());
float innerSecondaryStart = (m_gradient_is_vertical ? innerRect.left() : innerRect.top());
float innerSecondaryEnd = (m_gradient_is_vertical ? innerRect.right() : innerRect.bottom());
float outerSecondaryStart = (m_gradient_is_vertical ? outerRect.left() : outerRect.top());
float outerSecondaryEnd = (m_gradient_is_vertical ? outerRect.right() : outerRect.bottom());
for (int part = -1; part <= 1; part += 2) {
float innerEdge = (part == 1 ? innerEnd : innerStart);
float outerEdge = (part == 1 ? outerEnd : outerStart);
gradientPos = (innerEdge - innerStart + penWidth) / length;
while (nextGradientStop <= lastGradientStop && stops.at(nextGradientStop).first <= gradientPos) {
// Insert vertices at gradient stops.
float gp = (innerStart - penWidth) + stops.at(nextGradientStop).first * length;
fillColor = colorToColor4ub(stops.at(nextGradientStop).second);
if (hasFill) {
indices[fillHead++] = index;
indices[fillHead++] = index + 1;
}
if (penWidth) {
--borderHead;
indices[borderHead] = indices[borderHead + 2];
indices[--borderHead] = index + 2;
indices[borderTail++] = index + 3;
indices[borderTail] = indices[borderTail - 2];
++borderTail;
}
if (m_antialiasing) {
indices[--innerAAHead] = index + 2;
indices[--innerAAHead] = index;
indices[innerAATail++] = index + 1;
indices[innerAATail++] = index + 3;
bool lower = stops.at(nextGradientStop).first > 0.5f;
float dp = lower ? qMin(0.0f, length - gp - delta) : qMax(0.0f, delta - gp);
smoothVertices[index++].set(gp, innerSecondaryEnd, fillColor, dp, secondaryLength - innerSecondaryEnd - delta, m_gradient_is_vertical);
smoothVertices[index++].set(gp, innerSecondaryStart, fillColor, dp, delta - innerSecondaryStart, m_gradient_is_vertical);
if (penWidth) {
smoothVertices[index++].set(gp, innerSecondaryEnd, borderColor, (lower ? 0.49f : -0.49f) * penWidth, 0.49f * penWidth, m_gradient_is_vertical);
smoothVertices[index++].set(gp, innerSecondaryStart, borderColor, (lower ? 0.49f : -0.49f) * penWidth, -0.49f * penWidth, m_gradient_is_vertical);
} else {
smoothVertices[index++].set(gp, innerSecondaryEnd, transparent, lower ? delta : -delta, delta, m_gradient_is_vertical);
smoothVertices[index++].set(gp, innerSecondaryStart, transparent, lower ? delta : -delta, -delta, m_gradient_is_vertical);
}
} else {
vertices[index++].set(gp, innerSecondaryEnd, fillColor, m_gradient_is_vertical);
vertices[index++].set(gp, innerSecondaryStart, fillColor, m_gradient_is_vertical);
if (penWidth) {
vertices[index++].set(gp, innerSecondaryEnd, borderColor, m_gradient_is_vertical);
vertices[index++].set(gp, innerSecondaryStart, borderColor, m_gradient_is_vertical);
}
}
++nextGradientStop;
}
if (!stops.isEmpty()) {
if (nextGradientStop == 0) {
fillColor = colorToColor4ub(stops.at(0).second);
} else if (nextGradientStop == stops.size()) {
fillColor = colorToColor4ub(stops.last().second);
} else {
const QGradientStop &prev = stops.at(nextGradientStop - 1);
const QGradientStop &next = stops.at(nextGradientStop);
float t = (gradientPos - prev.first) / (next.first - prev.first);
fillColor = colorToColor4ub(prev.second) * (1 - t) + colorToColor4ub(next.second) * t;
}
}
if (hasFill) {
indices[fillHead++] = index;
indices[fillHead++] = index + 1;
}
if (penWidth) {
indices[--borderHead] = index + 4;
indices[--borderHead] = index + 2;
indices[borderTail++] = index + 3;
indices[borderTail++] = index + 5;
}
if (m_antialiasing) {
indices[--innerAAHead] = index + 2;
indices[--innerAAHead] = index;
indices[innerAATail++] = index + 1;
indices[innerAATail++] = index + 3;
float dp = part == 1 ? qMin(0.0f, length - innerEdge - delta) : qMax(0.0f, delta - innerEdge);
smoothVertices[index++].set(innerEdge, innerSecondaryEnd, fillColor, dp, secondaryLength - innerSecondaryEnd - delta, m_gradient_is_vertical);
smoothVertices[index++].set(innerEdge, innerSecondaryStart, fillColor, dp, delta - innerSecondaryStart, m_gradient_is_vertical);
if (penWidth) {
smoothVertices[index++].set(innerEdge, innerSecondaryEnd, borderColor, 0.49f * penWidth * part, 0.49f * penWidth, m_gradient_is_vertical);
smoothVertices[index++].set(innerEdge, innerSecondaryStart, borderColor, 0.49f * penWidth * part, -0.49f * penWidth, m_gradient_is_vertical);
smoothVertices[index++].set(outerEdge, outerSecondaryEnd, borderColor, -0.49f * penWidth * part, -0.49f * penWidth, m_gradient_is_vertical);
smoothVertices[index++].set(outerEdge, outerSecondaryStart, borderColor, -0.49f * penWidth * part, 0.49f * penWidth, m_gradient_is_vertical);
smoothVertices[index++].set(outerEdge, outerSecondaryEnd, transparent, delta * part, delta, m_gradient_is_vertical);
smoothVertices[index++].set(outerEdge, outerSecondaryStart, transparent, delta * part, -delta, m_gradient_is_vertical);
indices[--outerAAHead] = index - 2;
indices[--outerAAHead] = index - 4;
indices[outerAATail++] = index - 3;
indices[outerAATail++] = index - 1;
} else {
smoothVertices[index++].set(innerEdge, innerSecondaryEnd, transparent, delta * part, delta, m_gradient_is_vertical);
smoothVertices[index++].set(innerEdge, innerSecondaryStart, transparent, delta * part, -delta, m_gradient_is_vertical);
}
} else {
vertices[index++].set(innerEdge, innerSecondaryEnd, fillColor, m_gradient_is_vertical);
vertices[index++].set(innerEdge, innerSecondaryStart, fillColor, m_gradient_is_vertical);
if (penWidth) {
vertices[index++].set(innerEdge, innerSecondaryEnd, borderColor, m_gradient_is_vertical);
vertices[index++].set(innerEdge, innerSecondaryStart, borderColor, m_gradient_is_vertical);
vertices[index++].set(outerEdge, outerSecondaryEnd, borderColor, m_gradient_is_vertical);
vertices[index++].set(outerEdge, outerSecondaryStart, borderColor, m_gradient_is_vertical);
}
}
}
Q_ASSERT(index == vertexCount);
// Close the triangle strips.
if (m_antialiasing) {
indices[--innerAAHead] = indices[innerAATail - 1];
indices[--innerAAHead] = indices[innerAATail - 2];
Q_ASSERT(innerAATail <= indexCount);
}
if (penWidth) {
indices[--borderHead] = indices[borderTail - 1];
indices[--borderHead] = indices[borderTail - 2];
Q_ASSERT(borderTail <= indexCount);
}
if (m_antialiasing && penWidth) {
indices[--outerAAHead] = indices[outerAATail - 1];
indices[--outerAAHead] = indices[outerAATail - 2];
Q_ASSERT(outerAATail == indexCount);
}
}
}
QT_END_NAMESPACE