ff4ff35918
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.
178 lines
4.8 KiB
C++
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();
|
|
}
|