Source code

Revision control

Copy as Markdown

// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "textureitem.h"
#include <QPainter>
TextureItem::TextureItem(QQuickItem *parent)
: QQuickPaintedItem(parent), m_image(512, 512, QImage::Format_RGBA8888)
{
m_image.fill(Qt::white);
}
void TextureItem::paint(QPainter *painter)
{
const double scale = qMin(width() / double(m_image.width()),
height() / double(m_image.height()));
double w = m_image.width() * scale;
double h = m_image.height() * scale;
painter->drawImage(QRectF(0, 0, w, h), m_image);
updateImage();
}
const QQuick3DTextureData *TextureItem::textureData() const
{
return &m_textureData;
}
void TextureItem::setPoint(float x, float y, int id, bool pressed)
{
const double s = qMin(width(), height());
setUv(x/s, y/s, id, pressed);
}
void TextureItem::setUv(float u, float v, int id, bool pressed)
{
auto &s = state[id];
bool inRange = u >= 0 && u <= 1 && v >=0 && v <= 1;
if (!pressed || !inRange) {
s.reset();
return;
}
bool isDrawing = s.initialized;
QPointF pt(u, v);
QPointF prevRaw = s.prevRaw;
QPointF uv1 = s.prevFiltered;
QPointF uv2 = s.filter({u, v}, QDateTime::currentMSecsSinceEpoch());
// Huge jumps are probably caused by crossing a
// uv boundary on the model
const float dist = (pt - prevRaw).manhattanLength();
const bool jumped = dist > 0.9 && isDrawing;
if (jumped) {
QPointF adjust;
if (u < 0.2 && prevRaw.x() > 0.8)
adjust.setX(1);
else if (u > 0.8 && prevRaw.x() < 0.2)
adjust.setX(-1);
if (v < 0.2 && prevRaw.y() > 0.8)
adjust.setY(1);
else if (v > 0.8 && prevRaw.y() < 0.2)
adjust.setY(-1);
// End point of this line is moved outside. Since the filtered point is lagging behind, use the raw point for this.
uv2 = pt + adjust;
// And then we need to set the start point of the next line to be outside the opposite side.
// To avoid discontinuities, we use the same start point as this line.
s.prevFiltered = uv1 - adjust;
// Ideally, we should have drawn a second line here, but for simplicity, we'll wait until the next point arrives.
}
if (isDrawing) {
QPainter p;
p.begin(&m_image);
p.scale(m_image.width(), m_image.height());
QPen pen(s.color, m_penWidth);
pen.setCosmetic(true);
pen.setCapStyle(Qt::RoundCap);
p.setPen(pen);
p.drawLine(uv1, uv2);
p.end();
updateImage();
update();
}
}
void TextureItem::clear(const QColor &color)
{
m_image.fill(color);
updateImage();
update();
}
void TextureItem::setColor(const QColor &newColor, int id)
{
auto &s = state[id];
s.color = newColor;
}
void TextureItem::setPenWidth(qreal newPenWidth)
{
m_penWidth = newPenWidth;
}
void TextureItem::resetPoint(int id)
{
auto &s = state[id];
reset(s);
}
void TextureItem::updateImage()
{
m_textureData.setSize(m_image.size());
m_textureData.setTextureData(QByteArray::fromRawData(reinterpret_cast<const char*>(m_image.constBits()), m_image.sizeInBytes()));
}
void TextureItem::reset(TouchPointState &s)
{
s.reset();
}