1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
|
// 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();
}
|