1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qquickshapestrokenode_p.h"
5#include "qquickshapestrokenode_p_p.h"
6
7QT_BEGIN_NAMESPACE
8
9QQuickShapeStrokeNode::QQuickShapeStrokeNode()
10{
11 setFlag(OwnsGeometry, true);
12 setGeometry(new QSGGeometry(attributes(), 0, 0));
13 updateMaterial();
14}
15
16void QQuickShapeStrokeNode::QQuickShapeStrokeNode::updateMaterial()
17{
18 m_material.reset(other: new QQuickShapeStrokeMaterial(this));
19 setMaterial(m_material.data());
20}
21
22// Take the start, control and end point of a curve and return the points A, B, C
23// representing the curve as Q(s) = A*s*s + B*s + C
24std::array<QVector2D, 3> QQuickShapeStrokeNode::curveABC(const std::array<QVector2D, 3> &p)
25{
26 QVector2D a = p[0] - 2*p[1] + p[2];
27 QVector2D b = 2*p[1] - 2*p[0];
28 QVector2D c = p[0];
29
30 return {a, b, c};
31}
32
33// Curve from p[0] to p[2] with control point p[1]
34void QQuickShapeStrokeNode::appendTriangle(const std::array<QVector2D, 3> &v,
35 const std::array<QVector2D, 3> &p,
36 const std::array<QVector2D, 3> &n)
37{
38 auto abc = curveABC(p);
39
40 int currentVertex = m_uncookedVertexes.count();
41
42 for (int i = 0; i < 3; ++i) {
43 m_uncookedVertexes.append( t: { .x: v[i].x(), .y: v[i].y(),
44 .ax: abc[0].x(), .ay: abc[0].y(), .bx: abc[1].x(), .by: abc[1].y(), .cx: abc[2].x(), .cy: abc[2].y(),
45 .nx: n[i].x(), .ny: n[i].y() } );
46 }
47 m_uncookedIndexes << currentVertex << currentVertex + 1 << currentVertex + 2;
48}
49
50// Straight line from p0 to p1
51void QQuickShapeStrokeNode::appendTriangle(const std::array<QVector2D, 3> &v,
52 const std::array<QVector2D, 2> &p,
53 const std::array<QVector2D, 3> &n)
54{
55 // We could reduce this to a linear equation by setting A to (0,0).
56 // However, then we cannot use the cubic solution and need an additional
57 // code path in the shader. The following formulation looks more complicated
58 // but allows to always use the cubic solution.
59 auto A = p[1] - p[0];
60 auto B = QVector2D(0., 0.);
61 auto C = p[0];
62
63 int currentVertex = m_uncookedVertexes.count();
64
65// for (auto v : QList<QPair<QVector2D, QVector2D>>({{v0, n0}, {v1, n1}, {v2, n2}})) {
66 for (int i = 0; i < 3; ++i) {
67 m_uncookedVertexes.append( t: { .x: v[i].x(), .y: v[i].y(),
68 .ax: A.x(), .ay: A.y(), .bx: B.x(), .by: B.y(), .cx: C.x(), .cy: C.y(),
69 .nx: n[i].x(), .ny: n[i].y() } );
70 }
71 m_uncookedIndexes << currentVertex << currentVertex + 1 << currentVertex + 2;
72}
73
74void QQuickShapeStrokeNode::cookGeometry()
75{
76 QSGGeometry *g = geometry();
77 if (g->indexType() != QSGGeometry::UnsignedIntType) {
78 g = new QSGGeometry(attributes(),
79 m_uncookedVertexes.size(),
80 m_uncookedIndexes.size(),
81 QSGGeometry::UnsignedIntType);
82 setGeometry(g);
83 } else {
84 g->allocate(vertexCount: m_uncookedVertexes.size(), indexCount: m_uncookedIndexes.size());
85 }
86
87 g->setDrawingMode(QSGGeometry::DrawTriangles);
88 memcpy(dest: g->vertexData(),
89 src: m_uncookedVertexes.constData(),
90 n: g->vertexCount() * g->sizeOfVertex());
91 memcpy(dest: g->indexData(),
92 src: m_uncookedIndexes.constData(),
93 n: g->indexCount() * g->sizeOfIndex());
94
95 m_uncookedIndexes.clear();
96 m_uncookedVertexes.clear();
97}
98
99const QSGGeometry::AttributeSet &QQuickShapeStrokeNode::attributes()
100{
101 static QSGGeometry::Attribute data[] = {
102 QSGGeometry::Attribute::createWithAttributeType(pos: 0, tupleSize: 2, primitiveType: QSGGeometry::FloatType, attributeType: QSGGeometry::PositionAttribute), //vertexCoord
103 QSGGeometry::Attribute::createWithAttributeType(pos: 1, tupleSize: 2, primitiveType: QSGGeometry::FloatType, attributeType: QSGGeometry::UnknownAttribute), //A
104 QSGGeometry::Attribute::createWithAttributeType(pos: 2, tupleSize: 2, primitiveType: QSGGeometry::FloatType, attributeType: QSGGeometry::UnknownAttribute), //B
105 QSGGeometry::Attribute::createWithAttributeType(pos: 3, tupleSize: 2, primitiveType: QSGGeometry::FloatType, attributeType: QSGGeometry::UnknownAttribute), //C
106 QSGGeometry::Attribute::createWithAttributeType(pos: 4, tupleSize: 2, primitiveType: QSGGeometry::FloatType, attributeType: QSGGeometry::UnknownAttribute), //normalVector
107 };
108 static QSGGeometry::AttributeSet attrs = { .count: 5, .stride: sizeof(StrokeVertex), .attributes: data };
109 return attrs;
110}
111
112QT_END_NAMESPACE
113

source code of qtdeclarative/src/quickshapes/qquickshapestrokenode.cpp