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 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "linenode.h"
#include <QtGui/QColor>
#include <QtQuick/QSGMaterial>
class LineShader : public QSGMaterialShader
{
public:
LineShader() {
setShaderFileName(VertexStage, QLatin1String(":/scenegraph/graph/shaders/line.vert.qsb"));
setShaderFileName(FragmentStage, QLatin1String(":/scenegraph/graph/shaders/line.frag.qsb"));
}
bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
};
class LineMaterial : public QSGMaterial
{
public:
LineMaterial()
{
setFlag(Blending);
}
QSGMaterialType *type() const override
{
static QSGMaterialType type;
return &type;
}
QSGMaterialShader *createShader(QSGRendererInterface::RenderMode) const override
{
return new LineShader;
}
int compare(const QSGMaterial *m) const override
{
const LineMaterial *other = static_cast<const LineMaterial *>(m);
if (int diff = int(state.color.rgb()) - int(other->state.color.rgb()))
return diff;
if (int diff = state.size - other->state.size)
return diff;
if (int diff = state.spread - other->state.spread)
return diff;
return 0;
}
struct {
QColor color;
float size;
float spread;
} state;
};
bool LineShader::updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *)
{
QByteArray *buf = state.uniformData();
Q_ASSERT(buf->size() >= 92);
if (state.isMatrixDirty()) {
const QMatrix4x4 m = state.combinedMatrix();
memcpy(buf->data(), m.constData(), 64);
}
if (state.isOpacityDirty()) {
const float opacity = state.opacity();
memcpy(buf->data() + 80, &opacity, 4);
}
LineMaterial *mat = static_cast<LineMaterial *>(newMaterial);
float c[4];
mat->state.color.getRgbF(&c[0], &c[1], &c[2], &c[3]);
memcpy(buf->data() + 64, c, 16);
memcpy(buf->data() + 84, &mat->state.size, 4);
memcpy(buf->data() + 88, &mat->state.spread, 4);
return true;
}
struct LineVertex {
float x;
float y;
float t;
inline void set(float xx, float yy, float tt) { x = xx; y = yy; t = tt; }
};
static const QSGGeometry::AttributeSet &attributes()
{
static QSGGeometry::Attribute attr[] = {
QSGGeometry::Attribute::create(0, 2, QSGGeometry::FloatType, true),
QSGGeometry::Attribute::create(1, 1, QSGGeometry::FloatType)
};
static QSGGeometry::AttributeSet set = { 2, 3 * sizeof(float), attr };
return set;
}
LineNode::LineNode(float size, float spread, const QColor &color)
: m_geometry(attributes(), 0)
{
setGeometry(&m_geometry);
m_geometry.setDrawingMode(QSGGeometry::DrawTriangleStrip);
LineMaterial *m = new LineMaterial;
m->state.color = color;
m->state.size = size;
m->state.spread = spread;
setMaterial(m);
setFlag(OwnsMaterial);
}
/*
* Assumes that samples have values in the range of 0 to 1 and scales them to
* the height of bounds. The samples are stretched out horizontally along the
* width of the bounds.
*
* The position of each pair of points is identical, but we use the third value
* "t" to shift the point up or down and to add antialiasing.
*/
void LineNode::updateGeometry(const QRectF &bounds, const QList<qreal> &samples)
{
m_geometry.allocate(samples.size() * 2);
float x = bounds.x();
float y = bounds.y();
float w = bounds.width();
float h = bounds.height();
float dx = w / (samples.size() - 1);
LineVertex *v = (LineVertex *) m_geometry.vertexData();
for (int i=0; i<samples.size(); ++i) {
v[i*2+0].set(x + dx * i, y + samples.at(i) * h, 0);
v[i*2+1].set(x + dx * i, y + samples.at(i) * h, 1);
}
markDirty(QSGNode::DirtyGeometry);
}
|