Files
RedBear-OS/recipes/wip/qt/qtquick3d/source/tools/shapegen/shapemanager.cpp
T
vasilito ff4ff35918 feat: track all source trees in git — full fork offline-first model
Red Bear OS is a full fork. All sources must be available from git clone
with zero network access. Removed gitignore rules that excluded fetched
source trees under recipes/*/source/, local/recipes/kde/*/source/,
local/recipes/qt/*/source/, and vendor source trees.

Build artifacts (target/, build/, source.tar, *.o, *.so) remain excluded.

127291 files added — kernel, relibc, base, bootloader, pkgar, all KDE/Qt
frameworks, mesa, wayland, DRM drivers, and every other recipe source.
2026-05-14 10:55:53 +01:00

178 lines
4.8 KiB
C++

// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "shapemanager.h"
#include <QtQuick3DParticles/private/qquick3dparticleshapedatautils_p.h>
#include <QtCore/qdir.h>
#include <QCborStreamWriter>
#include <QCborStreamReader>
#include <QRandomGenerator>
ShapeManager::ShapeManager(QObject *parent) : QObject(parent)
{
}
void ShapeManager::setImage(const QString &filename)
{
if (m_imageFilename == filename)
return;
m_imageFilename = filename;
loadImage();
}
void ShapeManager::setDepth(float depth)
{
m_depth = depth;
}
void ShapeManager::setScale(float scale)
{
m_scale = scale;
}
// Set the amount of positions CBOR should contain.
// When -1, then amount is same as the amount of pixels in the image.
// Default value -1.
void ShapeManager::setAmount(int amount)
{
m_amount = amount;
}
void ShapeManager::setSortingMode(SortingMode mode)
{
m_sortingMode = mode;
}
void ShapeManager::setSortingPosition(const QVector3D &position)
{
m_sortingPosition = position;
}
bool ShapeManager::loadImage()
{
QFileInfo fileInfo(m_imageFilename);
// Is this a real file?
if (!fileInfo.exists()) {
qWarning() << "Imagefile not found:" << qPrintable(m_imageFilename);
return false;
}
if (!m_image.load(m_imageFilename)) {
qWarning() << "Not able to load image:" << qPrintable(m_imageFilename);
return false;
}
// Make sure image is in proper format
if (m_image.format() != QImage::Format_ARGB32 && m_image.format() != QImage::Format_ARGB32_Premultiplied)
m_image = m_image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
// Flip the image
m_image.flip();
return true;
}
bool ShapeManager::generateData()
{
if (m_image.isNull()) {
qWarning() << "Can't generate data, no image loaded";
return false;
}
QRect r(0, 0, m_image.width(), m_image.height());
// resample on the fly using 16-bit
int sx = (m_image.width() << 16) / r.width();
int sy = (m_image.height() << 16) / r.height();
int w = r.width();
int h = r.height();
for (int y = 0; y < h; ++y) {
const uint *sl = (const uint *) m_image.constScanLine((y * sy) >> 16);
for (int x = 0; x < w; ++x) {
if (sl[(x * sx) >> 16] & 0xff000000) {
QVector3D pos(x - (w * 0.5f), y - (h * 0.5f), 0.0f);
pos *= m_scale;
// Get random z based on depth
float posZ = float(QRandomGenerator::global()->generateDouble() - 0.5f) * m_depth * m_scale;
pos.setZ(posZ);
m_data << pos;
}
}
}
// Shuffle the data into random order
auto rd = std::random_device{};
std::shuffle(m_data.begin(),
m_data.end(),
std::default_random_engine(rd()));
return true;
}
bool ShapeManager::saveShapeData(const QString &filename)
{
m_outputData.clear();
QFile dataFile(filename);
if (!dataFile.open(QIODevice::WriteOnly)) {
// Invalid file
qWarning() << "Unable to open file:" << filename;
return false;
}
QCborStreamWriter writer(&dataFile);
QQuick3DParticleShapeDataUtils::writeShapeHeader(writer);
// Start positions array
writer.startArray();
// Collect correct amount of positions
if (m_amount < 0) {
m_outputData = m_data;
} else {
// m_data is shuffled so we can just pick m_amount from there
int index = 0;
while (m_outputData.size() < m_amount) {
m_outputData << m_data[index];
index = index < (m_data.size() - 1) ? index + 1 : 0;
}
}
// Sort
if (m_sortingMode == SortingMode::DistanceClosestFirst) {
std::sort(m_outputData.begin(),
m_outputData.end(),
[this](const QVector3D& lhs, const QVector3D& rhs) {
return m_sortingPosition.distanceToPoint(lhs) < m_sortingPosition.distanceToPoint(rhs);
});
} else if (m_sortingMode == SortingMode::DistanceClosestLast) {
std::sort(m_outputData.begin(),
m_outputData.end(),
[this](const QVector3D& lhs, const QVector3D& rhs) {
return m_sortingPosition.distanceToPoint(rhs) < m_sortingPosition.distanceToPoint(lhs);
});
}
// Write positions
for (auto position : m_outputData)
QQuick3DParticleShapeDataUtils::writeValue(writer, position);
// Leave positions array
writer.endArray();
// Leave root array
writer.endArray();
return true;
}
void ShapeManager::dumpOutput()
{
qDebug() << "Particle Shape";
qDebug() << m_outputData;
qDebug() << "Image positions:" << m_data.size();
qDebug() << "Generated positions:" << m_outputData.size();
}