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 "qsgcurvestrokenode_p.h"
5#include "qsgcurvestrokenode_p_p.h"
6
7QT_BEGIN_NAMESPACE
8
9QSGCurveStrokeNode::QSGCurveStrokeNode()
10{
11 setFlag(OwnsGeometry, true);
12 setGeometry(new QSGGeometry(attributes(), 0, 0));
13 updateMaterial();
14}
15
16void QSGCurveStrokeNode::QSGCurveStrokeNode::updateMaterial()
17{
18 m_material.reset(other: new QSGCurveStrokeMaterial(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> QSGCurveStrokeNode::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 QSGCurveStrokeNode::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 p[0] to p[1]
51void QSGCurveStrokeNode::appendTriangle(const std::array<QVector2D, 3> &v,
52 const std::array<QVector2D, 2> &p,
53 const std::array<QVector2D, 3> &n,
54 QSGCurveStrokeNode::TriangleFlags flags)
55{
56 Q_UNUSED(flags)
57 // We could reduce this to a linear equation by setting A to (0,0).
58 // However, then we cannot use the cubic solution and need an additional
59 // code path in the shader. The following formulation looks more complicated
60 // but allows to always use the cubic solution.
61 auto A = p[1] - p[0];
62 auto B = QVector2D(0., 0.);
63 auto C = p[0];
64
65 int currentVertex = m_uncookedVertexes.count();
66
67// for (auto v : QList<std::pair<QVector2D, QVector2D>>({{v0, n0}, {v1, n1}, {v2, n2}})) {
68 for (int i = 0; i < 3; ++i) {
69 m_uncookedVertexes.append( t: { .x: v[i].x(), .y: v[i].y(),
70 .ax: A.x(), .ay: A.y(), .bx: B.x(), .by: B.y(), .cx: C.x(), .cy: C.y(),
71 .nx: n[i].x(), .ny: n[i].y() } );
72 }
73 m_uncookedIndexes << currentVertex << currentVertex + 1 << currentVertex + 2;
74}
75
76void QSGCurveStrokeNode::cookGeometry()
77{
78 QSGGeometry *g = geometry();
79 if (g->indexType() != QSGGeometry::UnsignedIntType) {
80 g = new QSGGeometry(attributes(),
81 m_uncookedVertexes.size(),
82 m_uncookedIndexes.size(),
83 QSGGeometry::UnsignedIntType);
84 setGeometry(g);
85 } else {
86 g->allocate(vertexCount: m_uncookedVertexes.size(), indexCount: m_uncookedIndexes.size());
87 }
88
89 g->setDrawingMode(QSGGeometry::DrawTriangles);
90 memcpy(dest: g->vertexData(),
91 src: m_uncookedVertexes.constData(),
92 n: g->vertexCount() * g->sizeOfVertex());
93 memcpy(dest: g->indexData(),
94 src: m_uncookedIndexes.constData(),
95 n: g->indexCount() * g->sizeOfIndex());
96
97 m_uncookedIndexes.clear();
98 m_uncookedIndexes.squeeze();
99 m_uncookedVertexes.clear();
100 m_uncookedVertexes.squeeze();
101}
102
103const QSGGeometry::AttributeSet &QSGCurveStrokeNode::attributes()
104{
105 static QSGGeometry::Attribute data[] = {
106 QSGGeometry::Attribute::createWithAttributeType(pos: 0, tupleSize: 2, primitiveType: QSGGeometry::FloatType, attributeType: QSGGeometry::PositionAttribute), //vertexCoord
107 QSGGeometry::Attribute::createWithAttributeType(pos: 1, tupleSize: 2, primitiveType: QSGGeometry::FloatType, attributeType: QSGGeometry::UnknownAttribute), //A
108 QSGGeometry::Attribute::createWithAttributeType(pos: 2, tupleSize: 2, primitiveType: QSGGeometry::FloatType, attributeType: QSGGeometry::UnknownAttribute), //B
109 QSGGeometry::Attribute::createWithAttributeType(pos: 3, tupleSize: 2, primitiveType: QSGGeometry::FloatType, attributeType: QSGGeometry::UnknownAttribute), //C
110 QSGGeometry::Attribute::createWithAttributeType(pos: 4, tupleSize: 2, primitiveType: QSGGeometry::FloatType, attributeType: QSGGeometry::UnknownAttribute), //normalVector
111 };
112 static QSGGeometry::AttributeSet attrs = { .count: 5, .stride: sizeof(StrokeVertex), .attributes: data };
113 return attrs;
114}
115
116QT_END_NAMESPACE
117

source code of qtdeclarative/src/quick/scenegraph/qsgcurvestrokenode.cpp