mirror of
https://github.com/subsurface/subsurface.git
synced 2024-11-30 22:20:21 +00:00
faf3e7079d
So far the items to be recalculated in the drawing thread had a "dirty" flag and were kept in one array par z-level. Once the series are implemented in terms of QSGNodes, there may lots of these items. To make this more efficient when only one or two of these items change (e.g. highlighting due to mouseover), keep the dirty items in a linked list. Of course, this makes the draw first version of the chart less efficient. There are more fancy ways of implementing the double-linked list, but the few ns gained in the render thread are hardly worth it. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
164 lines
3.7 KiB
C++
164 lines
3.7 KiB
C++
// SPDX-License-Identifier: GPL-2.0
|
|
#include "chartitem.h"
|
|
#include "statsview.h"
|
|
|
|
#include <cmath>
|
|
#include <QQuickWindow>
|
|
#include <QSGFlatColorMaterial>
|
|
#include <QSGImageNode>
|
|
#include <QSGTexture>
|
|
|
|
static int round_up(double f)
|
|
{
|
|
return static_cast<int>(ceil(f));
|
|
}
|
|
|
|
ChartItem::ChartItem(StatsView &v, ChartZValue z) :
|
|
dirty(false), dirtyPrev(nullptr), dirtyNext(nullptr),
|
|
zValue(z), view(v)
|
|
{
|
|
}
|
|
|
|
ChartItem::~ChartItem()
|
|
{
|
|
if (dirty)
|
|
view.unregisterDirtyChartItem(*this);
|
|
}
|
|
|
|
QSizeF ChartItem::sceneSize() const
|
|
{
|
|
return view.size();
|
|
}
|
|
|
|
ChartPixmapItem::ChartPixmapItem(StatsView &v, ChartZValue z) : ChartItem(v, z),
|
|
positionDirty(false), textureDirty(false)
|
|
{
|
|
}
|
|
|
|
ChartPixmapItem::~ChartPixmapItem()
|
|
{
|
|
painter.reset(); // Make sure to destroy painter before image that is painted on
|
|
}
|
|
|
|
void ChartPixmapItem::setTextureDirty()
|
|
{
|
|
textureDirty = true;
|
|
view.registerDirtyChartItem(*this);
|
|
}
|
|
|
|
void ChartPixmapItem::setPositionDirty()
|
|
{
|
|
positionDirty = true;
|
|
view.registerDirtyChartItem(*this);
|
|
}
|
|
|
|
void ChartPixmapItem::render()
|
|
{
|
|
if (!node) {
|
|
node.reset(view.w()->createImageNode());
|
|
view.addQSGNode(node.get(), zValue);
|
|
}
|
|
if (!img) {
|
|
resize(QSizeF(1,1));
|
|
img->fill(Qt::transparent);
|
|
}
|
|
if (textureDirty) {
|
|
texture.reset(view.w()->createTextureFromImage(*img, QQuickWindow::TextureHasAlphaChannel));
|
|
node->setTexture(texture.get());
|
|
textureDirty = false;
|
|
}
|
|
if (positionDirty) {
|
|
node->setRect(rect);
|
|
positionDirty = false;
|
|
}
|
|
}
|
|
|
|
void ChartPixmapItem::resize(QSizeF size)
|
|
{
|
|
painter.reset();
|
|
img.reset(new QImage(round_up(size.width()), round_up(size.height()), QImage::Format_ARGB32));
|
|
painter.reset(new QPainter(img.get()));
|
|
painter->setRenderHint(QPainter::Antialiasing);
|
|
rect.setSize(size);
|
|
setTextureDirty();
|
|
}
|
|
|
|
void ChartPixmapItem::setPos(QPointF pos)
|
|
{
|
|
rect.moveTopLeft(pos);
|
|
setPositionDirty();
|
|
}
|
|
|
|
QRectF ChartPixmapItem::getRect() const
|
|
{
|
|
return rect;
|
|
}
|
|
|
|
ChartRectItem::ChartRectItem(StatsView &v, ChartZValue z,
|
|
const QPen &pen, const QBrush &brush, double radius) : ChartPixmapItem(v, z),
|
|
pen(pen), brush(brush), radius(radius)
|
|
{
|
|
}
|
|
|
|
ChartRectItem::~ChartRectItem()
|
|
{
|
|
}
|
|
|
|
void ChartRectItem::resize(QSizeF size)
|
|
{
|
|
ChartPixmapItem::resize(size);
|
|
img->fill(Qt::transparent);
|
|
painter->setPen(pen);
|
|
painter->setBrush(brush);
|
|
QSize imgSize = img->size();
|
|
int width = pen.width();
|
|
QRect rect(width / 2, width / 2, imgSize.width() - width, imgSize.height() - width);
|
|
painter->drawRoundedRect(rect, radius, radius, Qt::AbsoluteSize);
|
|
}
|
|
|
|
ChartLineItem::ChartLineItem(StatsView &v, ChartZValue z, QColor color, double width) : ChartItem(v, z),
|
|
color(color), width(width), positionDirty(false), materialDirty(false)
|
|
{
|
|
}
|
|
|
|
ChartLineItem::~ChartLineItem()
|
|
{
|
|
}
|
|
|
|
void ChartLineItem::render()
|
|
{
|
|
if (!node) {
|
|
geometry.reset(new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 2));
|
|
geometry->setDrawingMode(QSGGeometry::DrawLines);
|
|
material.reset(new QSGFlatColorMaterial);
|
|
node.reset(new QSGGeometryNode);
|
|
node->setGeometry(geometry.get());
|
|
node->setMaterial(material.get());
|
|
view.addQSGNode(node.get(), zValue);
|
|
positionDirty = materialDirty = true;
|
|
}
|
|
|
|
if (positionDirty) {
|
|
// Attention: width is a geometry property and therefore handled by position dirty!
|
|
geometry->setLineWidth(static_cast<float>(width));
|
|
auto vertices = geometry->vertexDataAsPoint2D();
|
|
vertices[0].set(static_cast<float>(from.x()), static_cast<float>(from.y()));
|
|
vertices[1].set(static_cast<float>(to.x()), static_cast<float>(to.y()));
|
|
node->markDirty(QSGNode::DirtyGeometry);
|
|
}
|
|
|
|
if (materialDirty) {
|
|
material->setColor(color);
|
|
node->markDirty(QSGNode::DirtyMaterial);
|
|
}
|
|
|
|
positionDirty = materialDirty = false;
|
|
}
|
|
|
|
void ChartLineItem::setLine(QPointF fromIn, QPointF toIn)
|
|
{
|
|
from = fromIn;
|
|
to = toIn;
|
|
positionDirty = true;
|
|
view.registerDirtyChartItem(*this);
|
|
}
|