Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquick3dparticlecustomshape.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5
11#include <QtQml/qqmlcontext.h>
12#include <QtQml/qqmlfile.h>
13#include <QtCore/qfile.h>
14
16
17/*!
18 \qmltype ParticleCustomShape3D
19 \inherits ParticleAbstractShape3D
20 \inqmlmodule QtQuick3D.Particles3D
21 \brief Loads custom particle shapes for emitters and affectors.
22 \since 6.3
23
24 The ParticleCustomShape3D element can be used to load custom particle shapes.
25
26 For example, to emit particles from positions defined in heart.cbor:
27
28 \qml
29 ParticleEmitter3D {
30 shape: ParticleCustomShape3D {
31 source: "heart.cbor"
32 }
33 ...
34 }
35 \endqml
36
37 The format of CBOR shape files is following:
38 \badcode
39 [
40 "QQ3D_SHAPE", // string
41 version, // integer
42 [
43 posX, // float
44 posY, // float
45 posZ, // float
46 posX, // float
47 ...
48 ]
49 ]
50 \endcode
51
52 To assist in generating these shape files you can use the shapegen tool.
53*/
54
55QQuick3DParticleCustomShape::QQuick3DParticleCustomShape(QObject *parent)
56 : QQuick3DParticleAbstractShape(parent)
57{
58}
59
60/*!
61 \qmlproperty url ParticleCustomShape3D::source
62
63 This property holds the location of the shape file.
64
65 \warning \a source is expected to contain trusted content. Application
66 developers are advised to carefully consider the potential implications
67 before passing in user-provided source files that are not part of the
68 application.
69*/
70
71QUrl QQuick3DParticleCustomShape::source() const
72{
73 return m_source;
74}
75
76/*!
77 \qmlproperty bool ParticleCustomShape3D::randomizeData
78
79 This property holds whether the particles are used in random order instead
80 of in the order they are specified in the source.
81
82 The default value is \c false.
83*/
84bool QQuick3DParticleCustomShape::randomizeData() const
85{
86 return m_random;
87}
88
89void QQuick3DParticleCustomShape::setSource(const QUrl &source)
90{
91 if (m_source == source)
92 return;
93
94 m_source = source;
95
96 loadFromSource();
97 Q_EMIT sourceChanged();
98}
99
100void QQuick3DParticleCustomShape::setRandomizeData(bool random)
101{
102 if (m_random == random)
103 return;
104
105 m_random = random;
106 if (m_random)
107 m_randomizeDirty = true;
108 Q_EMIT randomizeDataChanged();
109}
110
111void QQuick3DParticleCustomShape::loadFromSource()
112{
113 m_positions.clear();
114
115 // Get path to file
116 const QQmlContext *context = qmlContext(this);
117 QString dataFilePath = QQmlFile::urlToLocalFileOrQrc(context ? context->resolvedUrl(m_source) : m_source);
118
119 QFile dataFile(dataFilePath);
120 if (!dataFile.open(QIODevice::ReadOnly)) {
121 // Invalid file
122 qWarning() << "Unable to open file:" << dataFilePath;
123 return;
124 }
125 QCborStreamReader reader(&dataFile);
126
127 // Check that file is proper CBOR and get the version
128 int version = QQuick3DParticleShapeDataUtils::readShapeHeader(reader);
129
130 if (version == -1) {
131 // Invalid file
132 qWarning() << "Invalid shape data version:" << version;
133 return;
134 }
135
136 // Start positions array
137 reader.enterContainer();
138
139 m_center = QVector3D();
140 while (reader.lastError() == QCborError::NoError && reader.hasNext()) {
141 QVector3D pos = QQuick3DParticleShapeDataUtils::readValue(reader, QMetaType::QVector3D).value<QVector3D>();
142 m_positions.append(pos);
143 m_center += pos;
144 }
145 if (!m_positions.isEmpty())
146 m_center *= 1.0f / float(m_positions.size());
147
148 // Leave positions array
149 reader.leaveContainer();
150
151 // Leave root array
152 reader.leaveContainer();
153
154 if (m_random)
155 m_randomizeDirty = true;
156}
157
158void QQuick3DParticleCustomShape::doRandomizeData()
159{
160 if (!m_system || m_positions.isEmpty())
161 return;
162
163 auto rand = m_system->rand();
164 int seed = rand->get(0, QPRand::Shape1) * float(INT_MAX);
165 std::shuffle(m_positions.begin(), m_positions.end(), std::default_random_engine(seed));
166
167 m_randomizeDirty = false;
168}
169
170QVector3D QQuick3DParticleCustomShape::getPosition(int particleIndex)
171{
172 auto *parent = parentNode();
173 if (!parent || m_positions.isEmpty())
174 return QVector3D();
175
176 if (m_randomizeDirty)
177 doRandomizeData();
178
179 int index = particleIndex % m_positions.size();
180 return m_positions.at(index) * parent->scale();
181}
182
183QVector3D QQuick3DParticleCustomShape::getSurfaceNormal(int particleIndex)
184{
185 auto *parent = parentNode();
186 if (!parent || m_positions.isEmpty())
187 return QVector3D();
188
189 if (m_randomizeDirty)
190 doRandomizeData();
191
192 int index = particleIndex % m_positions.size();
193 return (m_positions.at(index) - m_center).normalized();
194}
195
196QT_END_NAMESPACE
Combined button and popup list for selecting options.