aboutsummaryrefslogtreecommitdiff
path: root/glyph.cpp
blob: f143ee8e7c27edac20652e9cf751c18bb41593ed (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#include "glyph.h"

#include <cmath>
#include <QSGGeometry>
#include <QSGGeometryNode>
#include <QSGMaterial>
#include <QSGFlatColorMaterial>

const float PI = 3.1415f;

Glyph::Glyph(QQuickItem *parent)
    : QQuickItem(parent)
    , m_size(0)
{
    setFlag(QQuickItem::ItemHasContents);
}

void Glyph::setSize(qreal size)
{
    if (size == m_size)
        return;

    m_size = size;
    setWidth(size);
    setHeight(size);
    emit sizeChanged();
    update();
}

void Glyph::setColor(const QColor &color)
{
    if (color == m_color)
        return;

    m_color = color;
    emit colorChanged();
    update();
}

int calculateCircleVertexCount(qreal radius)
{
    // 10 * sqrt(r) \approx 2*pi / acos(1 - 1 / (4*r))
    return (int) (10.0 * sqrt(radius));
}

void updateCircleGeometry(QSGGeometry *geometry, const QRectF &bounds)
{
    int vertexCount = geometry->vertexCount();
    float cy = bounds.center().x();
    float cx = bounds.center().y();

    float theta = 2 * PI / float(vertexCount);
    float c = cosf(theta);
    float s = sinf(theta);
    float x = bounds.width() / 2;
    float y = 0;

    QSGGeometry::Point2D *vertexData = geometry->vertexDataAsPoint2D();
    for (int i = 0; i < vertexCount; i++) {
        vertexData[i].set(x + cx, y + cy);

        float t = x;
        x = c*x - s*y;
        y = s*t + c*y;
    }
}

QSGNode *Glyph::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
    QSGGeometryNode *node = 0;
    QSGGeometry *geometry = 0;
    QSGFlatColorMaterial *material = 0;
    int vertexCount = calculateCircleVertexCount(m_size / 2);

    if (!oldNode) {
        node = new QSGGeometryNode;

        geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), vertexCount);
        geometry->setDrawingMode(GL_POLYGON);
        node->setGeometry(geometry);
        node->setFlag(QSGNode::OwnsGeometry);

        material = new QSGFlatColorMaterial;
        material->setColor(m_color);
        node->setMaterial(material);
        node->setFlag(QSGNode::OwnsMaterial);
    } else {
        node = static_cast<QSGGeometryNode *>(oldNode);
        geometry = node->geometry();
        geometry->allocate(vertexCount);
    }

    updateCircleGeometry(geometry, boundingRect());
    node->markDirty(QSGNode::DirtyGeometry);

    material = static_cast<QSGFlatColorMaterial *>(node->material());
    if (material->color() != m_color) {
        material->setColor(m_color);
        node->markDirty(QSGNode::DirtyMaterial);
    }

    return node;
}