Commit 4fb6ee7d authored by Kim Motoyoshi Kalland's avatar Kim Motoyoshi Kalland
Browse files

Fix Rectangle implementation.

parent 2002baaf
dev 5.10 5.11 5.12 5.12.1 5.12.10 5.12.11 5.12.12 5.12.2 5.12.3 5.12.4 5.12.5 5.12.6 5.12.7 5.12.8 5.12.9 5.13 5.13.0 5.13.1 5.13.2 5.14 5.14.0 5.14.1 5.14.2 5.15 5.15.0 5.15.1 5.15.2 5.3 5.4 5.5 5.6 5.7 5.8 5.9 5.9.8 6.0 6.0.0 6.1 6.1.0 6.1.1 6.1.2 6.1.3 6.2 6.2.0 6.2.1 6.2.2 old/5.0 old/5.1 old/5.2 wip/animation-refactor wip/cmake wip/dbus wip/gc wip/itemviews wip/nacl wip/new-backend wip/pointerhandler wip/propertycache-refactor wip/qquickdeliveryagent wip/scenegraphng wip/statemachine wip/textng wip/tizen wip/visuallistmodel wip/webassembly v5.15.0-alpha1 v5.14.1 v5.14.0 v5.14.0-rc2 v5.14.0-rc1 v5.14.0-beta3 v5.14.0-beta2 v5.14.0-beta1 v5.14.0-alpha1 v5.13.2 v5.13.1 v5.13.0 v5.13.0-rc3 v5.13.0-rc2 v5.13.0-rc1 v5.13.0-beta4 v5.13.0-beta3 v5.13.0-beta2 v5.13.0-beta1 v5.13.0-alpha1 v5.12.7 v5.12.6 v5.12.5 v5.12.4 v5.12.3 v5.12.2 v5.12.1 v5.12.0 v5.12.0-rc2 v5.12.0-rc1 v5.12.0-beta4 v5.12.0-beta3 v5.12.0-beta2 v5.12.0-beta1 v5.12.0-alpha1 v5.11.3 v5.11.2 v5.11.1 v5.11.0 v5.11.0-rc2 v5.11.0-rc1 v5.11.0-beta4 v5.11.0-beta3 v5.11.0-beta2 v5.11.0-beta1 v5.11.0-alpha1 v5.10.1 v5.10.0 v5.10.0-rc3 v5.10.0-rc2 v5.10.0-rc1 v5.10.0-beta4 v5.10.0-beta3 v5.10.0-beta2 v5.10.0-beta1 v5.10.0-alpha1 v5.9.9 v5.9.8 v5.9.7 v5.9.6 v5.9.5 v5.9.4 v5.9.3 v5.9.2 v5.9.1 v5.9.0 v5.9.0-rc2 v5.9.0-rc1 v5.9.0-beta4 v5.9.0-beta3 v5.9.0-beta2 v5.9.0-beta1 v5.9.0-alpha1 v5.8.0 v5.8.0-rc1 v5.8.0-beta1 v5.8.0-alpha1 v5.7.1 v5.7.0 v5.7.0-rc1 v5.7.0-beta1 v5.7.0-alpha1 v5.6.3 v5.6.2 v5.6.1 v5.6.1-1 v5.6.0 v5.6.0-rc1 v5.6.0-beta1 v5.6.0-alpha1 v5.5.1 v5.5.0 v5.5.0-rc1 v5.5.0-beta1 v5.5.0-alpha1 v5.4.2 v5.4.1 v5.4.0 v5.4.0-rc1 v5.4.0-beta1 v5.4.0-alpha1 v5.3.2 v5.3.1 v5.3.0 v5.3.0-rc1 v5.3.0-beta1 v5.3.0-alpha1 v5.2.1 v5.2.0 v5.2.0-rc1 v5.2.0-beta1 v5.2.0-alpha1 v5.1.1 v5.1.0 v5.1.0-rc2 v5.1.0-rc1 v5.1.0-beta1 v5.1.0-alpha1 v5.0.2 v5.0.1 v5.0.0 v5.0.0-rc2 v5.0.0-rc1 v5.0.0-beta2 v5.0.0-beta1 qt-v5.0.0-alpha1
No related merge requests found
Showing with 134 additions and 94 deletions
......@@ -55,64 +55,82 @@ QT_BEGIN_NAMESPACE
// XXX todo - should we change rectangle to draw entirely within its width/height?
QSGPen::QSGPen(QObject *parent)
: QObject(parent), _width(1), _color("#000000"), _valid(false)
: QObject(parent)
, m_width(1)
, m_color("#000000")
, m_aligned(true)
, m_valid(false)
{
}
qreal QSGPen::width() const
{
return m_width;
}
void QSGPen::setWidth(qreal w)
{
if (m_width == w && m_valid)
return;
m_width = w;
m_valid = m_color.alpha() && (qRound(m_width) >= 1 || (!m_aligned && m_width > 0));
emit penChanged();
}
QColor QSGPen::color() const
{
return _color;
return m_color;
}
void QSGPen::setColor(const QColor &c)
{
_color = c;
_valid = (_color.alpha() && _width >= 1) ? true : false;
m_color = c;
m_valid = m_color.alpha() && (qRound(m_width) >= 1 || (!m_aligned && m_width > 0));
emit penChanged();
}
int QSGPen::width() const
{
return _width;
bool QSGPen::aligned() const
{
return m_aligned;
}
void QSGPen::setWidth(int w)
void QSGPen::setAligned(bool aligned)
{
if (_width == w && _valid)
if (aligned == m_aligned)
return;
_width = w;
_valid = (_color.alpha() && _width >= 1) ? true : false;
m_aligned = aligned;
m_valid = m_color.alpha() && (qRound(m_width) >= 1 || (!m_aligned && m_width > 0));
emit penChanged();
}
bool QSGPen::isValid() const
{
return _valid;
return m_valid;
}
QSGGradientStop::QSGGradientStop(QObject *parent)
: QObject(parent)
: QObject(parent)
{
}
qreal QSGGradientStop::position() const
{
{
return m_position;
}
void QSGGradientStop::setPosition(qreal position)
{
{
m_position = position; updateGradient();
}
QColor QSGGradientStop::color() const
{
{
return m_color;
}
void QSGGradientStop::setColor(const QColor &color)
{
{
m_color = color; updateGradient();
}
......@@ -128,12 +146,12 @@ QSGGradient::QSGGradient(QObject *parent)
}
QSGGradient::~QSGGradient()
{
{
delete m_gradient;
}
QDeclarativeListProperty<QSGGradientStop> QSGGradient::stops()
{
{
return QDeclarativeListProperty<QSGGradientStop>(this, m_stops);
}
......@@ -257,8 +275,8 @@ QSGNode *QSGRectangle::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *da
if (d->pen && d->pen->isValid()) {
rectangle->setPenColor(d->pen->color());
rectangle->setPenWidth(d->pen->width());
rectangle->setAligned(d->pen->aligned());
} else {
rectangle->setPenColor(QColor());
rectangle->setPenWidth(0);
}
......
......@@ -58,26 +58,31 @@ class Q_DECLARATIVE_PRIVATE_EXPORT QSGPen : public QObject
{
Q_OBJECT
Q_PROPERTY(int width READ width WRITE setWidth NOTIFY penChanged)
Q_PROPERTY(qreal width READ width WRITE setWidth NOTIFY penChanged)
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY penChanged)
Q_PROPERTY(bool aligned READ aligned WRITE setAligned NOTIFY penChanged)
public:
QSGPen(QObject *parent=0);
int width() const;
void setWidth(int w);
qreal width() const;
void setWidth(qreal w);
QColor color() const;
void setColor(const QColor &c);
bool aligned() const;
void setAligned(bool aligned);
bool isValid() const;
Q_SIGNALS:
void penChanged();
private:
int _width;
QColor _color;
bool _valid;
qreal m_width;
QColor m_color;
bool m_aligned : 1;
bool m_valid : 1;
};
class Q_AUTOTEST_EXPORT QSGGradientStop : public QObject
......
......@@ -72,6 +72,7 @@ public:
virtual void setPenWidth(qreal width) = 0;
virtual void setGradientStops(const QGradientStops &stops) = 0;
virtual void setRadius(qreal radius) = 0;
virtual void setAligned(bool aligned) = 0;
virtual void update() = 0;
};
......
......@@ -50,6 +50,7 @@
#include <private/qsgcontext_p.h>
#include <QtCore/qmath.h>
#include <QtCore/qvarlengtharray.h>
QT_BEGIN_NAMESPACE
......@@ -57,6 +58,7 @@ QSGDefaultRectangleNode::QSGDefaultRectangleNode(QSGContext *context)
: m_border(0)
, m_radius(0)
, m_pen_width(0)
, m_aligned(true)
, m_gradient_is_opaque(true)
, m_dirty_geometry(false)
, m_default_geometry(QSGGeometry::defaultAttributes_Point2D(), 4)
......@@ -186,6 +188,14 @@ void QSGDefaultRectangleNode::setRadius(qreal radius)
m_dirty_geometry = true;
}
void QSGDefaultRectangleNode::setAligned(bool aligned)
{
if (aligned == m_aligned)
return;
m_aligned = aligned;
m_dirty_geometry = true;
}
void QSGDefaultRectangleNode::update()
{
if (m_dirty_geometry) {
......@@ -225,8 +235,10 @@ struct ColorVertex
void QSGDefaultRectangleNode::updateGeometry()
{
qreal penWidth = m_aligned ? qreal(qRound(m_pen_width)) : m_pen_width;
// fast path for the simple case...
if ((m_pen_width == 0 || m_border_material.color().alpha() == 0)
if ((penWidth == 0 || m_border_material.color().alpha() == 0)
&& m_radius == 0
&& m_material_type == TypeFlat) {
QSGGeometry::updateRectGeometry(&m_default_geometry, m_rect);
......@@ -234,9 +246,6 @@ void QSGDefaultRectangleNode::updateGeometry()
}
// ### This part down below is not optimal, using QVectors and reallocation for
// every change, but its all going to be fixed up in rewrite...
QSGGeometry *fill = geometry();
// Check that the vertex type matches the material.
......@@ -253,9 +262,12 @@ void QSGDefaultRectangleNode::updateGeometry()
int borderVertexCount = 0;
int borderIndexCount = 0;
QVector<uchar> fillVertexData;
QVector<Vertex> borderVertexData;
QVector<ushort> borderIndexData;
// Preallocate arrays for a rectangle with 18 segments per corner and 3 gradient stops.
QVarLengthArray<uchar, sizeof(ColorVertex) * (19 * 4 + 3 * 2)> fillVertices;
QVarLengthArray<Vertex, 19 * 8 + 3 * 2> borderVertices;
QVarLengthArray<ushort, 19 * 8 + 3 * 4 + 2> borderIndices;
int borderIndexHead = 0;
int borderIndexTail = 0;
Color4ub fillColor = colorToColor4ub(m_fill_material.color());
const QGradientStops &stops = m_gradient_stops;
......@@ -264,19 +276,20 @@ void QSGDefaultRectangleNode::updateGeometry()
// Rounded corners.
// Radius should never exceeds half of the width or half of the height
qreal radius = qMin(qMin(m_rect.width() / 2, m_rect.height() / 2), m_radius);
qreal radius = qMin(qMin(m_rect.width() * qreal(0.5), m_rect.height() * qreal(0.5)), m_radius);
QRectF innerRect = m_rect;
innerRect.adjust(radius, radius, -radius, -radius);
if (m_pen_width & 1) {
if (m_aligned && (int(penWidth) & 1)) {
// Pen width is odd, so add the offset as documented.
innerRect.moveLeft(innerRect.left() + qreal(0.5));
innerRect.moveTop(innerRect.top() + qreal(0.5));
}
qreal innerRadius = radius - m_pen_width * qreal(0.5);
qreal outerRadius = radius + m_pen_width * qreal(0.5);
qreal innerRadius = radius - penWidth * qreal(0.5);
qreal outerRadius = radius + penWidth * qreal(0.5);
int segments = qMin(30, qCeil(outerRadius)); // Number of segments per corner.
// Number of segments per corner, approximately one per 3 pixels.
int segments = qBound(3, qCeil(outerRadius * (M_PI / 6)), 18);
/*
......@@ -292,17 +305,15 @@ void QSGDefaultRectangleNode::updateGeometry()
*/
// Overestimate the number of vertices and indices, reduce afterwards when the actual numbers are known.
if (m_pen_width) {
if (penWidth) {
// The reason I add extra vertices where the gradient lines intersect the border is
// to avoid pixel sized gaps between the fill and the border caused by floating point
// inaccuracies.
borderVertexData.resize((segments + 1) * 2 * 4 + m_gradient_stops.size() * 2);
borderVertices.resize((segments + 1) * 2 * 4 + m_gradient_stops.size() * 2);
borderIndices.resize((segments + 1) * 2 * 4 + m_gradient_stops.size() * 4 + 2);
borderIndexHead = borderIndexTail = (borderIndices.count() >> 1) - 1;
}
fillVertexData.resize(((segments + 1) * 4 + m_gradient_stops.size() * 2) * fill->stride());
Vertex *borderVertices = borderVertexData.data();
void *fillVertices = fillVertexData.data(); // Can be Vertex, ColorVertex or TextureVertex.
fillVertices.resize(((segments + 1) * 4 + m_gradient_stops.size() * 2) * fill->stride());
int nextGradientStop = 0;
qreal gradientPos = (radius - innerRadius) / (innerRect.height() + 2 * radius);
......@@ -313,18 +324,26 @@ void QSGDefaultRectangleNode::updateGeometry()
qreal plx = 0; // previous inner left x-coordinate.
qreal prx = 0; // previous inner right x-coordinate.
qreal angle = qreal(0.5) * M_PI / qreal(segments);
qreal cosStep = qFastCos(angle);
qreal sinStep = qFastSin(angle);
for (int part = 0; part < 2; ++part) {
qreal c = 1 - part;
qreal s = part;
for (int i = 0; i <= segments; ++i) {
//### Should change to calculate sin/cos only once.
qreal angle = qreal(0.5 * M_PI) * (part + i / qreal(segments));
qreal s = qFastSin(angle);
qreal c = qFastCos(angle);
qreal y = (part ? innerRect.bottom() : innerRect.top()) - innerRadius * c; // current inner y-coordinate.
qreal lx = innerRect.left() - innerRadius * s; // current inner left x-coordinate.
qreal rx = innerRect.right() + innerRadius * s; // current inner right x-coordinate.
qreal Y = (part ? innerRect.bottom() : innerRect.top()) - outerRadius * c; // current outer y-coordinate.
qreal lX = innerRect.left() - outerRadius * s; // current outer left x-coordinate.
qreal rX = innerRect.right() + outerRadius * s; // current outer right x-coordinate.
{
// Rotate
qreal tmp = c;
c = c * cosStep - s * sinStep;
s = s * cosStep + tmp * sinStep;
}
gradientPos = ((part ? innerRect.height() : 0) + radius - innerRadius * c) / (innerRect.height() + 2 * radius);
while (nextGradientStop < stops.size() && stops.at(nextGradientStop).first <= gradientPos) {
......@@ -335,20 +354,20 @@ void QSGDefaultRectangleNode::updateGeometry()
qreal glx = plx * (1 - t) + t * lx;
qreal grx = prx * (1 - t) + t * rx;
if (m_pen_width) {
if (penWidth) {
borderVertices[borderVertexCount++].position = QVector2D(grx, gy);
borderVertices[borderVertexCount++].position = QVector2D(glx, gy);
int first = borderIndexData.first();
borderIndexData.prepend(borderVertexCount - 1);
borderIndexData.prepend(first);
int first = borderIndices[borderIndexHead];
borderIndices[--borderIndexHead] = borderVertexCount - 1;
borderIndices[--borderIndexHead] = first;
int last = borderIndexData.at(borderIndexData.size() - 2);
borderIndexData.append(last);
borderIndexData.append(borderVertexCount - 2);
int last = borderIndices[borderIndexTail - 2];
borderIndices[borderIndexTail++] = last;
borderIndices[borderIndexTail++] = borderVertexCount - 2;
}
ColorVertex *vertices = (ColorVertex *)fillVertices;
ColorVertex *vertices = (ColorVertex *)fillVertices.data();
fillColor = colorToColor4ub(stops.at(nextGradientStop).second);
vertices[fillVertexCount].position = QVector2D(grx, gy);
......@@ -361,21 +380,21 @@ void QSGDefaultRectangleNode::updateGeometry()
++nextGradientStop;
}
if (m_pen_width) {
if (penWidth) {
borderVertices[borderVertexCount++].position = QVector2D(rX, Y);
borderVertices[borderVertexCount++].position = QVector2D(lX, Y);
borderVertices[borderVertexCount++].position = QVector2D(rx, y);
borderVertices[borderVertexCount++].position = QVector2D(lx, y);
borderIndexData.prepend(borderVertexCount - 1);
borderIndexData.prepend(borderVertexCount - 3);
borderIndexData.append(borderVertexCount - 4);
borderIndexData.append(borderVertexCount - 2);
borderIndices[--borderIndexHead] = borderVertexCount - 1;
borderIndices[--borderIndexHead] = borderVertexCount - 3;
borderIndices[borderIndexTail++] = borderVertexCount - 4;
borderIndices[borderIndexTail++] = borderVertexCount - 2;
}
if (stops.isEmpty()) {
Q_ASSERT(m_material_type == TypeFlat);
Vertex *vertices = (Vertex *)fillVertices;
Vertex *vertices = (Vertex *)fillVertices.data();
vertices[fillVertexCount++].position = QVector2D(rx, y);
vertices[fillVertexCount++].position = QVector2D(lx, y);
} else {
......@@ -390,7 +409,7 @@ void QSGDefaultRectangleNode::updateGeometry()
fillColor = (colorToColor4ub(prev.second) * (1 - t) + colorToColor4ub(next.second) * t);
}
ColorVertex *vertices = (ColorVertex *)fillVertices;
ColorVertex *vertices = (ColorVertex *)fillVertices.data();
vertices[fillVertexCount].position = QVector2D(rx, y);
vertices[fillVertexCount].color = fillColor;
++fillVertexCount;
......@@ -405,15 +424,14 @@ void QSGDefaultRectangleNode::updateGeometry()
}
}
if (m_pen_width) {
if (penWidth) {
// Close border.
ushort first = borderIndexData.at(0);
ushort second = borderIndexData.at(1);
borderIndexData.append(first);
borderIndexData.append(second);
ushort first = borderIndices[borderIndexHead];
ushort second = borderIndices[borderIndexHead + 1];
borderIndices[borderIndexTail++] = first;
borderIndices[borderIndexTail++] = second;
borderIndexCount = borderIndexData.size();
borderIndexCount = borderIndexTail - borderIndexHead;
}
} else {
......@@ -423,27 +441,23 @@ void QSGDefaultRectangleNode::updateGeometry()
QRectF outerRect = m_rect;
qreal halfPenWidth = 0;
if (m_pen_width) {
if (m_pen_width & 1) {
if (penWidth) {
if (m_aligned && (int(penWidth) & 1)) {
// Pen width is odd, so add the offset as documented.
innerRect.moveLeft(innerRect.left() + qreal(0.5));
innerRect.moveTop(innerRect.top() + qreal(0.5));
outerRect = innerRect;
}
halfPenWidth = m_pen_width * qreal(0.5);
halfPenWidth = penWidth * qreal(0.5);
innerRect.adjust(halfPenWidth, halfPenWidth, -halfPenWidth, -halfPenWidth);
outerRect.adjust(-halfPenWidth, -halfPenWidth, halfPenWidth, halfPenWidth);
}
if (m_pen_width) {
borderVertexData.resize((2 + stops.size()) * 2 + 4);
borderIndexData.resize((2 + stops.size()) * 2 * 2 + 4);
if (penWidth) {
borderVertices.resize((2 + stops.size()) * 2 + 4);
borderIndices.resize((2 + stops.size()) * 2 * 2 + 4);
}
fillVertexData.resize((2 + stops.size()) * 2 * fill->stride());
void *fillVertices = fillVertexData.data();
Vertex *borderVertices = (Vertex *) borderVertexData.data();
ushort *borderIndices = borderIndexData.data();
fillVertices.resize((2 + stops.size()) * 2 * fill->stride());
int nextGradientStop = 0;
qreal gradientPos = halfPenWidth / m_rect.height();
......@@ -459,7 +473,7 @@ void QSGDefaultRectangleNode::updateGeometry()
qreal gy = (innerRect.top() - halfPenWidth) + stops.at(nextGradientStop).first * m_rect.height();
Q_ASSERT(fillVertexCount >= 2);
ColorVertex *vertices = (ColorVertex *)fillVertices;
ColorVertex *vertices = (ColorVertex *)fillVertices.data();
fillColor = colorToColor4ub(stops.at(nextGradientStop).second);
vertices[fillVertexCount].position = QVector2D(innerRect.right(), gy);
......@@ -469,7 +483,7 @@ void QSGDefaultRectangleNode::updateGeometry()
vertices[fillVertexCount].color = fillColor;
++fillVertexCount;
if (m_pen_width) {
if (penWidth) {
borderVertices[borderVertexCount++].position = QVector2D(innerRect.right(), gy);
borderVertices[borderVertexCount++].position = QVector2D(innerRect.left(), gy);
}
......@@ -479,7 +493,7 @@ void QSGDefaultRectangleNode::updateGeometry()
if (stops.isEmpty()) {
Q_ASSERT(m_material_type == TypeFlat);
Vertex *vertices = (Vertex *)fillVertices;
Vertex *vertices = (Vertex *)fillVertices.data();
vertices[fillVertexCount++].position = QVector2D(innerRect.right(), y);
vertices[fillVertexCount++].position = QVector2D(innerRect.left(), y);
} else {
......@@ -494,7 +508,7 @@ void QSGDefaultRectangleNode::updateGeometry()
fillColor = (colorToColor4ub(prev.second) * (1 - t) + colorToColor4ub(next.second) * t);
}
ColorVertex *vertices = (ColorVertex *)fillVertices;
ColorVertex *vertices = (ColorVertex *)fillVertices.data();
vertices[fillVertexCount].position = QVector2D(innerRect.right(), y);
vertices[fillVertexCount].color = fillColor;
++fillVertexCount;
......@@ -503,13 +517,13 @@ void QSGDefaultRectangleNode::updateGeometry()
++fillVertexCount;
}
if (m_pen_width) {
if (penWidth) {
borderVertices[borderVertexCount++].position = QVector2D(innerRect.right(), y);
borderVertices[borderVertexCount++].position = QVector2D(innerRect.left(), y);
}
}
if (m_pen_width) {
if (penWidth) {
// Add four corners.
borderVertices[borderVertexCount++].position = QVector2D(outerRect.right(), outerRect.top());
borderVertices[borderVertexCount++].position = QVector2D(outerRect.left(), outerRect.top());
......@@ -531,15 +545,15 @@ void QSGDefaultRectangleNode::updateGeometry()
}
// Copy from temporary datastructures to geometry...
if (m_pen_width) {
if (penWidth) {
borderGeometry->allocate(borderVertexCount, borderIndexCount);
memcpy(borderGeometry->indexData(), borderIndexData.constData(), borderIndexCount * sizeof(quint16));
memcpy(borderGeometry->vertexData(), borderVertexData.constData(), borderVertexCount * sizeof(Vertex));
memcpy(borderGeometry->indexData(), borderIndices.constData() + borderIndexHead, borderIndexCount * sizeof(quint16));
memcpy(borderGeometry->vertexData(), borderVertices.constData(), borderVertexCount * sizeof(Vertex));
m_border->markDirty(DirtyGeometry);
}
fill->allocate(fillVertexCount);
memcpy(fill->vertexData(), fillVertexData.constData(), fillVertexCount * fill->stride());
memcpy(fill->vertexData(), fillVertices.constData(), fillVertexCount * fill->stride());
markDirty(DirtyGeometry);
}
......
......@@ -68,6 +68,7 @@ public:
virtual void setPenWidth(qreal width);
virtual void setGradientStops(const QGradientStops &stops);
virtual void setRadius(qreal radius);
virtual void setAligned(bool aligned);
virtual void update();
private:
......@@ -87,8 +88,9 @@ private:
QRectF m_rect;
QGradientStops m_gradient_stops;
qreal m_radius;
int m_pen_width;
qreal m_pen_width;
uint m_aligned : 1;
uint m_gradient_is_opaque : 1;
uint m_dirty_geometry : 1;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment