#include "tiled_image_item.h"
#include <QSGImageNode>
#include <QSGTexture>
TiledImageItem::TiledImageItem(QQuickItem *parent) : QQuickItem{parent} {
setFlag(ItemHasContents, true);
setFlag(ItemObservesViewport, true);
}
TiledImageItem::~TiledImageItem() {}
void TiledImageItem::setImageData(int width, int height, uchar *pixels,
QImage::Format format) {
m_texture = QImage{pixels, width, height, width * 4, format};
setImplicitWidth(width / window()->effectiveDevicePixelRatio());
setImplicitHeight(height / window()->effectiveDevicePixelRatio());
buildTiles();
update();
}
void TiledImageItem::buildTiles() {
m_tiles.clear();
if (m_texture.isNull()) {
return;
}
const auto imageWidth = m_texture.width();
const auto imageHeight = m_texture.height();
for (int y = 0; y < imageHeight; y += m_tileSize) {
for (int x = 0; x < imageWidth; x += m_tileSize) {
int w = qMin(m_tileSize, imageWidth - x);
int h = qMin(m_tileSize, imageHeight - y);
QImage tileImage{&m_texture.scanLine(y)[x * m_texture.depth() / 8],
m_tileSize, m_tileSize, m_texture.bytesPerLine(),
m_texture.format()};
QRectF tileRect = QRect{x, y, w, h}.toRectF();
tileRect.setTopLeft(tileRect.topLeft() /
window()->effectiveDevicePixelRatio());
tileRect.setBottomRight(tileRect.bottomRight() /
window()->effectiveDevicePixelRatio());
Tile tile;
tile.outRect = tileRect;
tile.image = tileImage;
tile.dirty = true;
m_tiles.emplace_back(std::move(tile));
}
}
}
int TiledImageItem::tileSize() const { return m_tileSize; }
void TiledImageItem::setTileSize(int newTileSize) {
if (m_tileSize == newTileSize) {
return;
}
m_tileSize = newTileSize;
m_tiles.clear();
m_dirty = true;
Q_EMIT tileSizeChanged();
}
void TiledImageItem::test(const QString &fileName) {
auto image = new QImage(fileName);
setImageData(image->width(), image->height(), image->bits(), image->format());
}
QSGNode *TiledImageItem::updatePaintNode(QSGNode *oldNode,
UpdatePaintNodeData *) {
auto rootNode = oldNode;
if (!rootNode) {
rootNode = new QSGNode{};
}
if (!window()) {
return rootNode;
}
const auto rect = clipRect();
for (auto &tile : m_tiles) {
if (!rect.intersects(tile.outRect)) {
if (tile.node) {
rootNode->removeChildNode(tile.node.get());
tile.node.reset();
}
continue;
}
if (tile.dirty) {
tile.texture.reset(window()->createTextureFromImage(tile.image));
if (tile.node) {
tile.node->setTexture(tile.texture.get());
}
tile.dirty = false;
}
if (!tile.node) {
tile.node.reset(window()->createImageNode());
tile.node->setRect(tile.outRect);
tile.node->setTexture(tile.texture.get());
rootNode->appendChildNode(tile.node.get());
}
}
return rootNode;
}
TiledImageItem::Tile::Tile(Tile &&other) noexcept
: outRect{other.outRect},
image{std::move(other.image)},
dirty{other.dirty},
texture{std::move(other.texture)} {}