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)));
306 float &maxTriangleRadius,
314 const quint8 *srcVertices =
reinterpret_cast<const quint8 *
>(vertexBufferData.
data());
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];
571 if (geometrySpatialNode)
576 if (!
model->particleBuffer) {
591 if (!
system() && qobject_cast<QQuick3DParticleSystem *>(parentItem()))
592 setSystem(qobject_cast<QQuick3DParticleSystem *>(parentItem()));
601 qWarning() <<
"ModelBlendParticle3D.maxAmount: Unable to set maximum amount, because it is set from the model.";
607 if (!m_perEmitterData.
contains(emitter)) {
608 m_perEmitterData.
insert(emitter, PerEmitterData());
609 auto &perEmitter = m_perEmitterData[emitter];
610 perEmitter.emitter = emitter;
611 perEmitter.emitterIndex = m_nextEmitterIndex++;
613 auto &perEmitter = m_perEmitterData[emitter];
615 if (m_triangleParticleData[
index].emitterIndex != perEmitter.emitterIndex) {
616 if (m_triangleParticleData[
index].emitterIndex >= 0)
617 perEmitterData(m_triangleParticleData[
index].emitterIndex).particleCount--;
618 perEmitter.particleCount++;
620 m_triangleParticleData[
index].emitterIndex = perEmitter.emitterIndex;
629 float size,
float age)
631 auto &
dst = m_triangleParticleData[particleIndex];
633 m_dataChanged =
true;
636QQuick3DParticleModelBlendParticle::PerEmitterData &QQuick3DParticleModelBlendParticle::perEmitterData(
int emitterIndex)
638 for (
auto &perEmitter : m_perEmitterData) {
639 if (perEmitter.emitterIndex == emitterIndex)
642 return n_noPerEmitterData;
647 const auto &particles = m_triangleParticleData;
649 if (!
buffer || !m_dataChanged)
652 const int particleCount = m_particleCount;
654 char *dest =
buffer->pointer();
655 const TriangleParticleData *
src = particles.data();
656 const int pps =
buffer->particlesPerSlice();
657 const int ss =
buffer->sliceStride();
658 const int slices =
buffer->sliceCount();
659 const float c_degToRad = float(
M_PI / 180.0f);
662 for (
int s = 0;
s < slices;
s++) {
664 for (
int p = 0;
p < pps &&
i < particleCount; ) {
665 if (
src->size > 0.0f)
681 bounds.
fatten(m_maxTriangleRadius);
683 buffer->setBounds(bounds);
684 m_dataChanged =
false;
688 const QQuick3DObject::ItemChangeData &
value)
691 if (change == ItemParentHasChanged &&
value.sceneManager)
698 if (m_particleCount) {
699 for (
int i = 0;
i < m_particleCount;
i++) {
701 m_triangleParticleData[
i].size = 0.0f;
703 m_triangleParticleData[
i].size = 1.0f;
704 m_triangleParticleData[
i].position = m_triangleParticleData[
i].center;
712 return m_centerData[particleIndex];
737 ret(1,0) = bd *
e +
a *
f;
738 ret(1,1) =
a *
e - bd *
f;
740 ret(2,0) =
b *
f - ad *
e;
741 ret(2,1) = ad *
f +
b *
e;
746void QQuick3DParticleModelBlendParticle::handleEndNodeChanged()
748 if (m_endNode && m_model) {
760 m_endNodePosition = m_endNode->
position();
761 m_endNodeScale = m_endNode->
scale();
765 m_endNodeScale =
QVector3D(1.0f, 1.0f, 1.0f);
772 return m_endRotationMatrix.
map(
QVector3D(m_endNodeScale * m_centerData[idx])) + m_endNodePosition;
777 return m_endNodeRotation;
782 if (m_randomParticles.isEmpty()) {
785 m_randomParticles[
i] =
i;
792 qSwap(m_randomParticles[
i], m_randomParticles[ridx]);
795 return m_randomParticles[particleIndex];
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first byte in the byte-array.
void resize(qsizetype size)
Sets the size of the byte array to size bytes.
static QString cleanPath(const QString &path)
Returns path with directory separators normalized (that is, platform-native separators converted to "...
bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
QGenericMatrix< M, N, T > transposed() const
Returns this matrix, transposed about its diagonal.
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 QFile.
bool isIdentity() const
Returns true if the x, y, and z components of this quaternion are set to 0.0, and the scalar componen...
QMatrix3x3 toRotationMatrix() const
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)
QSSGRenderGraphObject * spatialNode
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.
Combined button and popup list for selecting options.
constexpr const T & min(const T &a, const T &b)
QVector3D Q_QUICK3DUTILS_EXPORT getScale(const QMatrix4x4 &m)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
constexpr float qDegreesToRadians(float degrees)
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
QSqlQueryModel * model
[16]
QRandomGenerator generator(sseq)
rect sceneTransform().map(QPointF(0
\inmodule QtCore \reentrant
static const char * getPositionAttrName()
void resize(int particleCount, int particleSize=sizeof(QSSGParticleSimple))
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent