Qt 6.x
The Qt SDK
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
qquickimageparticle.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <QtQuick/private/qsgcontext_p.h>
5#include <private/qsgadaptationlayer_p.h>
6#include <private/qquickitem_p.h>
7#include <QtQuick/qsgnode.h>
8#include <QtQuick/qsgtexture.h>
9#include <QFile>
10#include <QRandomGenerator>
13#include <private/qquicksprite_p.h>
14#include <private/qquickspriteengine_p.h>
15#include <QSGRendererInterface>
16#include <QtQuick/private/qsgplaintexture_p.h>
17#include <private/qqmlglobal_p.h>
18#include <QtQml/qqmlinfo.h>
19#include <QtCore/QtMath>
20#include <rhi/qrhi.h>
21
22#include <cmath>
23
25
26// Must match the shader code
27#define UNIFORM_ARRAY_SIZE 64
28
30{
31 public:
34 {}
35
37 delete texture;
38 delete colorTable;
39 }
40
45
50};
51
53{
54public:
56 {
57 setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_tabled.vert.qsb"));
58 setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_tabled.frag.qsb"));
59 }
60
61 bool updateUniformData(RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override
62 {
63 QByteArray *buf = renderState.uniformData();
64 Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4));
65
66 if (renderState.isMatrixDirty()) {
67 const QMatrix4x4 m = renderState.combinedMatrix();
68 memcpy(buf->data(), m.constData(), 64);
69 }
70
71 if (renderState.isOpacityDirty()) {
72 const float opacity = renderState.opacity();
73 memcpy(buf->data() + 64, &opacity, 4);
74 }
75
76 ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
77
78 float entry = float(state->entry);
79 memcpy(buf->data() + 68, &entry, 4);
80
81 float timestamp = float(state->timestamp);
82 memcpy(buf->data() + 72, &timestamp, 4);
83
84 float *p = reinterpret_cast<float *>(buf->data() + 80);
85 for (int i = 0; i < UNIFORM_ARRAY_SIZE; ++i) {
86 *p = state->sizeTable[i];
87 p += 4;
88 }
89 p = reinterpret_cast<float *>(buf->data() + 80 + (UNIFORM_ARRAY_SIZE * 4 * 4));
90 for (int i = 0; i < UNIFORM_ARRAY_SIZE; ++i) {
91 *p = state->opacityTable[i];
92 p += 4;
93 }
94
95 return true;
96 }
97
98 void updateSampledImage(RenderState &renderState, int binding, QSGTexture **texture,
99 QSGMaterial *newMaterial, QSGMaterial *) override
100 {
101 ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
102 if (binding == 2) {
103 state->colorTable->commitTextureOperations(renderState.rhi(), renderState.resourceUpdateBatch());
104 *texture = state->colorTable;
105 } else if (binding == 1) {
106 state->texture->commitTextureOperations(renderState.rhi(), renderState.resourceUpdateBatch());
107 *texture = state->texture;
108 }
109 }
110};
111
113{
114public:
116 Q_UNUSED(renderMode);
117 return new TabledMaterialRhiShader;
118 }
119 QSGMaterialType *type() const override { return &m_type; }
120
121 ImageMaterialData *state() override { return &m_state; }
122
123private:
124 static QSGMaterialType m_type;
125 ImageMaterialData m_state;
126};
127
128QSGMaterialType TabledMaterial::m_type;
129
131{
132public:
134 {
135 setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_deformed.vert.qsb"));
136 setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_deformed.frag.qsb"));
137 }
138
139 bool updateUniformData(RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override
140 {
141 QByteArray *buf = renderState.uniformData();
142 Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4));
143
144 if (renderState.isMatrixDirty()) {
145 const QMatrix4x4 m = renderState.combinedMatrix();
146 memcpy(buf->data(), m.constData(), 64);
147 }
148
149 if (renderState.isOpacityDirty()) {
150 const float opacity = renderState.opacity();
151 memcpy(buf->data() + 64, &opacity, 4);
152 }
153
154 ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
155
156 float entry = float(state->entry);
157 memcpy(buf->data() + 68, &entry, 4);
158
159 float timestamp = float(state->timestamp);
160 memcpy(buf->data() + 72, &timestamp, 4);
161
162 return true;
163 }
164
165 void updateSampledImage(RenderState &renderState, int binding, QSGTexture **texture,
166 QSGMaterial *newMaterial, QSGMaterial *) override
167 {
168 ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
169 if (binding == 1) {
170 state->texture->commitTextureOperations(renderState.rhi(), renderState.resourceUpdateBatch());
171 *texture = state->texture;
172 }
173 }
174};
175
177{
178public:
180 Q_UNUSED(renderMode);
182 }
183 QSGMaterialType *type() const override { return &m_type; }
184
185 ImageMaterialData *state() override { return &m_state; }
186
187private:
188 static QSGMaterialType m_type;
189 ImageMaterialData m_state;
190};
191
192QSGMaterialType DeformableMaterial::m_type;
193
195{
196public:
198 {
199 setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_sprite.vert.qsb"));
200 setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_sprite.frag.qsb"));
201 }
202
203 bool updateUniformData(RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override
204 {
205 QByteArray *buf = renderState.uniformData();
206 Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4));
207
208 if (renderState.isMatrixDirty()) {
209 const QMatrix4x4 m = renderState.combinedMatrix();
210 memcpy(buf->data(), m.constData(), 64);
211 }
212
213 if (renderState.isOpacityDirty()) {
214 const float opacity = renderState.opacity();
215 memcpy(buf->data() + 64, &opacity, 4);
216 }
217
218 ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
219
220 float entry = float(state->entry);
221 memcpy(buf->data() + 68, &entry, 4);
222
223 float timestamp = float(state->timestamp);
224 memcpy(buf->data() + 72, &timestamp, 4);
225
226 float *p = reinterpret_cast<float *>(buf->data() + 80);
227 for (int i = 0; i < UNIFORM_ARRAY_SIZE; ++i) {
228 *p = state->sizeTable[i];
229 p += 4;
230 }
231 p = reinterpret_cast<float *>(buf->data() + 80 + (UNIFORM_ARRAY_SIZE * 4 * 4));
232 for (int i = 0; i < UNIFORM_ARRAY_SIZE; ++i) {
233 *p = state->opacityTable[i];
234 p += 4;
235 }
236
237 return true;
238 }
239
240 void updateSampledImage(RenderState &renderState, int binding, QSGTexture **texture,
241 QSGMaterial *newMaterial, QSGMaterial *) override
242 {
243 ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
244 if (binding == 2) {
245 state->colorTable->commitTextureOperations(renderState.rhi(), renderState.resourceUpdateBatch());
246 *texture = state->colorTable;
247 } else if (binding == 1) {
248 state->texture->commitTextureOperations(renderState.rhi(), renderState.resourceUpdateBatch());
249 *texture = state->texture;
250 }
251 }
252};
253
255{
256public:
258 Q_UNUSED(renderMode);
260 }
261 QSGMaterialType *type() const override { return &m_type; }
262
263 ImageMaterialData *state() override { return &m_state; }
264
265private:
266 static QSGMaterialType m_type;
267 ImageMaterialData m_state;
268};
269
270QSGMaterialType SpriteMaterial::m_type;
271
273{
274public:
276 {
277 setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_coloredpoint.vert.qsb"));
278 setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_coloredpoint.frag.qsb"));
279 }
280
281 bool updateUniformData(RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override
282 {
283 QByteArray *buf = renderState.uniformData();
284 Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4));
285
286 if (renderState.isMatrixDirty()) {
287 const QMatrix4x4 m = renderState.combinedMatrix();
288 memcpy(buf->data(), m.constData(), 64);
289 }
290
291 if (renderState.isOpacityDirty()) {
292 const float opacity = renderState.opacity();
293 memcpy(buf->data() + 64, &opacity, 4);
294 }
295
296 ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
297
298 float entry = float(state->entry);
299 memcpy(buf->data() + 68, &entry, 4);
300
301 float timestamp = float(state->timestamp);
302 memcpy(buf->data() + 72, &timestamp, 4);
303
304 float dpr = float(state->dpr);
305 memcpy(buf->data() + 76, &dpr, 4);
306
307 return true;
308 }
309
310 void updateSampledImage(RenderState &renderState, int binding, QSGTexture **texture,
311 QSGMaterial *newMaterial, QSGMaterial *) override
312 {
313 ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
314 if (binding == 1) {
315 state->texture->commitTextureOperations(renderState.rhi(), renderState.resourceUpdateBatch());
316 *texture = state->texture;
317 }
318 }
319};
320
322{
323public:
325 Q_UNUSED(renderMode);
327 }
328 QSGMaterialType *type() const override { return &m_type; }
329
330 ImageMaterialData *state() override { return &m_state; }
331
332private:
333 static QSGMaterialType m_type;
334 ImageMaterialData m_state;
335};
336
337QSGMaterialType ColoredPointMaterial::m_type;
338
340{
341public:
343 {
344 setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_colored.vert.qsb"));
345 setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_colored.frag.qsb"));
346 }
347};
348
350{
351public:
353 Q_UNUSED(renderMode);
354 return new ColoredMaterialRhiShader;
355 }
356 QSGMaterialType *type() const override { return &m_type; }
357
358 ImageMaterialData *state() override { return &m_state; }
359
360private:
361 static QSGMaterialType m_type;
362 ImageMaterialData m_state;
363};
364
365QSGMaterialType ColoredMaterial::m_type;
366
368{
369public:
371 {
372 setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_simplepoint.vert.qsb"));
373 setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_simplepoint.frag.qsb"));
374 }
375
376 bool updateUniformData(RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override
377 {
378 QByteArray *buf = renderState.uniformData();
379 Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4));
380
381 if (renderState.isMatrixDirty()) {
382 const QMatrix4x4 m = renderState.combinedMatrix();
383 memcpy(buf->data(), m.constData(), 64);
384 }
385
386 if (renderState.isOpacityDirty()) {
387 const float opacity = renderState.opacity();
388 memcpy(buf->data() + 64, &opacity, 4);
389 }
390
391 ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
392
393 float entry = float(state->entry);
394 memcpy(buf->data() + 68, &entry, 4);
395
396 float timestamp = float(state->timestamp);
397 memcpy(buf->data() + 72, &timestamp, 4);
398
399 float dpr = float(state->dpr);
400 memcpy(buf->data() + 76, &dpr, 4);
401
402 return true;
403 }
404
405 void updateSampledImage(RenderState &renderState, int binding, QSGTexture **texture,
406 QSGMaterial *newMaterial, QSGMaterial *) override
407 {
408 ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
409 if (binding == 1) {
410 state->texture->commitTextureOperations(renderState.rhi(), renderState.resourceUpdateBatch());
411 *texture = state->texture;
412 }
413 }
414};
415
417{
418public:
420 Q_UNUSED(renderMode);
422 }
423 QSGMaterialType *type() const override { return &m_type; }
424
425 ImageMaterialData *state() override { return &m_state; }
426
427private:
428 static QSGMaterialType m_type;
429 ImageMaterialData m_state;
430};
431
432QSGMaterialType SimplePointMaterial::m_type;
433
435{
436 if (img.isNull()){
437 for (int i=0; i<size; i++)
438 array[i] = 1.0;
439 return;
440 }
442 for (int i=0; i<size; i++)
443 array[i] = qAlpha(scaled.pixel(i,0))/255.0;
444}
445
679 , m_color_variation(0.0)
680 , m_outgoingNode(nullptr)
681 , m_material(nullptr)
682 , m_alphaVariation(0.0)
683 , m_alpha(1.0)
684 , m_redVariation(0.0)
685 , m_greenVariation(0.0)
686 , m_blueVariation(0.0)
687 , m_rotation(0)
688 , m_rotationVariation(0)
689 , m_rotationVelocity(0)
690 , m_rotationVelocityVariation(0)
691 , m_autoRotation(false)
692 , m_xVector(nullptr)
693 , m_yVector(nullptr)
694 , m_spriteEngine(nullptr)
695 , m_spritesInterpolate(true)
696 , m_explicitColor(false)
697 , m_explicitRotation(false)
698 , m_explicitDeformation(false)
699 , m_explicitAnimation(false)
700 , m_bypassOptimizations(false)
701 , perfLevel(Unknown)
702 , m_targetPerfLevel(Unknown)
703 , m_debugMode(false)
704 , m_entryEffect(Fade)
705 , m_startedImageLoading(0)
706 , m_rhi(nullptr)
707 , m_apiChecked(false)
708 , m_dpr(1.0)
709 , m_previousActive(false)
710{
712}
713
715{
716 clearShadows();
717}
718
720{
721 return QQmlListProperty<QQuickSprite>(this, &m_sprites,
724}
725
727{
728 m_nodes.clear();
729 m_material = nullptr;
730 delete m_outgoingNode;
731 m_outgoingNode = nullptr;
732 m_apiChecked = false;
733}
734
736{
737 if (image.isEmpty()){
738 if (m_image) {
739 m_image.reset();
741 }
742 return;
743 }
744
745 if (!m_image)
746 m_image.reset(new ImageData);
747 if (image == m_image->source)
748 return;
749 m_image->source = image;
751 reset();
752}
753
754
756{
757 if (table.isEmpty()){
758 if (m_colorTable) {
759 m_colorTable.reset();
761 }
762 return;
763 }
764
765 if (!m_colorTable)
766 m_colorTable.reset(new ImageData);
767 if (table == m_colorTable->source)
768 return;
769 m_colorTable->source = table;
771 reset();
772}
773
775{
776 if (table.isEmpty()){
777 if (m_sizeTable) {
778 m_sizeTable.reset();
780 }
781 return;
782 }
783
784 if (!m_sizeTable)
785 m_sizeTable.reset(new ImageData);
786 if (table == m_sizeTable->source)
787 return;
788 m_sizeTable->source = table;
790 reset();
791}
792
794{
795 if (table.isEmpty()){
796 if (m_opacityTable) {
797 m_opacityTable.reset();
799 }
800 return;
801 }
802
803 if (!m_opacityTable)
804 m_opacityTable.reset(new ImageData);
805 if (table == m_opacityTable->source)
806 return;
807 m_opacityTable->source = table;
809 reset();
810}
811
813{
814 if (color == m_color)
815 return;
816 m_color = color;
818 m_explicitColor = true;
819 checkPerfLevel(ColoredPoint);
820}
821
823{
824 if (var == m_color_variation)
825 return;
826 m_color_variation = var;
828 m_explicitColor = true;
829 checkPerfLevel(ColoredPoint);
830}
831
833{
834 if (m_alphaVariation != arg) {
835 m_alphaVariation = arg;
837 }
838 m_explicitColor = true;
839 checkPerfLevel(ColoredPoint);
840}
841
843{
844 if (m_alpha != arg) {
845 m_alpha = arg;
847 }
848 m_explicitColor = true;
849 checkPerfLevel(ColoredPoint);
850}
851
853{
854 if (m_redVariation != arg) {
855 m_redVariation = arg;
857 }
858 m_explicitColor = true;
859 checkPerfLevel(ColoredPoint);
860}
861
863{
864 if (m_greenVariation != arg) {
865 m_greenVariation = arg;
867 }
868 m_explicitColor = true;
869 checkPerfLevel(ColoredPoint);
870}
871
873{
874 if (m_blueVariation != arg) {
875 m_blueVariation = arg;
877 }
878 m_explicitColor = true;
879 checkPerfLevel(ColoredPoint);
880}
881
883{
884 if (m_rotation != arg) {
885 m_rotation = arg;
887 }
888 m_explicitRotation = true;
889 checkPerfLevel(Deformable);
890}
891
893{
894 if (m_rotationVariation != arg) {
895 m_rotationVariation = arg;
897 }
898 m_explicitRotation = true;
899 checkPerfLevel(Deformable);
900}
901
903{
904 if (m_rotationVelocity != arg) {
905 m_rotationVelocity = arg;
907 }
908 m_explicitRotation = true;
909 checkPerfLevel(Deformable);
910}
911
913{
914 if (m_rotationVelocityVariation != arg) {
915 m_rotationVelocityVariation = arg;
917 }
918 m_explicitRotation = true;
919 checkPerfLevel(Deformable);
920}
921
923{
924 if (m_autoRotation != arg) {
925 m_autoRotation = arg;
927 }
928 m_explicitRotation = true;
929 checkPerfLevel(Deformable);
930}
931
933{
934 if (m_xVector != arg) {
935 m_xVector = arg;
937 }
938 m_explicitDeformation = true;
939 checkPerfLevel(Deformable);
940}
941
943{
944 if (m_yVector != arg) {
945 m_yVector = arg;
947 }
948 m_explicitDeformation = true;
949 checkPerfLevel(Deformable);
950}
951
953{
954 if (m_spritesInterpolate != arg) {
955 m_spritesInterpolate = arg;
957 }
958}
959
961{
962 if (m_bypassOptimizations != arg) {
963 m_bypassOptimizations = arg;
965 }
966 // Applies regardless of perfLevel
967 reset();
968}
969
971{
972 if (m_entryEffect != arg) {
973 m_entryEffect = arg;
974 if (m_material)
975 getState(m_material)->entry = (qreal) m_entryEffect;
977 }
978}
979
981{
982 m_explicitColor = false;
983 for (auto groupId : groupIds()) {
984 for (QQuickParticleData* d : std::as_const(m_system->groupData[groupId]->data)) {
985 if (d->colorOwner == this) {
986 d->colorOwner = nullptr;
987 }
988 }
989 }
990 m_color = QColor();
991 m_color_variation = 0.0f;
992 m_redVariation = 0.0f;
993 m_blueVariation = 0.0f;
994 m_greenVariation = 0.0f;
995 m_alpha = 1.0f;
996 m_alphaVariation = 0.0f;
997}
998
1000{
1001 m_explicitRotation = false;
1002 for (auto groupId : groupIds()) {
1003 for (QQuickParticleData* d : std::as_const(m_system->groupData[groupId]->data)) {
1004 if (d->rotationOwner == this) {
1005 d->rotationOwner = nullptr;
1006 }
1007 }
1008 }
1009 m_rotation = 0;
1010 m_rotationVariation = 0;
1011 m_rotationVelocity = 0;
1012 m_rotationVelocityVariation = 0;
1013 m_autoRotation = false;
1014}
1015
1017{
1018 m_explicitDeformation = false;
1019 for (auto groupId : groupIds()) {
1020 for (QQuickParticleData* d : std::as_const(m_system->groupData[groupId]->data)) {
1021 if (d->deformationOwner == this) {
1022 d->deformationOwner = nullptr;
1023 }
1024 }
1025 }
1026 if (m_xVector)
1027 delete m_xVector;
1028 if (m_yVector)
1029 delete m_yVector;
1030 m_xVector = nullptr;
1031 m_yVector = nullptr;
1032}
1033
1035{
1037 m_pleaseReset = true;
1038 update();
1039}
1040
1041
1042void QQuickImageParticle::invalidateSceneGraph()
1043{
1044 reset();
1045}
1046
1047void QQuickImageParticle::createEngine()
1048{
1049 if (m_spriteEngine)
1050 delete m_spriteEngine;
1051 if (m_sprites.size()) {
1052 m_spriteEngine = new QQuickSpriteEngine(m_sprites, this);
1053 connect(m_spriteEngine, SIGNAL(stateChanged(int)),
1054 this, SLOT(spriteAdvance(int)), Qt::DirectConnection);
1055 m_explicitAnimation = true;
1056 } else {
1057 m_spriteEngine = nullptr;
1058 m_explicitAnimation = false;
1059 }
1060 reset();
1061}
1062
1067};
1068
1070{
1071 3, // Attribute Count
1072 ( 2 + 4 + 4 ) * sizeof(float),
1074};
1075
1081};
1082
1084{
1085 4, // Attribute Count
1086 ( 2 + 4 + 4 ) * sizeof(float) + 4 * sizeof(uchar),
1088};
1089
1096};
1097
1099{
1100 5, // Attribute Count
1101 ( 2 + 4 + 4 ) * sizeof(float) + (4 + 4) * sizeof(uchar),
1103};
1104
1106 QSGGeometry::Attribute::create(0, 4, QSGGeometry::FloatType), // Position & Rotation
1110 QSGGeometry::Attribute::create(4, 4, QSGGeometry::FloatType), // DeformationVectors
1111 QSGGeometry::Attribute::create(5, 4, QSGGeometry::UnsignedByteType), // TexCoord & autoRotate
1112};
1113
1115{
1116 6, // Attribute Count
1117 (4 + 4 + 4 + 4) * sizeof(float) + (4 + 4) * sizeof(uchar),
1119};
1120
1122 QSGGeometry::Attribute::create(0, 4, QSGGeometry::FloatType), // Position & Rotation
1126 QSGGeometry::Attribute::create(4, 4, QSGGeometry::FloatType), // DeformationVectors
1127 QSGGeometry::Attribute::create(5, 4, QSGGeometry::UnsignedByteType), // TexCoord & autoRotate
1130};
1131
1133{
1134 8, // Attribute Count
1135 (4 + 4 + 4 + 4 + 3 + 3) * sizeof(float) + (4 + 4) * sizeof(uchar),
1137};
1138
1139void QQuickImageParticle::clearShadows()
1140{
1141 foreach (const QVector<QQuickParticleData*> data, m_shadowData)
1143 m_shadowData.clear();
1144}
1145
1146//Only call if you need to, may initialize the whole array first time
1147QQuickParticleData* QQuickImageParticle::getShadowDatum(QQuickParticleData* datum)
1148{
1149 //Will return datum if the datum is a sentinel or uninitialized, to centralize that one check
1150 if (datum->systemIndex == -1)
1151 return datum;
1152 if (!m_shadowData.contains(datum->groupId)) {
1155 const int gdSize = gd->size();
1156 data.reserve(gdSize);
1157 for (int i = 0; i < gdSize; i++) {
1159 *datum = *(gd->data[i]);
1160 data << datum;
1161 }
1162 m_shadowData.insert(datum->groupId, data);
1163 }
1164 //### If dynamic resize is added, remember to potentially resize the shadow data on out-of-bounds access request
1165
1166 return m_shadowData[datum->groupId][datum->index];
1167}
1168
1169void QQuickImageParticle::checkPerfLevel(PerformanceLevel level)
1170{
1171 if (m_targetPerfLevel < level) {
1172 m_targetPerfLevel = level;
1173 reset();
1174 }
1175}
1176
1177bool QQuickImageParticle::loadingSomething()
1178{
1179 return (m_image && m_image->pix.isLoading())
1180 || (m_colorTable && m_colorTable->pix.isLoading())
1181 || (m_sizeTable && m_sizeTable->pix.isLoading())
1182 || (m_opacityTable && m_opacityTable->pix.isLoading())
1183 || (m_spriteEngine && m_spriteEngine->isLoading());
1184}
1185
1186void QQuickImageParticle::mainThreadFetchImageData()
1187{
1188 const QQmlContext *context = nullptr;
1189 QQmlEngine *engine = nullptr;
1190 const auto loadPix = [&](ImageData *image) {
1191 if (!engine) {
1192 context = qmlContext(this);
1193 engine = context->engine();
1194 }
1195 image->pix.load(engine, context->resolvedUrl(image->source));
1196 };
1197
1198
1199 if (m_image) {//ImageData created on setSource
1200 m_image->pix.clear(this);
1201 loadPix(m_image.get());
1202 }
1203
1204 if (m_spriteEngine)
1205 m_spriteEngine->startAssemblingImage();
1206
1207 if (m_colorTable)
1208 loadPix(m_colorTable.get());
1209
1210 if (m_sizeTable)
1211 loadPix(m_sizeTable.get());
1212
1213 if (m_opacityTable)
1214 loadPix(m_opacityTable.get());
1215
1216 m_startedImageLoading = 2;
1217}
1218
1220{
1221 // Starts async parts, like loading images, on gui thread
1222 // Not on individual properties, because we delay until system is running
1223 if (*passThrough || loadingSomething())
1224 return;
1225
1226 if (m_startedImageLoading == 0) {
1227 m_startedImageLoading = 1;
1228 //stage 1 is in gui thread
1229 QQuickImageParticle::staticMetaObject.invokeMethod(this, "mainThreadFetchImageData", Qt::QueuedConnection);
1230 } else if (m_startedImageLoading == 2) {
1231 finishBuildParticleNodes(passThrough); //rest happens in render thread
1232 }
1233
1234 //No mutex, because it's slow and a compare that fails due to a race condition means just a dropped frame
1235}
1236
1237void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node)
1238{
1239 if (!m_rhi)
1240 return;
1241
1242 if (m_count * 4 > 0xffff) {
1243 // Index data is ushort.
1244 qmlInfo(this) << "ImageParticle: Too many particles - maximum 16383 per ImageParticle";
1245 return;
1246 }
1247
1248 if (m_count <= 0)
1249 return;
1250
1251 m_debugMode = m_system->m_debugMode;
1252
1253 if (m_sprites.size() || m_bypassOptimizations) {
1254 perfLevel = Sprites;
1255 } else if (m_colorTable || m_sizeTable || m_opacityTable) {
1256 perfLevel = Tabled;
1257 } else if (m_autoRotation || m_rotation || m_rotationVariation
1258 || m_rotationVelocity || m_rotationVelocityVariation
1259 || m_xVector || m_yVector) {
1260 perfLevel = Deformable;
1261 } else if (m_alphaVariation || m_alpha != 1.0 || m_color.isValid() || m_color_variation
1262 || m_redVariation || m_blueVariation || m_greenVariation) {
1263 perfLevel = ColoredPoint;
1264 } else {
1265 perfLevel = SimplePoint;
1266 }
1267
1268 for (auto groupId : groupIds()) {
1269 //For sharing higher levels, need to have highest used so it renders
1270 for (QQuickParticlePainter* p : std::as_const(m_system->groupData[groupId]->painters)) {
1271 QQuickImageParticle* other = qobject_cast<QQuickImageParticle*>(p);
1272 if (other){
1273 if (other->perfLevel > perfLevel) {
1274 if (other->perfLevel >= Tabled){//Deformable is the highest level needed for this, anything higher isn't shared (or requires your own sprite)
1275 if (perfLevel < Deformable)
1276 perfLevel = Deformable;
1277 } else {
1278 perfLevel = other->perfLevel;
1279 }
1280 } else if (other->perfLevel < perfLevel) {
1281 other->reset();
1282 }
1283 }
1284 }
1285 }
1286
1287 // Points with a size other than 1 are an optional feature with QRhi
1288 // because some of the underlying APIs have no support for this.
1289 // Therefore, avoid the point sprite path with APIs like Direct3D.
1290 if (perfLevel < Colored && !m_rhi->isFeatureSupported(QRhi::VertexShaderPointSize))
1291 perfLevel = Colored;
1292
1293 if (perfLevel >= ColoredPoint && !m_color.isValid())
1294 m_color = QColor(Qt::white);//Hidden default, but different from unset
1295
1296 m_targetPerfLevel = perfLevel;
1297
1298 clearShadows();
1299 if (m_material)
1300 m_material = nullptr;
1301
1302 //Setup material
1306 QImage image;
1307 bool imageLoaded = false;
1308 switch (perfLevel) {//Fallthrough intended
1309 case Sprites:
1310 {
1311 if (!m_spriteEngine) {
1312 qWarning() << "ImageParticle: No sprite engine...";
1313 //Sprite performance mode with static image is supported, but not advised
1314 //Note that in this case it always uses shadow data
1315 } else {
1316 image = m_spriteEngine->assembledImage();
1317 if (image.isNull())//Warning is printed in engine
1318 return;
1319 imageLoaded = true;
1320 }
1321 m_material = new SpriteMaterial;
1322 ImageMaterialData *state = getState(m_material);
1323 if (imageLoaded)
1325 state->animSheetSize = QSizeF(image.size() / image.devicePixelRatio());
1326 if (m_spriteEngine)
1327 m_spriteEngine->setCount(m_count);
1328 }
1329 Q_FALLTHROUGH();
1330 case Tabled:
1331 {
1332 if (!m_material)
1333 m_material = new TabledMaterial;
1334
1335 if (m_colorTable) {
1336 if (m_colorTable->pix.isReady())
1337 colortable = m_colorTable->pix.image();
1338 else
1339 qmlWarning(this) << "Error loading color table: " << m_colorTable->pix.error();
1340 }
1341
1342 if (m_sizeTable) {
1343 if (m_sizeTable->pix.isReady())
1344 sizetable = m_sizeTable->pix.image();
1345 else
1346 qmlWarning(this) << "Error loading size table: " << m_sizeTable->pix.error();
1347 }
1348
1349 if (m_opacityTable) {
1350 if (m_opacityTable->pix.isReady())
1351 opacitytable = m_opacityTable->pix.image();
1352 else
1353 qmlWarning(this) << "Error loading opacity table: " << m_opacityTable->pix.error();
1354 }
1355
1356 if (colortable.isNull()){//###Goes through image just for this
1358 colortable.fill(Qt::white);
1359 }
1360 ImageMaterialData *state = getState(m_material);
1364 }
1365 Q_FALLTHROUGH();
1366 case Deformable:
1367 {
1368 if (!m_material)
1369 m_material = new DeformableMaterial;
1370 }
1371 Q_FALLTHROUGH();
1372 case Colored:
1373 {
1374 if (!m_material)
1375 m_material = new ColoredMaterial;
1376 }
1377 Q_FALLTHROUGH();
1378 case ColoredPoint:
1379 {
1380 if (!m_material)
1381 m_material = new ColoredPointMaterial;
1382 }
1383 Q_FALLTHROUGH();
1384 default://Also Simple
1385 {
1386 if (!m_material)
1387 m_material = new SimplePointMaterial;
1388 ImageMaterialData *state = getState(m_material);
1389 if (!imageLoaded) {
1390 if (!m_image || !m_image->pix.isReady()) {
1391 if (m_image)
1392 qmlWarning(this) << m_image->pix.error();
1393 delete m_material;
1394 return;
1395 }
1396 //state->texture //TODO: Shouldn't this be better? But not crash?
1397 // = QQuickItemPrivate::get(this)->sceneGraphContext()->textureForFactory(m_imagePix.textureFactory());
1398 state->texture = QSGPlainTexture::fromImage(m_image->pix.image());
1399 }
1400 state->texture->setFiltering(QSGTexture::Linear);
1401 state->entry = (qreal) m_entryEffect;
1402 state->dpr = m_dpr;
1403
1405 }
1406 }
1407
1408 m_nodes.clear();
1409 for (auto groupId : groupIds()) {
1410 int count = m_system->groupData[groupId]->size();
1411 QSGGeometryNode* node = new QSGGeometryNode();
1412 node->setMaterial(m_material);
1414
1415 m_nodes.insert(groupId, node);
1416 m_idxStarts.insert(groupId, m_lastIdxStart);
1417 m_startsIdx.append(qMakePair(m_lastIdxStart, groupId));
1418 m_lastIdxStart += count;
1419
1420 //Create Particle Geometry
1421 int vCount = count * 4;
1422 int iCount = count * 6;
1423
1424 QSGGeometry *g;
1425 if (perfLevel == Sprites)
1426 g = new QSGGeometry(SpriteParticle_AttributeSet, vCount, iCount);
1427 else if (perfLevel == Tabled)
1428 g = new QSGGeometry(DeformableParticle_AttributeSet, vCount, iCount);
1429 else if (perfLevel == Deformable)
1430 g = new QSGGeometry(DeformableParticle_AttributeSet, vCount, iCount);
1431 else if (perfLevel == Colored)
1432 g = new QSGGeometry(ColoredParticle_AttributeSet, vCount, iCount);
1433 else if (perfLevel == ColoredPoint)
1435 else //Simple
1437
1439 node->setGeometry(g);
1440 if (perfLevel <= ColoredPoint){
1441 g->setDrawingMode(QSGGeometry::DrawPoints);
1442 if (m_debugMode)
1443 qDebug("Using point sprites");
1444 } else {
1445 g->setDrawingMode(QSGGeometry::DrawTriangles);
1446 }
1447
1448 for (int p=0; p < count; ++p)
1449 commit(groupId, p);//commit sets geometry for the node, has its own perfLevel switch
1450
1451 if (perfLevel == Sprites)
1452 initTexCoords<SpriteVertex>((SpriteVertex*)g->vertexData(), vCount);
1453 else if (perfLevel == Tabled)
1454 initTexCoords<DeformableVertex>((DeformableVertex*)g->vertexData(), vCount);
1455 else if (perfLevel == Deformable)
1456 initTexCoords<DeformableVertex>((DeformableVertex*)g->vertexData(), vCount);
1457 else if (perfLevel == Colored)
1458 initTexCoords<ColoredVertex>((ColoredVertex*)g->vertexData(), vCount);
1459
1460 if (perfLevel > ColoredPoint){
1461 quint16 *indices = g->indexDataAsUShort();
1462 for (int i=0; i < count; ++i) {
1463 int o = i * 4;
1464 indices[0] = o;
1465 indices[1] = o + 1;
1466 indices[2] = o + 2;
1467 indices[3] = o + 1;
1468 indices[4] = o + 3;
1469 indices[5] = o + 2;
1470 indices += 6;
1471 }
1472 }
1473 }
1474
1475 if (perfLevel == Sprites)
1476 spritesUpdate();//Gives all vertexes the initial sprite data, then maintained per frame
1477
1478 foreach (QSGGeometryNode* node, m_nodes){
1479 if (node == *(m_nodes.begin()))
1480 node->setFlag(QSGGeometryNode::OwnsMaterial);//Root node owns the material for memory management purposes
1481 else
1482 (*(m_nodes.begin()))->appendChildNode(node);
1483 }
1484
1485 *node = *(m_nodes.begin());
1486 update();
1487}
1488
1490{
1491 if (!m_apiChecked || m_windowChanged) {
1492 m_apiChecked = true;
1493 m_windowChanged = false;
1494
1497 if (!rif)
1498 return nullptr;
1499
1501 const bool isRhi = QSGRendererInterface::isApiRhiBased(api);
1502
1503 if (!node && !isRhi)
1504 return nullptr;
1505
1506 if (isRhi)
1507 m_rhi = static_cast<QRhi *>(rif->getResource(m_window, QSGRendererInterface::RhiResource));
1508 else
1509 m_rhi = nullptr;
1510
1511 if (isRhi && !m_rhi) {
1512 qWarning("Failed to query QRhi, particles disabled");
1513 return nullptr;
1514 }
1515 // Get the pixel ratio of the window, used for pointsize scaling
1516 m_dpr = m_window ? m_window->devicePixelRatio() : 1.0;
1517 }
1518
1519 if (m_pleaseReset){
1520 // Cannot just destroy the node and then return null (in case image
1521 // loading is still in progress). Rather, keep track of the old node
1522 // until we have a new one.
1523 delete m_outgoingNode;
1524 m_outgoingNode = node;
1525 node = nullptr;
1526
1527 m_nodes.clear();
1528
1529 m_idxStarts.clear();
1530 m_startsIdx.clear();
1531 m_lastIdxStart = 0;
1532
1533 m_material = nullptr;
1534
1535 m_pleaseReset = false;
1536 m_startedImageLoading = 0;//Cancel a part-way build (may still have a pending load)
1537 } else if (!m_material) {
1538 delete node;
1539 node = nullptr;
1540 }
1541
1542 if (m_system && m_system->isRunning() && !m_system->isPaused()){
1543 bool dirty = prepareNextFrame(&node);
1544 if (node) {
1545 update();
1546 if (dirty) {
1547 foreach (QSGGeometryNode* n, m_nodes)
1548 n->markDirty(QSGNode::DirtyGeometry);
1549 }
1550 } else if (m_startedImageLoading < 2) {
1551 update();//To call prepareNextFrame() again from the renderThread
1552 }
1553 }
1554
1555 if (!node) {
1556 node = m_outgoingNode;
1557 m_outgoingNode = nullptr;
1558 }
1559
1560 return node;
1561}
1562
1564{
1565 if (*node == nullptr){//TODO: Staggered loading (as emitted)
1566 buildParticleNodes(node);
1567 if (m_debugMode) {
1568 qDebug() << "QQuickImageParticle Feature level: " << perfLevel;
1569 qDebug() << "QQuickImageParticle Nodes: ";
1570 int count = 0;
1571 for (auto it = m_nodes.keyBegin(), end = m_nodes.keyEnd(); it != end; ++it) {
1572 qDebug() << "Group " << *it << " (" << m_system->groupData[*it]->size()
1573 << " particles)";
1574 count += m_system->groupData[*it]->size();
1575 }
1576 qDebug() << "Total count: " << count;
1577 }
1578 if (*node == nullptr)
1579 return false;
1580 }
1581 qint64 timeStamp = m_system->systemSync(this);
1582
1583 qreal time = timeStamp / 1000.;
1584
1585 switch (perfLevel){//Fall-through intended
1586 case Sprites:
1587 //Advance State
1588 if (m_spriteEngine)
1589 m_spriteEngine->updateSprites(timeStamp);//fires signals if anim changed
1590 spritesUpdate(time);
1591 Q_FALLTHROUGH();
1592 case Tabled:
1593 case Deformable:
1594 case Colored:
1595 case ColoredPoint:
1596 case SimplePoint:
1597 default: //Also Simple
1598 getState(m_material)->timestamp = time;
1599 break;
1600 }
1601
1602 bool active = false;
1603 for (auto groupId : groupIds()) {
1604 if (m_system->groupData[groupId]->isActive()) {
1605 active = true;
1606 break;
1607 }
1608 }
1609
1610 const bool dirty = active || m_previousActive;
1611 if (dirty) {
1612 foreach (QSGGeometryNode* node, m_nodes)
1614 }
1615
1616 m_previousActive = active;
1617 return dirty;
1618}
1619
1620void QQuickImageParticle::spritesUpdate(qreal time)
1621{
1622 ImageMaterialData *state = getState(m_material);
1623 // Sprite progression handled CPU side, so as to have per-frame control.
1624 for (auto groupId : groupIds()) {
1625 for (QQuickParticleData* mainDatum : std::as_const(m_system->groupData[groupId]->data)) {
1626 QSGGeometryNode *node = m_nodes[groupId];
1627 if (!node)
1628 continue;
1629 //TODO: Interpolate between two different animations if it's going to transition next frame
1630 // This is particularly important for cut-up sprites.
1631 QQuickParticleData* datum = (mainDatum->animationOwner == this ? mainDatum : getShadowDatum(mainDatum));
1632 int spriteIdx = 0;
1633 for (int i = 0; i<m_startsIdx.size(); i++) {
1634 if (m_startsIdx[i].second == groupId){
1635 spriteIdx = m_startsIdx[i].first + datum->index;
1636 break;
1637 }
1638 }
1639
1640 double frameAt;
1641 qreal progress = 0;
1642
1643 if (datum->frameDuration > 0) {
1644 qreal frame = (time - datum->animT)/(datum->frameDuration / 1000.0);
1645 frame = qBound((qreal)0.0, frame, (qreal)((qreal)datum->frameCount - 1.0));//Stop at count-1 frames until we have between anim interpolation
1646 if (m_spritesInterpolate)
1647 progress = std::modf(frame,&frameAt);
1648 else
1649 std::modf(frame,&frameAt);
1650 } else {
1651 datum->frameAt++;
1652 if (datum->frameAt >= datum->frameCount){
1653 datum->frameAt = 0;
1654 m_spriteEngine->advance(spriteIdx);
1655 }
1656 frameAt = datum->frameAt;
1657 }
1658 if (m_spriteEngine->sprite(spriteIdx)->reverse())//### Store this in datum too?
1659 frameAt = (datum->frameCount - 1) - frameAt;
1660 QSizeF sheetSize = state->animSheetSize;
1661 qreal y = datum->animY / sheetSize.height();
1662 qreal w = datum->animWidth / sheetSize.width();
1663 qreal h = datum->animHeight / sheetSize.height();
1664 qreal x1 = datum->animX / sheetSize.width();
1665 x1 += frameAt * w;
1666 qreal x2 = x1;
1667 if (frameAt < (datum->frameCount-1))
1668 x2 += w;
1669
1670 SpriteVertex *spriteVertices = (SpriteVertex *) node->geometry()->vertexData();
1671 spriteVertices += datum->index*4;
1672 for (int i=0; i<4; i++) {
1673 spriteVertices[i].animX1 = x1;
1674 spriteVertices[i].animY1 = y;
1675 spriteVertices[i].animX2 = x2;
1676 spriteVertices[i].animW = w;
1677 spriteVertices[i].animH = h;
1678 spriteVertices[i].animProgress = progress;
1679 }
1680 }
1681 }
1682}
1683
1684void QQuickImageParticle::spriteAdvance(int spriteIdx)
1685{
1686 if (!m_startsIdx.size())//Probably overly defensive
1687 return;
1688
1689 int gIdx = -1;
1690 int i;
1691 for (i = 0; i<m_startsIdx.size(); i++) {
1692 if (spriteIdx < m_startsIdx[i].first) {
1693 gIdx = m_startsIdx[i-1].second;
1694 break;
1695 }
1696 }
1697 if (gIdx == -1)
1698 gIdx = m_startsIdx[i-1].second;
1699 int pIdx = spriteIdx - m_startsIdx[i-1].first;
1700
1701 QQuickParticleData* mainDatum = m_system->groupData[gIdx]->data[pIdx];
1702 QQuickParticleData* datum = (mainDatum->animationOwner == this ? mainDatum : getShadowDatum(mainDatum));
1703
1704 datum->animIdx = m_spriteEngine->spriteState(spriteIdx);
1705 datum->animT = m_spriteEngine->spriteStart(spriteIdx)/1000.0;
1706 datum->frameCount = m_spriteEngine->spriteFrames(spriteIdx);
1707 datum->frameDuration = m_spriteEngine->spriteDuration(spriteIdx) / datum->frameCount;
1708 datum->animX = m_spriteEngine->spriteX(spriteIdx);
1709 datum->animY = m_spriteEngine->spriteY(spriteIdx);
1710 datum->animWidth = m_spriteEngine->spriteWidth(spriteIdx);
1711 datum->animHeight = m_spriteEngine->spriteHeight(spriteIdx);
1712}
1713
1714void QQuickImageParticle::initialize(int gIdx, int pIdx)
1715{
1717 QQuickParticleData* datum = m_system->groupData[gIdx]->data[pIdx];
1718 qreal redVariation = m_color_variation + m_redVariation;
1719 qreal greenVariation = m_color_variation + m_greenVariation;
1720 qreal blueVariation = m_color_variation + m_blueVariation;
1721 int spriteIdx = 0;
1722 if (m_spriteEngine) {
1723 spriteIdx = m_idxStarts[gIdx] + datum->index;
1724 if (spriteIdx >= m_spriteEngine->count())
1725 m_spriteEngine->setCount(spriteIdx+1);
1726 }
1727
1728 float rotation;
1729 float rotationVelocity;
1730 uchar autoRotate;
1731 switch (perfLevel){//Fall-through is intended on all of them
1732 case Sprites:
1733 // Initial Sprite State
1734 if (m_explicitAnimation && m_spriteEngine){
1735 if (!datum->animationOwner)
1736 datum->animationOwner = this;
1737 QQuickParticleData* writeTo = (datum->animationOwner == this ? datum : getShadowDatum(datum));
1738 writeTo->animT = writeTo->t;
1739 //writeTo->animInterpolate = m_spritesInterpolate;
1740 if (m_spriteEngine){
1741 m_spriteEngine->start(spriteIdx);
1742 writeTo->frameCount = m_spriteEngine->spriteFrames(spriteIdx);
1743 writeTo->frameDuration = m_spriteEngine->spriteDuration(spriteIdx) / writeTo->frameCount;
1744 writeTo->animIdx = 0;//Always starts at 0
1745 writeTo->frameAt = -1;
1746 writeTo->animX = m_spriteEngine->spriteX(spriteIdx);
1747 writeTo->animY = m_spriteEngine->spriteY(spriteIdx);
1748 writeTo->animWidth = m_spriteEngine->spriteWidth(spriteIdx);
1749 writeTo->animHeight = m_spriteEngine->spriteHeight(spriteIdx);
1750 }
1751 } else {
1752 ImageMaterialData *state = getState(m_material);
1753 QQuickParticleData* writeTo = getShadowDatum(datum);
1754 writeTo->animT = datum->t;
1755 writeTo->frameCount = 1;
1756 writeTo->frameDuration = 60000000.0;
1757 writeTo->frameAt = -1;
1758 writeTo->animIdx = 0;
1759 writeTo->animT = 0;
1760 writeTo->animX = writeTo->animY = 0;
1761 writeTo->animWidth = state->animSheetSize.width();
1762 writeTo->animHeight = state->animSheetSize.height();
1763 }
1764 Q_FALLTHROUGH();
1765 case Tabled:
1766 case Deformable:
1767 //Initial Rotation
1768 if (m_explicitDeformation){
1769 if (!datum->deformationOwner)
1770 datum->deformationOwner = this;
1771 if (m_xVector){
1772 const QPointF &ret = m_xVector->sample(QPointF(datum->x, datum->y));
1773 if (datum->deformationOwner == this) {
1774 datum->xx = ret.x();
1775 datum->xy = ret.y();
1776 } else {
1777 QQuickParticleData* shadow = getShadowDatum(datum);
1778 shadow->xx = ret.x();
1779 shadow->xy = ret.y();
1780 }
1781 }
1782 if (m_yVector){
1783 const QPointF &ret = m_yVector->sample(QPointF(datum->x, datum->y));
1784 if (datum->deformationOwner == this) {
1785 datum->yx = ret.x();
1786 datum->yy = ret.y();
1787 } else {
1788 QQuickParticleData* shadow = getShadowDatum(datum);
1789 shadow->yx = ret.x();
1790 shadow->yy = ret.y();
1791 }
1792 }
1793 }
1794
1795 if (m_explicitRotation){
1796 if (!datum->rotationOwner)
1797 datum->rotationOwner = this;
1799 m_rotation + (m_rotationVariation
1800 - 2 * QRandomGenerator::global()->bounded(m_rotationVariation)));
1802 m_rotationVelocity
1803 + (m_rotationVelocityVariation
1804 - 2 * QRandomGenerator::global()->bounded(m_rotationVelocityVariation)));
1805 autoRotate = m_autoRotation ? 1 : 0;
1806 if (datum->rotationOwner == this) {
1807 datum->rotation = rotation;
1809 datum->autoRotate = autoRotate;
1810 } else {
1811 QQuickParticleData* shadow = getShadowDatum(datum);
1812 shadow->rotation = rotation;
1814 shadow->autoRotate = autoRotate;
1815 }
1816 }
1817 Q_FALLTHROUGH();
1818 case Colored:
1819 Q_FALLTHROUGH();
1820 case ColoredPoint:
1821 //Color initialization
1822 // Particle color
1823 if (m_explicitColor) {
1824 if (!datum->colorOwner)
1825 datum->colorOwner = this;
1826 const auto rgbColor = m_color.toRgb();
1827 color.r = rgbColor.red() * (1 - redVariation) + QRandomGenerator::global()->bounded(256) * redVariation;
1828 color.g = rgbColor.green() * (1 - greenVariation) + QRandomGenerator::global()->bounded(256) * greenVariation;
1829 color.b = rgbColor.blue() * (1 - blueVariation) + QRandomGenerator::global()->bounded(256) * blueVariation;
1830 color.a = m_alpha * rgbColor.alpha() * (1 - m_alphaVariation) + QRandomGenerator::global()->bounded(256) * m_alphaVariation;
1831 if (datum->colorOwner == this)
1832 datum->color = color;
1833 else
1834 getShadowDatum(datum)->color = color;
1835 }
1836 default:
1837 break;
1838 }
1839}
1840
1841void QQuickImageParticle::commit(int gIdx, int pIdx)
1842{
1843 if (m_pleaseReset)
1844 return;
1845 QSGGeometryNode *node = m_nodes[gIdx];
1846 if (!node)
1847 return;
1848 QQuickParticleData* datum = m_system->groupData[gIdx]->data[pIdx];
1849 SpriteVertex *spriteVertices = (SpriteVertex *) node->geometry()->vertexData();
1850 DeformableVertex *deformableVertices = (DeformableVertex *) node->geometry()->vertexData();
1851 ColoredVertex *coloredVertices = (ColoredVertex *) node->geometry()->vertexData();
1852 ColoredPointVertex *coloredPointVertices = (ColoredPointVertex *) node->geometry()->vertexData();
1853 SimplePointVertex *simplePointVertices = (SimplePointVertex *) node->geometry()->vertexData();
1854 switch (perfLevel){//No automatic fall through intended on this one
1855 case Sprites:
1856 spriteVertices += pIdx*4;
1857 for (int i=0; i<4; i++){
1858 spriteVertices[i].x = datum->x - m_systemOffset.x();
1859 spriteVertices[i].y = datum->y - m_systemOffset.y();
1860 spriteVertices[i].t = datum->t;
1861 spriteVertices[i].lifeSpan = datum->lifeSpan;
1862 spriteVertices[i].size = datum->size;
1863 spriteVertices[i].endSize = datum->endSize;
1864 spriteVertices[i].vx = datum->vx;
1865 spriteVertices[i].vy = datum->vy;
1866 spriteVertices[i].ax = datum->ax;
1867 spriteVertices[i].ay = datum->ay;
1868 if (m_explicitDeformation && datum->deformationOwner != this) {
1869 QQuickParticleData* shadow = getShadowDatum(datum);
1870 spriteVertices[i].xx = shadow->xx;
1871 spriteVertices[i].xy = shadow->xy;
1872 spriteVertices[i].yx = shadow->yx;
1873 spriteVertices[i].yy = shadow->yy;
1874 } else {
1875 spriteVertices[i].xx = datum->xx;
1876 spriteVertices[i].xy = datum->xy;
1877 spriteVertices[i].yx = datum->yx;
1878 spriteVertices[i].yy = datum->yy;
1879 }
1880 if (m_explicitRotation && datum->rotationOwner != this) {
1881 QQuickParticleData* shadow = getShadowDatum(datum);
1882 spriteVertices[i].rotation = shadow->rotation;
1883 spriteVertices[i].rotationVelocity = shadow->rotationVelocity;
1884 spriteVertices[i].autoRotate = shadow->autoRotate;
1885 } else {
1886 spriteVertices[i].rotation = datum->rotation;
1887 spriteVertices[i].rotationVelocity = datum->rotationVelocity;
1888 spriteVertices[i].autoRotate = datum->autoRotate;
1889 }
1890 //Sprite-related vertices updated per-frame in spritesUpdate(), not on demand
1891 if (m_explicitColor && datum->colorOwner != this) {
1892 QQuickParticleData* shadow = getShadowDatum(datum);
1893 spriteVertices[i].color = shadow->color;
1894 } else {
1895 spriteVertices[i].color = datum->color;
1896 }
1897 }
1898 break;
1899 case Tabled: //Fall through until it has its own vertex class
1900 case Deformable:
1901 deformableVertices += pIdx*4;
1902 for (int i=0; i<4; i++){
1903 deformableVertices[i].x = datum->x - m_systemOffset.x();
1904 deformableVertices[i].y = datum->y - m_systemOffset.y();
1905 deformableVertices[i].t = datum->t;
1906 deformableVertices[i].lifeSpan = datum->lifeSpan;
1907 deformableVertices[i].size = datum->size;
1908 deformableVertices[i].endSize = datum->endSize;
1909 deformableVertices[i].vx = datum->vx;
1910 deformableVertices[i].vy = datum->vy;
1911 deformableVertices[i].ax = datum->ax;
1912 deformableVertices[i].ay = datum->ay;
1913 if (m_explicitDeformation && datum->deformationOwner != this) {
1914 QQuickParticleData* shadow = getShadowDatum(datum);
1915 deformableVertices[i].xx = shadow->xx;
1916 deformableVertices[i].xy = shadow->xy;
1917 deformableVertices[i].yx = shadow->yx;
1918 deformableVertices[i].yy = shadow->yy;
1919 } else {
1920 deformableVertices[i].xx = datum->xx;
1921 deformableVertices[i].xy = datum->xy;
1922 deformableVertices[i].yx = datum->yx;
1923 deformableVertices[i].yy = datum->yy;
1924 }
1925 if (m_explicitRotation && datum->rotationOwner != this) {
1926 QQuickParticleData* shadow = getShadowDatum(datum);
1927 deformableVertices[i].rotation = shadow->rotation;
1928 deformableVertices[i].rotationVelocity = shadow->rotationVelocity;
1929 deformableVertices[i].autoRotate = shadow->autoRotate;
1930 } else {
1931 deformableVertices[i].rotation = datum->rotation;
1932 deformableVertices[i].rotationVelocity = datum->rotationVelocity;
1933 deformableVertices[i].autoRotate = datum->autoRotate;
1934 }
1935 if (m_explicitColor && datum->colorOwner != this) {
1936 QQuickParticleData* shadow = getShadowDatum(datum);
1937 deformableVertices[i].color = shadow->color;
1938 } else {
1939 deformableVertices[i].color = datum->color;
1940 }
1941 }
1942 break;
1943 case Colored:
1944 coloredVertices += pIdx*4;
1945 for (int i=0; i<4; i++){
1946 coloredVertices[i].x = datum->x - m_systemOffset.x();
1947 coloredVertices[i].y = datum->y - m_systemOffset.y();
1948 coloredVertices[i].t = datum->t;
1949 coloredVertices[i].lifeSpan = datum->lifeSpan;
1950 coloredVertices[i].size = datum->size;
1951 coloredVertices[i].endSize = datum->endSize;
1952 coloredVertices[i].vx = datum->vx;
1953 coloredVertices[i].vy = datum->vy;
1954 coloredVertices[i].ax = datum->ax;
1955 coloredVertices[i].ay = datum->ay;
1956 if (m_explicitColor && datum->colorOwner != this) {
1957 QQuickParticleData* shadow = getShadowDatum(datum);
1958 coloredVertices[i].color = shadow->color;
1959 } else {
1960 coloredVertices[i].color = datum->color;
1961 }
1962 }
1963 break;
1964 case ColoredPoint:
1965 coloredPointVertices += pIdx*1;
1966 for (int i=0; i<1; i++){
1967 coloredPointVertices[i].x = datum->x - m_systemOffset.x();
1968 coloredPointVertices[i].y = datum->y - m_systemOffset.y();
1969 coloredPointVertices[i].t = datum->t;
1970 coloredPointVertices[i].lifeSpan = datum->lifeSpan;
1971 coloredPointVertices[i].size = datum->size;
1972 coloredPointVertices[i].endSize = datum->endSize;
1973 coloredPointVertices[i].vx = datum->vx;
1974 coloredPointVertices[i].vy = datum->vy;
1975 coloredPointVertices[i].ax = datum->ax;
1976 coloredPointVertices[i].ay = datum->ay;
1977 if (m_explicitColor && datum->colorOwner != this) {
1978 QQuickParticleData* shadow = getShadowDatum(datum);
1979 coloredPointVertices[i].color = shadow->color;
1980 } else {
1981 coloredPointVertices[i].color = datum->color;
1982 }
1983 }
1984 break;
1985 case SimplePoint:
1986 simplePointVertices += pIdx*1;
1987 for (int i=0; i<1; i++){
1988 simplePointVertices[i].x = datum->x - m_systemOffset.x();
1989 simplePointVertices[i].y = datum->y - m_systemOffset.y();
1990 simplePointVertices[i].t = datum->t;
1991 simplePointVertices[i].lifeSpan = datum->lifeSpan;
1992 simplePointVertices[i].size = datum->size;
1993 simplePointVertices[i].endSize = datum->endSize;
1994 simplePointVertices[i].vx = datum->vx;
1995 simplePointVertices[i].vy = datum->vy;
1996 simplePointVertices[i].ax = datum->ax;
1997 simplePointVertices[i].ay = datum->ay;
1998 }
1999 break;
2000 default:
2001 break;
2002 }
2003}
2004
2005
2006
2008
2009#include "moc_qquickimageparticle_p.cpp"
QSGMaterialShader * createShader(QSGRendererInterface::RenderMode renderMode) const override
This function returns a new instance of a the QSGMaterialShader implementation used to render geometr...
ImageMaterialData * state() override
QSGMaterialType * type() const override
This function is called by the scene graph to query an identifier that is unique to the QSGMaterialSh...
void updateSampledImage(RenderState &renderState, int binding, QSGTexture **texture, QSGMaterial *newMaterial, QSGMaterial *) override
This function is called by the scene graph to prepare use of sampled images in the shader,...
bool updateUniformData(RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override
This function is called by the scene graph to get the contents of the shader program's uniform buffer...
QSGMaterialShader * createShader(QSGRendererInterface::RenderMode renderMode) const override
This function returns a new instance of a the QSGMaterialShader implementation used to render geometr...
ImageMaterialData * state() override
QSGMaterialType * type() const override
This function is called by the scene graph to query an identifier that is unique to the QSGMaterialSh...
void updateSampledImage(RenderState &renderState, int binding, QSGTexture **texture, QSGMaterial *newMaterial, QSGMaterial *) override
This function is called by the scene graph to prepare use of sampled images in the shader,...
bool updateUniformData(RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override
This function is called by the scene graph to get the contents of the shader program's uniform buffer...
ImageMaterialData * state() override
QSGMaterialShader * createShader(QSGRendererInterface::RenderMode renderMode) const override
This function returns a new instance of a the QSGMaterialShader implementation used to render geometr...
QSGMaterialType * type() const override
This function is called by the scene graph to query an identifier that is unique to the QSGMaterialSh...
float opacityTable[UNIFORM_ARRAY_SIZE]
float sizeTable[UNIFORM_ARRAY_SIZE]
bool updateUniformData(RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override
This function is called by the scene graph to get the contents of the shader program's uniform buffer...
void updateSampledImage(RenderState &renderState, int binding, QSGTexture **texture, QSGMaterial *newMaterial, QSGMaterial *) override
This function is called by the scene graph to prepare use of sampled images in the shader,...
\inmodule QtCore
Definition qbytearray.h:57
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
QColor toRgb() const noexcept
Create and returns an RGB QColor based on this color.
Definition qcolor.cpp:2035
bool isValid() const noexcept
Returns true if the color is valid; otherwise returns false.
Definition qcolor.h:285
key_iterator keyEnd() const noexcept
Definition qhash.h:1211
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
Definition qhash.h:1202
key_iterator keyBegin() const noexcept
Definition qhash.h:1210
void clear() noexcept(std::is_nothrow_destructible< Node >::value)
Removes all items from the hash and frees up all memory used by it.
Definition qhash.h:949
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1283
\inmodule QtGui
Definition qimage.h:37
QImage scaled(int w, int h, Qt::AspectRatioMode aspectMode=Qt::IgnoreAspectRatio, Qt::TransformationMode mode=Qt::FastTransformation) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qimage.h:208
QRgb pixel(int x, int y) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qimage.cpp:2478
@ Format_ARGB32_Premultiplied
Definition qimage.h:48
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
T & first()
Definition qlist.h:628
void append(parameter_type t)
Definition qlist.h:441
void clear()
Definition qlist.h:417
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
Definition qmatrix4x4.h:25
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
\inmodule QtCore\reentrant
Definition qpoint.h:214
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:333
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:338
The QQmlContext class defines a context within a QML engine.
Definition qqmlcontext.h:25
The QQmlEngine class provides an environment for instantiating QML components.
Definition qqmlengine.h:57
The QQmlListProperty class allows applications to expose list-like properties of QObject-derived clas...
Definition qqmllist.h:24
virtual QPointF sample(const QPointF &from)
void sceneGraphInvalidated() override
QQmlListProperty< QQuickSprite > sprites
void rotationChanged(qreal arg)
void setYVector(QQuickDirection *arg)
void setColortable(const QUrl &table)
void rotationVelocityChanged(qreal arg)
void setSizetable(const QUrl &table)
QSGNode * updatePaintNode(QSGNode *, UpdatePaintNodeData *) override
Called on the render thread when it is time to sync the state of the item with the scene graph.
void blueVariationChanged(qreal arg)
QQuickImageParticle(QQuickItem *parent=nullptr)
\qmltype ImageParticle \instantiates QQuickImageParticle \inqmlmodule QtQuick.Particles \inherits Par...
void xVectorChanged(QQuickDirection *arg)
void greenVariationChanged(qreal arg)
void setSpritesInterpolate(bool arg)
void buildParticleNodes(QSGNode **)
void setXVector(QQuickDirection *arg)
void setColorVariation(qreal var)
void bypassOptimizationsChanged(bool arg)
void setRotationVelocityVariation(qreal arg)
void rotationVariationChanged(qreal arg)
void initialize(int gIdx, int pIdx) override
void spritesInterpolateChanged(bool arg)
void setColor(const QColor &color)
bool prepareNextFrame(QSGNode **)
void setRedVariation(qreal arg)
void alphaVariationChanged(qreal arg)
void setBypassOptimizations(bool arg)
void entryEffectChanged(EntryEffect arg)
void setRotationVelocity(qreal arg)
void redVariationChanged(qreal arg)
void alphaChanged(qreal arg)
void setRotationVariation(qreal arg)
void yVectorChanged(QQuickDirection *arg)
void setOpacitytable(const QUrl &table)
void commit(int gIdx, int pIdx) override
void setBlueVariation(qreal arg)
void setGreenVariation(qreal arg)
void autoRotationChanged(bool arg)
void setImage(const QUrl &image)
void setEntryEffect(EntryEffect arg)
void setAlphaVariation(qreal arg)
void colorVariationChanged()
void rotationVelocityVariationChanged(qreal arg)
QSGRenderContext * sceneGraphRenderContext() const
static QQuickItemPrivate * get(QQuickItem *item)
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:64
void setFlag(Flag flag, bool enabled=true)
Enables the specified flag for this item if enabled is true; if enabled is false, the flag is disable...
QString state() const
\qmlproperty string QtQuick::Item::state
qreal y
Defines the item's y position relative to its parent.
Definition qquickitem.h:74
void stateChanged(const QString &)
void update()
Schedules a call to updatePaintNode() for this item.
QQuickImageParticle * deformationOwner
QQuickImageParticle * colorOwner
QQuickParticleGroupData::ID groupId
QQuickImageParticle * animationOwner
QQuickImageParticle * rotationOwner
QVector< QQuickParticleData * > data
const GroupIDs & groupIds() const
QQuickParticleSystem * m_system
QVarLengthArray< QQuickParticleGroupData *, 32 > groupData
int systemSync(QQuickParticlePainter *p)
int spriteDuration(int sprite=0) const
QQuickSprite * sprite(int sprite=0) const
int spriteFrames(int sprite=0) const
int spriteStart(int sprite=0) const
int spriteX(int sprite=0) const
void advance(int index=0) override
int spriteState(int sprite=0) const
int spriteHeight(int sprite=0) const
int spriteWidth(int sprite=0) const
int spriteY(int sprite=0) const
QImage assembledImage(int maxSize=2048)
void start(int index=0, int state=0)
static Q_DECL_CONST_FUNCTION QRandomGenerator * global()
\threadsafe
Definition qrandom.h:275
double bounded(double highest)
Generates one random double in the range between 0 (inclusive) and highest (exclusive).
Definition qrandom.h:72
\inmodule QtGui
Definition qrhi.h:1767
@ VertexShaderPointSize
Definition qrhi.h:1808
const QSGGeometry * geometry() const
Returns this node's geometry.
Definition qsgnode.h:160
void setGeometry(QSGGeometry *geometry)
Sets the geometry of this node to geometry.
Definition qsgnode.cpp:762
virtual QSGRendererInterface * rendererInterface(QSGRenderContext *renderContext)
Returns a pointer to the (presumably) global renderer interface.
The QSGGeometryNode class is used for all rendered content in the scene graph.
Definition qsgnode.h:191
void setMaterial(QSGMaterial *material)
Sets the material of this geometry node to material.
Definition qsgnode.cpp:925
The QSGGeometry class provides low-level storage for graphics primitives in the \l{Qt Quick Scene Gra...
Definition qsggeometry.h:15
void * vertexData()
Returns a pointer to the raw vertex data of this geometry object.
Encapsulates the current rendering state during a call to QSGMaterialShader::updateUniformData() and ...
QByteArray * uniformData()
Returns a pointer to the data for the uniform (constant) buffer in the shader.
QMatrix4x4 combinedMatrix() const
Returns the matrix combined of modelview matrix and project matrix.
bool isMatrixDirty() const
Returns true if the dirtyStates() contain the dirty matrix state, otherwise returns false.
bool isOpacityDirty() const
Returns true if the dirtyStates() contains the dirty opacity state, otherwise returns false.
QRhi * rhi()
Returns the current QRhi.
float opacity() const
\variable QSGMaterialShader::GraphicsPipelineState::blendEnable
QRhiResourceUpdateBatch * resourceUpdateBatch()
Returns a resource update batch to which upload and copy operatoins can be queued.
The QSGMaterialShader class represents a graphics API independent shader program.
void setShaderFileName(Stage stage, const QString &filename)
Sets the filename for the shader for the specified stage.
The QSGMaterial class encapsulates rendering state for a shader program.
Definition qsgmaterial.h:15
void setFlag(Flags flags, bool on=true)
Sets the flags flags on this material if on is true; otherwise clears the attribute.
\group qtquick-scenegraph-nodes \title Qt Quick Scene Graph Node classes
Definition qsgnode.h:37
@ DirtyMaterial
Definition qsgnode.h:75
@ DirtyGeometry
Definition qsgnode.h:74
@ OwnsMaterial
Definition qsgnode.h:58
@ OwnsGeometry
Definition qsgnode.h:57
void markDirty(DirtyState bits)
Notifies all connected renderers that the node has dirty bits.
Definition qsgnode.cpp:622
void setFlag(Flag, bool=true)
Sets the flag f on this node if enabled is true; otherwise clears the flag.
Definition qsgnode.cpp:584
static QSGPlainTexture * fromImage(const QImage &image)
QSGContext * sceneGraphContext() const
An interface providing access to some of the graphics API specific internals of the scenegraph.
RenderMode
\value RenderMode2D Normal 2D rendering \value RenderMode2DNoDepthBuffer Normal 2D rendering with dep...
static bool isApiRhiBased(GraphicsApi api)
virtual GraphicsApi graphicsApi() const =0
Returns the graphics API that is in use by the Qt Quick scenegraph.
virtual void * getResource(QQuickWindow *window, Resource resource) const
Queries a graphics resource in window.
GraphicsApi
\value Unknown An unknown graphics API is in use \value Software The Qt Quick 2D Renderer is in use \...
\inmodule QtQuick
Definition qsgtexture.h:20
T * get() const noexcept
void reset(T *other=nullptr) noexcept(noexcept(Cleanup::cleanup(std::declval< T * >())))
Deletes the existing object it is pointing to (if any), and sets its pointer to other.
\inmodule QtCore
Definition qsize.h:207
constexpr qreal width() const noexcept
Returns the width.
Definition qsize.h:321
constexpr qreal height() const noexcept
Returns the height.
Definition qsize.h:324
\inmodule QtCore
Definition qurl.h:94
constexpr size_type size() const noexcept
T * data() noexcept
bool updateUniformData(RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override
This function is called by the scene graph to get the contents of the shader program's uniform buffer...
void updateSampledImage(RenderState &renderState, int binding, QSGTexture **texture, QSGMaterial *newMaterial, QSGMaterial *) override
This function is called by the scene graph to prepare use of sampled images in the shader,...
QSGMaterialShader * createShader(QSGRendererInterface::RenderMode renderMode) const override
This function returns a new instance of a the QSGMaterialShader implementation used to render geometr...
QSGMaterialType * type() const override
This function is called by the scene graph to query an identifier that is unique to the QSGMaterialSh...
ImageMaterialData * state() override
QSGMaterialType * type() const override
This function is called by the scene graph to query an identifier that is unique to the QSGMaterialSh...
QSGMaterialShader * createShader(QSGRendererInterface::RenderMode renderMode) const override
This function returns a new instance of a the QSGMaterialShader implementation used to render geometr...
ImageMaterialData * state() override
bool updateUniformData(RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override
This function is called by the scene graph to get the contents of the shader program's uniform buffer...
void updateSampledImage(RenderState &renderState, int binding, QSGTexture **texture, QSGMaterial *newMaterial, QSGMaterial *) override
This function is called by the scene graph to prepare use of sampled images in the shader,...
QSGMaterialShader * createShader(QSGRendererInterface::RenderMode renderMode) const override
This function returns a new instance of a the QSGMaterialShader implementation used to render geometr...
ImageMaterialData * state() override
QSGMaterialType * type() const override
This function is called by the scene graph to query an identifier that is unique to the QSGMaterialSh...
qDeleteAll(list.begin(), list.end())
QSet< QString >::iterator it
else opt state
[0]
Combined button and popup list for selecting options.
@ white
Definition qnamespace.h:30
@ QueuedConnection
@ DirectConnection
Definition image.cpp:4
static void * context
#define Q_FALLTHROUGH()
#define qDebug
[1]
Definition qlogging.h:160
#define qWarning
Definition qlogging.h:162
return ret
constexpr float qDegreesToRadians(float degrees)
Definition qmath.h:260
constexpr const T & qBound(const T &min, const T &val, const T &max)
Definition qminmax.h:44
#define SLOT(a)
Definition qobjectdefs.h:51
#define SIGNAL(a)
Definition qobjectdefs.h:52
const GLfloat * m
GLenum GLuint GLint level
GLfloat GLfloat GLfloat w
[0]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint GLuint end
GLuint GLfloat GLfloat GLfloat x1
GLenum GLenum GLsizei count
GLint GLint GLint GLint GLsizei GLsizei GLsizei GLboolean commit
GLenum GLuint GLenum GLsizei const GLchar * buf
GLenum GLuint texture
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLboolean GLboolean g
GLint first
GLfloat n
GLsizei GLenum const void * indices
GLint y
GLfloat GLfloat GLfloat GLfloat h
GLint void * img
Definition qopenglext.h:233
GLuint entry
GLenum array
GLfixed GLfixed x2
GLfloat GLfloat p
[1]
GLenum GLenum GLsizei void * table
constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2) noexcept(noexcept(std::make_pair(std::forward< T1 >(value1), std::forward< T2 >(value2))))
Definition qpair.h:19
QQmlContext * qmlContext(const QObject *obj)
Definition qqml.cpp:71
Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me)
Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me)
static QT_BEGIN_NAMESPACE qreal dpr(const QWindow *w)
static QSGGeometry::Attribute DeformableParticle_Attributes[]
static QSGGeometry::AttributeSet SpriteParticle_AttributeSet
void fillUniformArrayFromImage(float *array, const QImage &img, int size)
static QSGGeometry::Attribute SpriteParticle_Attributes[]
#define UNIFORM_ARRAY_SIZE
static QSGGeometry::AttributeSet SimplePointParticle_AttributeSet
static QSGGeometry::Attribute ColoredParticle_Attributes[]
static QSGGeometry::AttributeSet DeformableParticle_AttributeSet
static QSGGeometry::AttributeSet ColoredParticle_AttributeSet
static QSGGeometry::Attribute ColoredPointParticle_Attributes[]
static QSGGeometry::AttributeSet ColoredPointParticle_AttributeSet
static QSGGeometry::Attribute SimplePointParticle_Attributes[]
void spriteReplace(QQmlListProperty< QQuickSprite > *p, qsizetype idx, QQuickSprite *s)
void spriteAppend(QQmlListProperty< QQuickSprite > *p, QQuickSprite *s)
void spriteRemoveLast(QQmlListProperty< QQuickSprite > *p)
qsizetype spriteCount(QQmlListProperty< QQuickSprite > *p)
QQuickSprite * spriteAt(QQmlListProperty< QQuickSprite > *p, qsizetype idx)
void spriteClear(QQmlListProperty< QQuickSprite > *p)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
constexpr int qAlpha(QRgb rgb)
Definition qrgb.h:27
SSL_CTX int(*) void arg)
#define QStringLiteral(str)
#define emit
#define Q_UNUSED(x)
unsigned char uchar
Definition qtypes.h:27
unsigned short quint16
Definition qtypes.h:43
long long qint64
Definition qtypes.h:55
double qreal
Definition qtypes.h:92
QImage scaled(const QImage &image)
[0]
QObject::connect nullptr
QSharedPointer< T > other(t)
[5]
QFrame frame
[0]
QJSEngine engine
[0]
The QSGGeometry::AttributeSet describes how the vertices in a QSGGeometry are built up.
Definition qsggeometry.h:73
The QSGGeometry::Attribute describes a single vertex attribute in a QSGGeometry.
Definition qsggeometry.h:58
static Attribute create(int pos, int tupleSize, int primitiveType, bool isPosition=false)
Creates a new QSGGeometry::Attribute for attribute register pos with tupleSize.
The QSGMaterialType class is used as a unique type token in combination with QSGMaterial.
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent