8#include <QtCore/qdir.h>
9#include <QtQml/qqmlfile.h>
11#include <QtQuick3D/private/qquick3dobject_p.h>
12#include <QtQuick3D/private/qquick3dgeometry_p.h>
14#include <QtQuick3DUtils/private/qssgutils_p.h>
15#include <QtQuick3DRuntimeRender/private/qssgrenderparticles_p.h>
16#include <QtQuick3DRuntimeRender/private/qssgrendergeometry_p.h>
17#include <QtQuick3DRuntimeRender/private/qssgrendermodel_p.h>
18#include <QtQuick3DUtils/private/qssgmesh_p.h>
68 delete m_modelGeometry;
141 return m_modelBlendMode;
170 return m_activationNode;
197 if (m_endNode == node)
209 handleEndNodeChanged();
215 if (m_modelBlendMode ==
mode)
217 m_modelBlendMode =
mode;
248void QQuick3DParticleModelBlendParticle::regenerate()
259 if (QQuick3DParticleSystem::isGloballyDisabled())
264 m_model = qobject_cast<QQuick3DModel *>(
obj);
273 handleEndNodeChanged();
295 const quint8 *vertex = srcVertices + idx * vertexStride;
296 return *
reinterpret_cast<const QVector3D *
>(vertex + posOffset);
301 return qMax(center.distanceToPoint(
p1),
qMax(center.distanceToPoint(
p2), center.distanceToPoint(p0)));
305 QVector<QVector3D> ¢erData,
306 float &maxTriangleRadius,
314 const quint8 *srcVertices =
reinterpret_cast<const quint8 *
>(vertexBufferData.data());
316 const quint16 *indexData16 =
reinterpret_cast<const quint16 *
>(indexBufferData.begin());
317 const quint32 *indexData32 =
reinterpret_cast<const quint32 *
>(indexBufferData.begin());
318 const float c_div3 = 1.0f / 3.0f;
319 for (
quint32 i = 0;
i < primitiveCount;
i++) {
322 i0 = indexData16[3 *
i];
323 i1 = indexData16[3 *
i + 1];
324 i2 = indexData16[3 *
i + 2];
326 i0 = indexData32[3 *
i];
327 i1 = indexData32[3 *
i + 1];
328 i2 = indexData32[3 *
i + 2];
334 centerData[
i] = center;
336 memcpy(
dst, srcVertices + i0 * vertexStride, vertexStride);
338 memcpy(
dst, srcVertices + i1 * vertexStride, vertexStride);
340 memcpy(
dst, srcVertices + i2 * vertexStride, vertexStride);
346 float &maxTriangleRadius,
352 const quint8 *srcVertices =
reinterpret_cast<const quint8 *
>(vertexBufferData.data());
353 const float c_div3 = 1.0f / 3.0f;
354 for (
quint32 i = 0;
i < primitiveCount;
i++) {
359 centerData[
i] = center;
364void QQuick3DParticleModelBlendParticle::updateParticles()
366 m_maxTriangleRadius = 0.f;
374 qWarning () <<
"ModelBlendParticle3D: Invalid geometry primitive type, must be Triangles. ";
378 auto indexBuffer = geometry->
indexData();
380 if (!vertexBuffer.size()) {
381 qWarning () <<
"ModelBlendParticle3D: Invalid geometry, vertexData is empty. ";
388 if (attr.semantic == semantic)
395 if (indexBuffer.size()) {
416 primitiveCount /= 12;
418 unindexedVertexData.resize(geometry->
stride() * primitiveCount * 3);
419 m_centerData.resize(primitiveCount);
420 m_particleCount = primitiveCount;
435 quint32 primitiveCount = vertexBuffer.size() / geometry->
stride() / 3;
436 m_centerData.resize(primitiveCount);
437 m_particleCount = primitiveCount;
452 qWarning () <<
"ModelBlendParticle3D: Unable to load mesh: " <<
src;
455 if (mesh.
drawMode() != QSSGMesh::Mesh::DrawMode::Triangles) {
456 qWarning () <<
"ModelBlendParticle3D: Invalid mesh primitive type, must be Triangles. ";
466 for (
const auto &e : vb.entries) {
467 if (e.name ==
name) {
468 Q_ASSERT(e.componentType == QSSGMesh::Mesh::ComponentType::Float32);
484 if (indexBuffer.componentType == QSSGMesh::Mesh::ComponentType::UnsignedInt16)
489 if (indexBuffer.data.size()) {
492 quint32 primitiveCount = indexedPrimitiveCount(indexBuffer);
493 bool u16IndexType = indexBuffer.componentType == QSSGMesh::Mesh::ComponentType::UnsignedInt16;
494 unindexedVertexData.resize(vertexBuffer.stride * primitiveCount * 3);
495 m_centerData.resize(primitiveCount);
496 m_particleCount = primitiveCount;
508 m_modelGeometry->
setStride(vertexBuffer.stride);
513 quint32 primitiveCount = vertexBuffer.data.size() / vertexBuffer.stride / 3;
514 m_centerData.resize(primitiveCount);
515 m_particleCount = primitiveCount;
523 m_modelGeometry->
setStride(vertexBuffer.stride);
527 for (
auto &e : vertexBuffer.entries)
528 m_modelGeometry->addAttribute(toAttribute(e));
529 for (
auto &
s : mesh.subsets())
542 m_maxTriangleRadius *= scaleMax;
544 m_triangleParticleData.resize(m_particleCount);
547 for (
int i = 0;
i < m_particleCount;
i++) {
548 m_triangleParticleData[
i].center = m_centerData[
i];
551 m_triangleParticleData[
i].size = 0.0f;
553 m_triangleParticleData[
i].size = 1.0f;
554 m_triangleParticleData[
i].position = m_centerData[
i];
570#if QT_CONFIG(qml_debug)
572 if (geometrySpatialNode)
578 if (!
model->particleBuffer) {
586 updateParticleBuffer(
model->particleBuffer, psystem->sceneTransform());
593 if (!
system() && qobject_cast<QQuick3DParticleSystem *>(parentItem()))
594 setSystem(qobject_cast<QQuick3DParticleSystem *>(parentItem()));
603 qWarning() <<
"ModelBlendParticle3D.maxAmount: Unable to set maximum amount, because it is set from the model.";
609 if (!m_perEmitterData.
contains(emitter)) {
610 m_perEmitterData.
insert(emitter, PerEmitterData());
611 auto &perEmitter = m_perEmitterData[emitter];
612 perEmitter.emitter = emitter;
613 perEmitter.emitterIndex = m_nextEmitterIndex++;
615 auto &perEmitter = m_perEmitterData[emitter];
617 if (m_triangleParticleData[
index].emitterIndex != perEmitter.emitterIndex) {
618 if (m_triangleParticleData[
index].emitterIndex >= 0)
619 perEmitterData(m_triangleParticleData[
index].emitterIndex).particleCount--;
620 perEmitter.particleCount++;
622 m_triangleParticleData[
index].emitterIndex = perEmitter.emitterIndex;
631 float size,
float age)
633 auto &
dst = m_triangleParticleData[particleIndex];
635 m_dataChanged =
true;
638QQuick3DParticleModelBlendParticle::PerEmitterData &QQuick3DParticleModelBlendParticle::perEmitterData(
int emitterIndex)
640 for (
auto &perEmitter : m_perEmitterData) {
641 if (perEmitter.emitterIndex == emitterIndex)
644 return n_noPerEmitterData;
649 const auto &particles = m_triangleParticleData;
651 if (!
buffer || !m_dataChanged)
654 const int particleCount = m_particleCount;
656 char *dest =
buffer->pointer();
657 const TriangleParticleData *
src = particles.data();
658 const int pps =
buffer->particlesPerSlice();
659 const int ss =
buffer->sliceStride();
660 const int slices =
buffer->sliceCount();
661 const float c_degToRad = float(
M_PI / 180.0f);
664 for (
int s = 0;
s < slices;
s++) {
666 for (
int p = 0;
p < pps &&
i < particleCount; ) {
667 if (
src->size > 0.0f)
669 dp->position =
src->position;
670 dp->rotation =
src->rotation * c_degToRad;
671 dp->color =
src->color;
673 dp->center =
src->center;
674 dp->size =
src->size;
683 bounds.
fatten(m_maxTriangleRadius);
685 buffer->setBounds(bounds);
686 m_dataChanged =
false;
690 const QQuick3DObject::ItemChangeData &
value)
693 if (change == ItemParentHasChanged &&
value.sceneManager)
700 if (m_particleCount) {
701 for (
int i = 0;
i < m_particleCount;
i++) {
703 m_triangleParticleData[
i].size = 0.0f;
705 m_triangleParticleData[
i].size = 1.0f;
706 m_triangleParticleData[
i].position = m_triangleParticleData[
i].center;
714 return m_centerData[particleIndex];
739 ret(1,0) = bd * e +
a *
f;
740 ret(1,1) =
a * e - bd *
f;
742 ret(2,0) =
b *
f - ad * e;
743 ret(2,1) = ad *
f +
b * e;
748void QQuick3DParticleModelBlendParticle::handleEndNodeChanged()
750 if (m_endNode && m_model) {
751 if (!m_model->
rotation().isIdentity()) {
760 m_endRotationMatrix =
QMatrix4x4(m_endNode->
rotation().toRotationMatrix().transposed());
762 m_endNodePosition = m_endNode->
position();
763 m_endNodeScale = m_endNode->
scale();
767 m_endNodeScale =
QVector3D(1.0f, 1.0f, 1.0f);
774 return m_endRotationMatrix.
map(
QVector3D(m_endNodeScale * m_centerData[idx])) + m_endNodePosition;
779 return m_endNodeRotation;
784 if (m_randomParticles.isEmpty()) {
787 m_randomParticles[
i] =
i;
794 qSwap(m_randomParticles[
i], m_randomParticles[ridx]);
797 return m_randomParticles[particleIndex];
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
static QString cleanPath(const QString &path)
Returns path with directory separators normalized (that is, platform-native separators converted to "...
QFILE_MAYBE_NODISCARD bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
QList< T > & fill(parameter_type t, qsizetype size=-1)
void resize(qsizetype size)
iterator insert(const Key &key, const T &value)
bool contains(const Key &key) const
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
QMatrix4x4 inverted(bool *invertible=nullptr) const
Returns the inverse of this matrix.
QPoint map(const QPoint &point) const
Maps point by multiplying this matrix by point.
void setToIdentity()
Sets this matrix to the identity.
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
void setParent(QObject *parent)
Makes the object a child of parent.
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
The QQmlComponent class encapsulates a QML component definition.
QQmlContext * creationContext() const
Returns the QQmlContext the component was created in.
virtual QObject * create(QQmlContext *context=nullptr)
Create an object instance from this component, within the specified context.
The QQmlContext class defines a context within a QML engine.
static QString urlToLocalFileOrQrc(const QString &)
If url is a local file returns a path suitable for passing to \l{QFile}.
static QQuick3DGeometry::Attribute::Semantic semanticFromName(const QByteArray &name)
static QQuick3DGeometry::Attribute::ComponentType toComponentType(QSSGMesh::Mesh::ComponentType componentType)
\qmltype Geometry \inherits Object3D \inqmlmodule QtQuick3D \instantiates QQuick3DGeometry
Attribute::Semantic int int stride
Returns the byte stride of the vertex buffer.
void setPrimitiveType(PrimitiveType type)
Sets the primitive type used for rendering to type.
int attributeCount() const
Returns the number of attributes defined for this geometry.
void setStride(int stride)
Sets the stride of the vertex buffer to stride, measured in bytes.
void addAttribute(Attribute::Semantic semantic, int offset, Attribute::ComponentType componentType)
Adds vertex attribute description.
void setVertexData(const QByteArray &data)
Sets the vertex buffer data.
int const QVector3D const QVector3D & boundsMax
Returns the maximum coordinate of the bounding volume.
int const QVector3D & boundsMin
Returns the minimum coordinate of the bounding volume.
PrimitiveType primitiveType() const
Returns the primitive type used when rendering.
Attribute attribute(int index) const
Returns attribute definition number index.
void setBounds(const QVector3D &min, const QVector3D &max)
Sets the bounding volume of the geometry to the cube defined by the points min and max.
QByteArray vertexData() const
Returns the vertex buffer data set by setVertexData.
QByteArray indexData() const
Returns the index buffer data.
QQuick3DGeometry * geometry
void setGeometry(QQuick3DGeometry *geometry)
void setSource(const QUrl &source)
QMatrix4x4 sceneTransform
QQuick3DNode * parentNode() const
static QSSGRenderGraphObject * updateSpatialNode(QQuick3DObject *o, QSSGRenderGraphObject *n)
static QQuick3DObjectPrivate * get(QQuick3DObject *item)
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
void setParentItem(QQuick3DObject *parentItem)
virtual void itemChange(ItemChange, const ItemChangeData &)
bool isComponentComplete() const
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
void doSetMaxAmount(int amount) override
QVector3D particleCenter(int particleIndex) const
void activationNodeChanged()
QSSGRenderGraphObject * updateSpatialNode(QSSGRenderGraphObject *node) override
ModelBlendEmitMode emitMode
void setEndTime(int endTime)
void itemChange(ItemChange, const ItemChangeData &) override
QQuick3DNode * activationNode
void setModelBlendMode(ModelBlendMode mode)
bool lastParticle() const
ModelBlendMode modelBlendMode
QVector3D particleEndPosition(int particleIndex) const
~QQuick3DParticleModelBlendParticle() override
QQuick3DParticleModelBlendParticle(QQuick3DNode *parent=nullptr)
\qmltype ModelBlendParticle3D \inherits Particle3D \inqmlmodule QtQuick3D.Particles3D
void modelBlendModeChanged()
int nextCurrentIndex(const QQuick3DParticleEmitter *emitter) override
void setActivationNode(QQuick3DNode *activationNode)
void setParticleData(int particleIndex, const QVector3D &position, const QVector3D &rotation, const QVector4D &color, float size, float age)
void setDelegate(QQmlComponent *setDelegate)
void setEndNode(QQuick3DNode *endNode)
int randomIndex(int particleIndex)
QVector3D particleEndRotation(int particleIndex) const
void setEmitMode(ModelBlendEmitMode emitMode)
void setFadeInEffect(QQuick3DParticle::FadeType fadeInEffect)
QList< QQuick3DParticleData > m_particleData
virtual int nextCurrentIndex(const QQuick3DParticleEmitter *emitter)
void setSystem(QQuick3DParticleSystem *system)
QQuick3DParticleSystem * system() const
void setFadeOutEffect(QQuick3DParticle::FadeType fadeOutEffect)
virtual void doSetMaxAmount(int amount)
\inmodule QtCore \reentrant
quint32 generate()
Generates a 32-bit random quantity and returns it.
constexpr QRect transposed() const noexcept
Class representing 3D range or axis aligned bounding box.
Q_ALWAYS_INLINE void fatten(double distance)
void include(const QVector3D &v)
expands the volume to include v
static QSSGBounds3 transform(const QMatrix3x3 &matrix, const QSSGBounds3 &bounds)
gets the transformed bounds of the passed AABB (resulting in a bigger AABB).
static QString primitivePath(const QString &primitive)
static Mesh loadMesh(QIODevice *device, quint32 id=0)
VertexBuffer vertexBuffer() const
IndexBuffer indexBuffer() const
QVector< Subset > subsets() const
DrawMode drawMode() const
\macro QT_RESTRICTED_CAST_FROM_ASCII
QString toString(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Returns a string representation of the URL.
The QVector3D class represents a vector or vertex in 3D space.
constexpr float y() const noexcept
Returns the y coordinate of this point.
constexpr float x() const noexcept
Returns the x coordinate of this point.
constexpr float z() const noexcept
Returns the z coordinate of this point.
The QVector4D class represents a vector or vertex in 4D space.
QVector3D Q_QUICK3DUTILS_EXPORT getScale(const QMatrix4x4 &m)
Combined button and popup list for selecting options.
constexpr const T & min(const T &a, const T &b)
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
constexpr float qDegreesToRadians(float degrees)
static QT_BEGIN_NAMESPACE QQuick3DGeometry::Attribute attributeBySemantic(const QQuick3DGeometry *geometry, QQuick3DGeometry::Attribute::Semantic semantic)
constexpr const T & qMax(const T &a, const T &b)
GLboolean GLboolean GLboolean b
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat z
GLint GLint GLint GLint GLint x
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLenum GLsizei count
GLenum GLuint GLintptr offset
GLsizei GLsizei GLchar * source
GLuint GLenum GLenum transform
GLenum GLenum GLenum GLenum GLenum scale
QQmlContext * qmlContext(const QObject *obj)
static float calcTriangleRadius(const QVector3D ¢er, const QVector3D &p0, const QVector3D &p1, const QVector3D &p2)
static QVector3D getPosition(const quint8 *srcVertices, quint32 idx, quint32 vertexStride, quint32 posOffset)
static void getVertexCenterData(QVector< QVector3D > ¢erData, float &maxTriangleRadius, const QByteArray &vertexBufferData, quint32 vertexStride, quint32 posOffset, quint32 primitiveCount)
static void copyToUnindexedVertices(QByteArray &unindexedVertexData, QVector< QVector3D > ¢erData, float &maxTriangleRadius, const QByteArray &vertexBufferData, quint32 vertexStride, quint32 posOffset, const QByteArray &indexBufferData, bool u16Indices, quint32 primitiveCount)
static QMatrix3x3 qt_fromEulerRotation(const QVector3D &eulerRotation)
static QSSGMesh::Mesh loadModelBlendParticleMesh(const QString &source)
#define Q_QUICK3D_PROFILE_ASSIGN_ID_SG(obj, bgnode)
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
QLatin1StringView QLatin1String
QT_BEGIN_NAMESPACE constexpr void qSwap(T &value1, T &value2) noexcept(std::is_nothrow_swappable_v< T >)
QSqlQueryModel * model
[16]
QRandomGenerator generator(sseq)
rect sceneTransform().map(QPointF(0
\inmodule QtCore \reentrant
ComponentType componentType
static const char * getPositionAttrName()
void resize(int particleCount, int particleSize=sizeof(QSSGParticleSimple))