Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
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#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
5
6#include <QtQuick/private/qsgcontext_p.h>
7#include <private/qsgadaptationlayer_p.h>
8#include <private/qquickitem_p.h>
9#include <QtQuick/qsgnode.h>
10#include <QtQuick/qsgtexture.h>
11#include <QFile>
12#include <QRandomGenerator>
15#include <private/qquicksprite_p.h>
16#include <private/qquickspriteengine_p.h>
17#include <QSGRendererInterface>
18#include <QtQuick/private/qsgplaintexture_p.h>
19#include <private/qqmlglobal_p.h>
20#include <QtQml/qqmlinfo.h>
21#include <QtCore/QtMath>
22#include <rhi/qrhi.h>
23
24#include <cmath>
25
27
28// Must match the shader code
29#define UNIFORM_ARRAY_SIZE 64
30
53
55{
56public:
58 {
59 setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_tabled.vert.qsb"), viewCount);
60 setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_tabled.frag.qsb"), viewCount);
61 }
62
63 bool updateUniformData(RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override
64 {
65 QByteArray *buf = renderState.uniformData();
66 Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4));
67 const int shaderMatrixCount = newMaterial->viewCount();
68 const int matrixCount = qMin(renderState.projectionMatrixCount(), shaderMatrixCount);
69
70 for (int viewIndex = 0; viewIndex < matrixCount; ++viewIndex) {
71 if (renderState.isMatrixDirty()) {
72 const QMatrix4x4 m = renderState.combinedMatrix(viewIndex);
73 memcpy(buf->data() + 64 * viewIndex, m.constData(), 64);
74 }
75 }
76
77 if (renderState.isOpacityDirty()) {
78 const float opacity = renderState.opacity();
79 memcpy(buf->data() + 64 * shaderMatrixCount, &opacity, 4);
80 }
81
82 ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
83
84 float entry = float(state->entry);
85 memcpy(buf->data() + 64 * shaderMatrixCount + 4, &entry, 4);
86
87 float timestamp = float(state->timestamp);
88 memcpy(buf->data() + 64 * shaderMatrixCount + 8, &timestamp, 4);
89
90 float *p = reinterpret_cast<float *>(buf->data() + 64 * shaderMatrixCount + 16);
91 for (int i = 0; i < UNIFORM_ARRAY_SIZE; ++i) {
92 *p = state->sizeTable[i];
93 p += 4;
94 }
95 p = reinterpret_cast<float *>(buf->data() + 64 * shaderMatrixCount + 16 + (UNIFORM_ARRAY_SIZE * 4 * 4));
96 for (int i = 0; i < UNIFORM_ARRAY_SIZE; ++i) {
97 *p = state->opacityTable[i];
98 p += 4;
99 }
100
101 return true;
102 }
103
104 void updateSampledImage(RenderState &renderState, int binding, QSGTexture **texture,
105 QSGMaterial *newMaterial, QSGMaterial *) override
106 {
107 ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
108 if (binding == 2) {
109 state->colorTable->commitTextureOperations(renderState.rhi(), renderState.resourceUpdateBatch());
110 *texture = state->colorTable;
111 } else if (binding == 1) {
112 state->texture->commitTextureOperations(renderState.rhi(), renderState.resourceUpdateBatch());
113 *texture = state->texture;
114 }
115 }
116};
117
119{
120public:
122 Q_UNUSED(renderMode);
124 }
125 QSGMaterialType *type() const override { return &m_type; }
126
127 ImageMaterialData *state() override { return &m_state; }
128
129private:
130 static QSGMaterialType m_type;
131 ImageMaterialData m_state;
132};
133
134QSGMaterialType TabledMaterial::m_type;
135
137{
138public:
140 {
141 setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_deformed.vert.qsb"), viewCount);
142 setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_deformed.frag.qsb"), viewCount);
143 }
144
145 bool updateUniformData(RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override
146 {
147 QByteArray *buf = renderState.uniformData();
148 Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4));
149 const int shaderMatrixCount = newMaterial->viewCount();
150 const int matrixCount = qMin(renderState.projectionMatrixCount(), shaderMatrixCount);
151
152 for (int viewIndex = 0; viewIndex < matrixCount; ++viewIndex) {
153 if (renderState.isMatrixDirty()) {
154 const QMatrix4x4 m = renderState.combinedMatrix(viewIndex);
155 memcpy(buf->data() + 64 * viewIndex, m.constData(), 64);
156 }
157 }
158
159 if (renderState.isOpacityDirty()) {
160 const float opacity = renderState.opacity();
161 memcpy(buf->data() + 64 * shaderMatrixCount, &opacity, 4);
162 }
163
164 ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
165
166 float entry = float(state->entry);
167 memcpy(buf->data() + 64 * shaderMatrixCount + 4, &entry, 4);
168
169 float timestamp = float(state->timestamp);
170 memcpy(buf->data() + 64 * shaderMatrixCount + 8, &timestamp, 4);
171
172 return true;
173 }
174
175 void updateSampledImage(RenderState &renderState, int binding, QSGTexture **texture,
176 QSGMaterial *newMaterial, QSGMaterial *) override
177 {
178 ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
179 if (binding == 1) {
180 state->texture->commitTextureOperations(renderState.rhi(), renderState.resourceUpdateBatch());
181 *texture = state->texture;
182 }
183 }
184};
185
187{
188public:
190 Q_UNUSED(renderMode);
192 }
193 QSGMaterialType *type() const override { return &m_type; }
194
195 ImageMaterialData *state() override { return &m_state; }
196
197private:
198 static QSGMaterialType m_type;
199 ImageMaterialData m_state;
200};
201
202QSGMaterialType DeformableMaterial::m_type;
203
205{
206public:
208 {
209 setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_sprite.vert.qsb"), viewCount);
210 setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_sprite.frag.qsb"), viewCount);
211 }
212
213 bool updateUniformData(RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override
214 {
215 QByteArray *buf = renderState.uniformData();
216 Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4));
217 const int shaderMatrixCount = newMaterial->viewCount();
218 const int matrixCount = qMin(renderState.projectionMatrixCount(), shaderMatrixCount);
219
220 for (int viewIndex = 0; viewIndex < matrixCount; ++viewIndex) {
221 if (renderState.isMatrixDirty()) {
222 const QMatrix4x4 m = renderState.combinedMatrix(viewIndex);
223 memcpy(buf->data() + 64 * viewIndex, m.constData(), 64);
224 }
225 }
226
227 if (renderState.isOpacityDirty()) {
228 const float opacity = renderState.opacity();
229 memcpy(buf->data() + 64 * shaderMatrixCount, &opacity, 4);
230 }
231
232 ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
233
234 float entry = float(state->entry);
235 memcpy(buf->data() + 64 * shaderMatrixCount + 4, &entry, 4);
236
237 float timestamp = float(state->timestamp);
238 memcpy(buf->data() + 64 * shaderMatrixCount + 8, &timestamp, 4);
239
240 float *p = reinterpret_cast<float *>(buf->data() + 64 * shaderMatrixCount + 16);
241 for (int i = 0; i < UNIFORM_ARRAY_SIZE; ++i) {
242 *p = state->sizeTable[i];
243 p += 4;
244 }
245 p = reinterpret_cast<float *>(buf->data() + 64 * shaderMatrixCount + 16 + (UNIFORM_ARRAY_SIZE * 4 * 4));
246 for (int i = 0; i < UNIFORM_ARRAY_SIZE; ++i) {
247 *p = state->opacityTable[i];
248 p += 4;
249 }
250
251 return true;
252 }
253
254 void updateSampledImage(RenderState &renderState, int binding, QSGTexture **texture,
255 QSGMaterial *newMaterial, QSGMaterial *) override
256 {
257 ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
258 if (binding == 2) {
259 state->colorTable->commitTextureOperations(renderState.rhi(), renderState.resourceUpdateBatch());
260 *texture = state->colorTable;
261 } else if (binding == 1) {
262 state->texture->commitTextureOperations(renderState.rhi(), renderState.resourceUpdateBatch());
263 *texture = state->texture;
264 }
265 }
266};
267
269{
270public:
272 Q_UNUSED(renderMode);
274 }
275 QSGMaterialType *type() const override { return &m_type; }
276
277 ImageMaterialData *state() override { return &m_state; }
278
279private:
280 static QSGMaterialType m_type;
281 ImageMaterialData m_state;
282};
283
284QSGMaterialType SpriteMaterial::m_type;
285
287{
288public:
290 {
291 setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_coloredpoint.vert.qsb"), viewCount);
292 setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_coloredpoint.frag.qsb"), viewCount);
293 }
294
295 bool updateUniformData(RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override
296 {
297 QByteArray *buf = renderState.uniformData();
298 Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4));
299 const int shaderMatrixCount = newMaterial->viewCount();
300 const int matrixCount = qMin(renderState.projectionMatrixCount(), shaderMatrixCount);
301
302 for (int viewIndex = 0; viewIndex < matrixCount; ++viewIndex) {
303 if (renderState.isMatrixDirty()) {
304 const QMatrix4x4 m = renderState.combinedMatrix(viewIndex);
305 memcpy(buf->data() + 64 * viewIndex, m.constData(), 64);
306 }
307 }
308
309 if (renderState.isOpacityDirty()) {
310 const float opacity = renderState.opacity();
311 memcpy(buf->data() + 64 * shaderMatrixCount, &opacity, 4);
312 }
313
314 ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
315
316 float entry = float(state->entry);
317 memcpy(buf->data() + 64 * shaderMatrixCount + 4, &entry, 4);
318
319 float timestamp = float(state->timestamp);
320 memcpy(buf->data() + 64 * shaderMatrixCount + 8, &timestamp, 4);
321
322 float dpr = float(state->dpr);
323 memcpy(buf->data() + 64 * shaderMatrixCount + 12, &dpr, 4);
324
325 return true;
326 }
327
328 void updateSampledImage(RenderState &renderState, int binding, QSGTexture **texture,
329 QSGMaterial *newMaterial, QSGMaterial *) override
330 {
331 ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
332 if (binding == 1) {
333 state->texture->commitTextureOperations(renderState.rhi(), renderState.resourceUpdateBatch());
334 *texture = state->texture;
335 }
336 }
337};
338
340{
341public:
343 Q_UNUSED(renderMode);
345 }
346 QSGMaterialType *type() const override { return &m_type; }
347
348 ImageMaterialData *state() override { return &m_state; }
349
350private:
351 static QSGMaterialType m_type;
352 ImageMaterialData m_state;
353};
354
355QSGMaterialType ColoredPointMaterial::m_type;
356
358{
359public:
362 {
363 setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_colored.vert.qsb"), viewCount);
364 setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_colored.frag.qsb"), viewCount);
365 }
366};
367
369{
370public:
372 Q_UNUSED(renderMode);
374 }
375 QSGMaterialType *type() const override { return &m_type; }
376
377 ImageMaterialData *state() override { return &m_state; }
378
379private:
380 static QSGMaterialType m_type;
381 ImageMaterialData m_state;
382};
383
384QSGMaterialType ColoredMaterial::m_type;
385
387{
388public:
390 {
391 setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_simplepoint.vert.qsb"), viewCount);
392 setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_simplepoint.frag.qsb"), viewCount);
393 }
394
395 bool updateUniformData(RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override
396 {
397 QByteArray *buf = renderState.uniformData();
398 Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4));
399 const int shaderMatrixCount = newMaterial->viewCount();
400 const int matrixCount = qMin(renderState.projectionMatrixCount(), shaderMatrixCount);
401
402 for (int viewIndex = 0; viewIndex < matrixCount; ++viewIndex) {
403 if (renderState.isMatrixDirty()) {
404 const QMatrix4x4 m = renderState.combinedMatrix(viewIndex);
405 memcpy(buf->data() + 64 * viewIndex, m.constData(), 64);
406 }
407 }
408
409 if (renderState.isOpacityDirty()) {
410 const float opacity = renderState.opacity();
411 memcpy(buf->data() + 64 * shaderMatrixCount, &opacity, 4);
412 }
413
414 ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
415
416 float entry = float(state->entry);
417 memcpy(buf->data() + 64 * shaderMatrixCount + 4, &entry, 4);
418
419 float timestamp = float(state->timestamp);
420 memcpy(buf->data() + 64 * shaderMatrixCount + 8, &timestamp, 4);
421
422 float dpr = float(state->dpr);
423 memcpy(buf->data() + 64 * shaderMatrixCount + 12, &dpr, 4);
424
425 return true;
426 }
427
428 void updateSampledImage(RenderState &renderState, int binding, QSGTexture **texture,
429 QSGMaterial *newMaterial, QSGMaterial *) override
430 {
431 ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state();
432 if (binding == 1) {
433 state->texture->commitTextureOperations(renderState.rhi(), renderState.resourceUpdateBatch());
434 *texture = state->texture;
435 }
436 }
437};
438
440{
441public:
443 Q_UNUSED(renderMode);
445 }
446 QSGMaterialType *type() const override { return &m_type; }
447
448 ImageMaterialData *state() override { return &m_state; }
449
450private:
451 static QSGMaterialType m_type;
452 ImageMaterialData m_state;
453};
454
455QSGMaterialType SimplePointMaterial::m_type;
456
458{
459 if (img.isNull()){
460 for (int i=0; i<size; i++)
461 array[i] = 1.0;
462 return;
463 }
465 for (int i=0; i<size; i++)
466 array[i] = qAlpha(scaled.pixel(i,0))/255.0;
467}
468
701 : QQuickParticlePainter(parent)
702 , m_color_variation(0.0)
703 , m_outgoingNode(nullptr)
704 , m_material(nullptr)
705 , m_alphaVariation(0.0)
706 , m_alpha(1.0)
707 , m_redVariation(0.0)
708 , m_greenVariation(0.0)
709 , m_blueVariation(0.0)
710 , m_rotation(0)
711 , m_rotationVariation(0)
712 , m_rotationVelocity(0)
713 , m_rotationVelocityVariation(0)
714 , m_autoRotation(false)
715 , m_xVector(nullptr)
716 , m_yVector(nullptr)
717 , m_spriteEngine(nullptr)
718 , m_spritesInterpolate(true)
719 , m_explicitColor(false)
720 , m_explicitRotation(false)
721 , m_explicitDeformation(false)
722 , m_explicitAnimation(false)
723 , m_bypassOptimizations(false)
724 , perfLevel(Unknown)
725 , m_targetPerfLevel(Unknown)
726 , m_debugMode(false)
727 , m_entryEffect(Fade)
728 , m_startedImageLoading(0)
729 , m_rhi(nullptr)
730 , m_apiChecked(false)
731 , m_dpr(1.0)
732 , m_previousActive(false)
733{
735}
736
738{
739 clearShadows();
740}
741
742QQmlListProperty<QQuickSprite> QQuickImageParticle::sprites()
743{
744 return QQmlListProperty<QQuickSprite>(this, &m_sprites,
747}
748
750{
751 m_nodes.clear();
752 m_material = nullptr;
753 delete m_outgoingNode;
754 m_outgoingNode = nullptr;
755 m_apiChecked = false;
756}
757
759{
760 if (image.isEmpty()){
761 if (m_image) {
762 m_image.reset();
764 }
765 return;
766 }
767
768 if (!m_image)
769 m_image.reset(new ImageData);
770 if (image == m_image->source)
771 return;
772 m_image->source = image;
774 reset();
775}
776
777
779{
780 if (table.isEmpty()){
781 if (m_colorTable) {
782 m_colorTable.reset();
784 }
785 return;
786 }
787
788 if (!m_colorTable)
789 m_colorTable.reset(new ImageData);
790 if (table == m_colorTable->source)
791 return;
792 m_colorTable->source = table;
794 reset();
795}
796
798{
799 if (table.isEmpty()){
800 if (m_sizeTable) {
801 m_sizeTable.reset();
803 }
804 return;
805 }
806
807 if (!m_sizeTable)
808 m_sizeTable.reset(new ImageData);
809 if (table == m_sizeTable->source)
810 return;
811 m_sizeTable->source = table;
813 reset();
814}
815
817{
818 if (table.isEmpty()){
819 if (m_opacityTable) {
820 m_opacityTable.reset();
822 }
823 return;
824 }
825
826 if (!m_opacityTable)
827 m_opacityTable.reset(new ImageData);
828 if (table == m_opacityTable->source)
829 return;
830 m_opacityTable->source = table;
832 reset();
833}
834
836{
837 if (color == m_color)
838 return;
839 m_color = color;
841 m_explicitColor = true;
842 checkPerfLevel(ColoredPoint);
843}
844
846{
847 if (var == m_color_variation)
848 return;
849 m_color_variation = var;
851 m_explicitColor = true;
852 checkPerfLevel(ColoredPoint);
853}
854
856{
857 if (m_alphaVariation != arg) {
858 m_alphaVariation = arg;
860 }
861 m_explicitColor = true;
862 checkPerfLevel(ColoredPoint);
863}
864
866{
867 if (m_alpha != arg) {
868 m_alpha = arg;
870 }
871 m_explicitColor = true;
872 checkPerfLevel(ColoredPoint);
873}
874
876{
877 if (m_redVariation != arg) {
878 m_redVariation = arg;
880 }
881 m_explicitColor = true;
882 checkPerfLevel(ColoredPoint);
883}
884
886{
887 if (m_greenVariation != arg) {
888 m_greenVariation = arg;
890 }
891 m_explicitColor = true;
892 checkPerfLevel(ColoredPoint);
893}
894
896{
897 if (m_blueVariation != arg) {
898 m_blueVariation = arg;
900 }
901 m_explicitColor = true;
902 checkPerfLevel(ColoredPoint);
903}
904
906{
907 if (m_rotation != arg) {
908 m_rotation = arg;
910 }
911 m_explicitRotation = true;
912 checkPerfLevel(Deformable);
913}
914
916{
917 if (m_rotationVariation != arg) {
918 m_rotationVariation = arg;
920 }
921 m_explicitRotation = true;
922 checkPerfLevel(Deformable);
923}
924
926{
927 if (m_rotationVelocity != arg) {
928 m_rotationVelocity = arg;
930 }
931 m_explicitRotation = true;
932 checkPerfLevel(Deformable);
933}
934
936{
937 if (m_rotationVelocityVariation != arg) {
938 m_rotationVelocityVariation = arg;
940 }
941 m_explicitRotation = true;
942 checkPerfLevel(Deformable);
943}
944
946{
947 if (m_autoRotation != arg) {
948 m_autoRotation = arg;
950 }
951 m_explicitRotation = true;
952 checkPerfLevel(Deformable);
953}
954
956{
957 if (m_xVector != arg) {
958 m_xVector = arg;
960 }
961 m_explicitDeformation = true;
962 checkPerfLevel(Deformable);
963}
964
966{
967 if (m_yVector != arg) {
968 m_yVector = arg;
970 }
971 m_explicitDeformation = true;
972 checkPerfLevel(Deformable);
973}
974
976{
977 if (m_spritesInterpolate != arg) {
978 m_spritesInterpolate = arg;
980 }
981}
982
984{
985 if (m_bypassOptimizations != arg) {
986 m_bypassOptimizations = arg;
988 }
989 // Applies regardless of perfLevel
990 reset();
991}
992
994{
995 if (m_entryEffect != arg) {
996 m_entryEffect = arg;
997 if (m_material)
998 getState(m_material)->entry = (qreal) m_entryEffect;
1000 }
1001}
1002
1004{
1005 m_explicitColor = false;
1006 for (auto groupId : groupIds()) {
1007 for (QQuickParticleData* d : std::as_const(m_system->groupData[groupId]->data)) {
1008 if (d->colorOwner == this) {
1009 d->colorOwner = nullptr;
1010 }
1011 }
1012 }
1013 m_color = QColor();
1014 m_color_variation = 0.0f;
1015 m_redVariation = 0.0f;
1016 m_blueVariation = 0.0f;
1017 m_greenVariation = 0.0f;
1018 m_alpha = 1.0f;
1019 m_alphaVariation = 0.0f;
1020}
1021
1023{
1024 m_explicitRotation = false;
1025 for (auto groupId : groupIds()) {
1026 for (QQuickParticleData* d : std::as_const(m_system->groupData[groupId]->data)) {
1027 if (d->rotationOwner == this) {
1028 d->rotationOwner = nullptr;
1029 }
1030 }
1031 }
1032 m_rotation = 0;
1033 m_rotationVariation = 0;
1034 m_rotationVelocity = 0;
1035 m_rotationVelocityVariation = 0;
1036 m_autoRotation = false;
1037}
1038
1040{
1041 m_explicitDeformation = false;
1042 for (auto groupId : groupIds()) {
1043 for (QQuickParticleData* d : std::as_const(m_system->groupData[groupId]->data)) {
1044 if (d->deformationOwner == this) {
1045 d->deformationOwner = nullptr;
1046 }
1047 }
1048 }
1049 if (m_xVector)
1050 delete m_xVector;
1051 if (m_yVector)
1052 delete m_yVector;
1053 m_xVector = nullptr;
1054 m_yVector = nullptr;
1055}
1056
1058{
1060 m_pleaseReset = true;
1061 update();
1062}
1063
1064
1065void QQuickImageParticle::invalidateSceneGraph()
1066{
1067 reset();
1068}
1069
1070void QQuickImageParticle::createEngine()
1071{
1072 if (m_spriteEngine)
1073 delete m_spriteEngine;
1074 if (m_sprites.size()) {
1075 m_spriteEngine = new QQuickSpriteEngine(m_sprites, this);
1077 this, &QQuickImageParticle::spriteAdvance, Qt::DirectConnection);
1078 m_explicitAnimation = true;
1079 } else {
1080 m_spriteEngine = nullptr;
1081 m_explicitAnimation = false;
1082 }
1083 reset();
1084}
1085
1091
1093{
1094 3, // Attribute Count
1095 ( 2 + 4 + 4 ) * sizeof(float),
1097};
1098
1105
1107{
1108 4, // Attribute Count
1109 ( 2 + 4 + 4 ) * sizeof(float) + 4 * sizeof(uchar),
1111};
1112
1120
1122{
1123 5, // Attribute Count
1124 ( 2 + 4 + 4 ) * sizeof(float) + (4 + 4) * sizeof(uchar),
1126};
1127
1136
1138{
1139 6, // Attribute Count
1140 (4 + 4 + 4 + 4) * sizeof(float) + (4 + 4) * sizeof(uchar),
1142};
1143
1154
1156{
1157 8, // Attribute Count
1158 (4 + 4 + 4 + 4 + 3 + 3) * sizeof(float) + (4 + 4) * sizeof(uchar),
1160};
1161
1162void QQuickImageParticle::clearShadows()
1163{
1164 foreach (const QVector<QQuickParticleData*> data, m_shadowData)
1166 m_shadowData.clear();
1167}
1168
1169//Only call if you need to, may initialize the whole array first time
1170QQuickParticleData* QQuickImageParticle::getShadowDatum(QQuickParticleData* datum)
1171{
1172 //Will return datum if the datum is a sentinel or uninitialized, to centralize that one check
1173 if (datum->systemIndex == -1)
1174 return datum;
1175 if (!m_shadowData.contains(datum->groupId)) {
1177 QVector<QQuickParticleData*> data;
1178 const int gdSize = gd->size();
1179 data.reserve(gdSize);
1180 for (int i = 0; i < gdSize; i++) {
1182 *datum = *(gd->data[i]);
1183 data << datum;
1184 }
1185 m_shadowData.insert(datum->groupId, data);
1186 }
1187 //### If dynamic resize is added, remember to potentially resize the shadow data on out-of-bounds access request
1188
1189 return m_shadowData[datum->groupId][datum->index];
1190}
1191
1192void QQuickImageParticle::checkPerfLevel(PerformanceLevel level)
1193{
1194 if (m_targetPerfLevel < level) {
1195 m_targetPerfLevel = level;
1196 reset();
1197 }
1198}
1199
1200bool QQuickImageParticle::loadingSomething()
1201{
1202 return (m_image && m_image->pix.isLoading())
1203 || (m_colorTable && m_colorTable->pix.isLoading())
1204 || (m_sizeTable && m_sizeTable->pix.isLoading())
1205 || (m_opacityTable && m_opacityTable->pix.isLoading())
1206 || (m_spriteEngine && m_spriteEngine->isLoading());
1207}
1208
1209void QQuickImageParticle::mainThreadFetchImageData()
1210{
1211 const QQmlContext *context = nullptr;
1212 QQmlEngine *engine = nullptr;
1213 const auto loadPix = [&](ImageData *image) {
1214 if (!engine) {
1215 context = qmlContext(this);
1216 engine = context->engine();
1217 }
1218 image->pix.load(engine, context->resolvedUrl(image->source));
1219 };
1220
1221
1222 if (m_image) {//ImageData created on setSource
1223 m_image->pix.clear(this);
1224 loadPix(m_image.get());
1225 }
1226
1227 if (m_spriteEngine)
1228 m_spriteEngine->startAssemblingImage();
1229
1230 if (m_colorTable)
1231 loadPix(m_colorTable.get());
1232
1233 if (m_sizeTable)
1234 loadPix(m_sizeTable.get());
1235
1236 if (m_opacityTable)
1237 loadPix(m_opacityTable.get());
1238
1239 m_startedImageLoading = 2;
1240}
1241
1243{
1244 // Starts async parts, like loading images, on gui thread
1245 // Not on individual properties, because we delay until system is running
1246 if (*passThrough || loadingSomething())
1247 return;
1248
1249 if (m_startedImageLoading == 0) {
1250 m_startedImageLoading = 1;
1251 //stage 1 is in gui thread
1252 QQuickImageParticle::staticMetaObject.invokeMethod(this, "mainThreadFetchImageData", Qt::QueuedConnection);
1253 } else if (m_startedImageLoading == 2) {
1254 finishBuildParticleNodes(passThrough); //rest happens in render thread
1255 }
1256
1257 //No mutex, because it's slow and a compare that fails due to a race condition means just a dropped frame
1258}
1259
1260void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node)
1261{
1262 if (!m_rhi)
1263 return;
1264
1265 if (m_count * 4 > 0xffff) {
1266 // Index data is ushort.
1267 qmlInfo(this) << "ImageParticle: Too many particles - maximum 16383 per ImageParticle";
1268 return;
1269 }
1270
1271 if (m_count <= 0)
1272 return;
1273
1274 m_debugMode = m_system->m_debugMode;
1275
1276 if (m_sprites.size() || m_bypassOptimizations) {
1277 perfLevel = Sprites;
1278 } else if (m_colorTable || m_sizeTable || m_opacityTable) {
1279 perfLevel = Tabled;
1280 } else if (m_autoRotation || m_rotation || m_rotationVariation
1281 || m_rotationVelocity || m_rotationVelocityVariation
1282 || m_xVector || m_yVector) {
1283 perfLevel = Deformable;
1284 } else if (m_alphaVariation || m_alpha != 1.0 || m_color.isValid() || m_color_variation
1285 || m_redVariation || m_blueVariation || m_greenVariation) {
1286 perfLevel = ColoredPoint;
1287 } else {
1288 perfLevel = SimplePoint;
1289 }
1290
1291 for (auto groupId : groupIds()) {
1292 //For sharing higher levels, need to have highest used so it renders
1293 for (QQuickParticlePainter* p : std::as_const(m_system->groupData[groupId]->painters)) {
1294 QQuickImageParticle* other = qobject_cast<QQuickImageParticle*>(p);
1295 if (other){
1296 if (other->perfLevel > perfLevel) {
1297 if (other->perfLevel >= Tabled){//Deformable is the highest level needed for this, anything higher isn't shared (or requires your own sprite)
1298 if (perfLevel < Deformable)
1299 perfLevel = Deformable;
1300 } else {
1301 perfLevel = other->perfLevel;
1302 }
1303 } else if (other->perfLevel < perfLevel) {
1304 other->reset();
1305 }
1306 }
1307 }
1308 }
1309
1310 // Points with a size other than 1 are an optional feature with QRhi
1311 // because some of the underlying APIs have no support for this.
1312 // Therefore, avoid the point sprite path with APIs like Direct3D.
1313 if (perfLevel < Colored && !m_rhi->isFeatureSupported(QRhi::VertexShaderPointSize))
1314 perfLevel = Colored;
1315
1316 if (perfLevel >= ColoredPoint && !m_color.isValid())
1317 m_color = QColor(Qt::white);//Hidden default, but different from unset
1318
1319 m_targetPerfLevel = perfLevel;
1320
1321 clearShadows();
1322 if (m_material)
1323 m_material = nullptr;
1324
1325 //Setup material
1329 QImage image;
1330 bool imageLoaded = false;
1331 switch (perfLevel) {//Fallthrough intended
1332 case Sprites:
1333 {
1334 if (!m_spriteEngine) {
1335 qWarning() << "ImageParticle: No sprite engine...";
1336 //Sprite performance mode with static image is supported, but not advised
1337 //Note that in this case it always uses shadow data
1338 } else {
1339 image = m_spriteEngine->assembledImage();
1340 if (image.isNull())//Warning is printed in engine
1341 return;
1342 imageLoaded = true;
1343 }
1344 m_material = new SpriteMaterial;
1345 ImageMaterialData *state = getState(m_material);
1346 if (imageLoaded)
1348 state->animSheetSize = QSizeF(image.size() / image.devicePixelRatio());
1349 if (m_spriteEngine)
1350 m_spriteEngine->setCount(m_count);
1351 }
1352 Q_FALLTHROUGH();
1353 case Tabled:
1354 {
1355 if (!m_material)
1356 m_material = new TabledMaterial;
1357
1358 if (m_colorTable) {
1359 if (m_colorTable->pix.isReady())
1360 colortable = m_colorTable->pix.image();
1361 else
1362 qmlWarning(this) << "Error loading color table: " << m_colorTable->pix.error();
1363 }
1364
1365 if (m_sizeTable) {
1366 if (m_sizeTable->pix.isReady())
1367 sizetable = m_sizeTable->pix.image();
1368 else
1369 qmlWarning(this) << "Error loading size table: " << m_sizeTable->pix.error();
1370 }
1371
1372 if (m_opacityTable) {
1373 if (m_opacityTable->pix.isReady())
1374 opacitytable = m_opacityTable->pix.image();
1375 else
1376 qmlWarning(this) << "Error loading opacity table: " << m_opacityTable->pix.error();
1377 }
1378
1379 if (colortable.isNull()){//###Goes through image just for this
1381 colortable.fill(Qt::white);
1382 }
1383 ImageMaterialData *state = getState(m_material);
1387 }
1388 Q_FALLTHROUGH();
1389 case Deformable:
1390 {
1391 if (!m_material)
1392 m_material = new DeformableMaterial;
1393 }
1394 Q_FALLTHROUGH();
1395 case Colored:
1396 {
1397 if (!m_material)
1398 m_material = new ColoredMaterial;
1399 }
1400 Q_FALLTHROUGH();
1401 case ColoredPoint:
1402 {
1403 if (!m_material)
1404 m_material = new ColoredPointMaterial;
1405 }
1406 Q_FALLTHROUGH();
1407 default://Also Simple
1408 {
1409 if (!m_material)
1410 m_material = new SimplePointMaterial;
1411 ImageMaterialData *state = getState(m_material);
1412 if (!imageLoaded) {
1413 if (!m_image || !m_image->pix.isReady()) {
1414 if (m_image)
1415 qmlWarning(this) << m_image->pix.error();
1416 delete m_material;
1417 return;
1418 }
1419 //state->texture //TODO: Shouldn't this be better? But not crash?
1420 // = QQuickItemPrivate::get(this)->sceneGraphContext()->textureForFactory(m_imagePix.textureFactory());
1421 state->texture = QSGPlainTexture::fromImage(m_image->pix.image());
1422 }
1423 state->texture->setFiltering(QSGTexture::Linear);
1424 state->entry = (qreal) m_entryEffect;
1425 state->dpr = m_dpr;
1426
1428 }
1429 }
1430
1431 m_nodes.clear();
1432 for (auto groupId : groupIds()) {
1433 int count = m_system->groupData[groupId]->size();
1434 QSGGeometryNode* node = new QSGGeometryNode();
1435 node->setMaterial(m_material);
1437
1438 m_nodes.insert(groupId, node);
1439 m_idxStarts.insert(groupId, m_lastIdxStart);
1440 m_startsIdx.append(qMakePair(m_lastIdxStart, groupId));
1441 m_lastIdxStart += count;
1442
1443 //Create Particle Geometry
1444 int vCount = count * 4;
1445 int iCount = count * 6;
1446
1447 QSGGeometry *g;
1448 if (perfLevel == Sprites)
1449 g = new QSGGeometry(SpriteParticle_AttributeSet, vCount, iCount);
1450 else if (perfLevel == Tabled)
1451 g = new QSGGeometry(DeformableParticle_AttributeSet, vCount, iCount);
1452 else if (perfLevel == Deformable)
1453 g = new QSGGeometry(DeformableParticle_AttributeSet, vCount, iCount);
1454 else if (perfLevel == Colored)
1455 g = new QSGGeometry(ColoredParticle_AttributeSet, vCount, iCount);
1456 else if (perfLevel == ColoredPoint)
1458 else //Simple
1460
1462 node->setGeometry(g);
1463 if (perfLevel <= ColoredPoint){
1464 g->setDrawingMode(QSGGeometry::DrawPoints);
1465 if (m_debugMode)
1466 qDebug("Using point sprites");
1467 } else {
1468 g->setDrawingMode(QSGGeometry::DrawTriangles);
1469 }
1470
1471 for (int p=0; p < count; ++p)
1472 commit(groupId, p);//commit sets geometry for the node, has its own perfLevel switch
1473
1474 if (perfLevel == Sprites)
1475 initTexCoords<SpriteVertex>((SpriteVertex*)g->vertexData(), vCount);
1476 else if (perfLevel == Tabled)
1477 initTexCoords<DeformableVertex>((DeformableVertex*)g->vertexData(), vCount);
1478 else if (perfLevel == Deformable)
1479 initTexCoords<DeformableVertex>((DeformableVertex*)g->vertexData(), vCount);
1480 else if (perfLevel == Colored)
1481 initTexCoords<ColoredVertex>((ColoredVertex*)g->vertexData(), vCount);
1482
1483 if (perfLevel > ColoredPoint){
1484 quint16 *indices = g->indexDataAsUShort();
1485 for (int i=0; i < count; ++i) {
1486 int o = i * 4;
1487 indices[0] = o;
1488 indices[1] = o + 1;
1489 indices[2] = o + 2;
1490 indices[3] = o + 1;
1491 indices[4] = o + 3;
1492 indices[5] = o + 2;
1493 indices += 6;
1494 }
1495 }
1496 }
1497
1498 if (perfLevel == Sprites)
1499 spritesUpdate();//Gives all vertexes the initial sprite data, then maintained per frame
1500
1501 foreach (QSGGeometryNode* node, m_nodes){
1502 if (node == *(m_nodes.begin()))
1503 node->setFlag(QSGGeometryNode::OwnsMaterial);//Root node owns the material for memory management purposes
1504 else
1505 (*(m_nodes.begin()))->appendChildNode(node);
1506 }
1507
1508 *node = *(m_nodes.begin());
1509 update();
1510}
1511
1513{
1514 if (!m_apiChecked || m_windowChanged) {
1515 m_apiChecked = true;
1516 m_windowChanged = false;
1517
1518 QSGRenderContext *rc = QQuickItemPrivate::get(this)->sceneGraphRenderContext();
1520 if (!rif)
1521 return nullptr;
1522
1523 QSGRendererInterface::GraphicsApi api = rif->graphicsApi();
1524 const bool isRhi = QSGRendererInterface::isApiRhiBased(api);
1525
1526 if (!node && !isRhi)
1527 return nullptr;
1528
1529 if (isRhi)
1530 m_rhi = static_cast<QRhi *>(rif->getResource(m_window, QSGRendererInterface::RhiResource));
1531 else
1532 m_rhi = nullptr;
1533
1534 if (isRhi && !m_rhi) {
1535 qWarning("Failed to query QRhi, particles disabled");
1536 return nullptr;
1537 }
1538 // Get the pixel ratio of the window, used for pointsize scaling
1539 m_dpr = m_window ? m_window->devicePixelRatio() : 1.0;
1540 }
1541
1542 if (m_pleaseReset){
1543 // Cannot just destroy the node and then return null (in case image
1544 // loading is still in progress). Rather, keep track of the old node
1545 // until we have a new one.
1546 delete m_outgoingNode;
1547 m_outgoingNode = node;
1548 node = nullptr;
1549
1550 m_nodes.clear();
1551
1552 m_idxStarts.clear();
1553 m_startsIdx.clear();
1554 m_lastIdxStart = 0;
1555
1556 m_material = nullptr;
1557
1558 m_pleaseReset = false;
1559 m_startedImageLoading = 0;//Cancel a part-way build (may still have a pending load)
1560 } else if (!m_material) {
1561 delete node;
1562 node = nullptr;
1563 }
1564
1565 if (m_system && m_system->isRunning() && !m_system->isPaused()){
1566 bool dirty = prepareNextFrame(&node);
1567 if (node) {
1568 update();
1569 if (dirty) {
1570 foreach (QSGGeometryNode* n, m_nodes)
1571 n->markDirty(QSGNode::DirtyGeometry);
1572 }
1573 } else if (m_startedImageLoading < 2) {
1574 update();//To call prepareNextFrame() again from the renderThread
1575 }
1576 }
1577
1578 if (!node) {
1579 node = m_outgoingNode;
1580 m_outgoingNode = nullptr;
1581 }
1582
1583 return node;
1584}
1585
1587{
1588 if (*node == nullptr){//TODO: Staggered loading (as emitted)
1589 buildParticleNodes(node);
1590 if (m_debugMode) {
1591 qDebug() << "QQuickImageParticle Feature level: " << perfLevel;
1592 qDebug() << "QQuickImageParticle Nodes: ";
1593 int count = 0;
1594 for (auto it = m_nodes.keyBegin(), end = m_nodes.keyEnd(); it != end; ++it) {
1595 qDebug() << "Group " << *it << " (" << m_system->groupData[*it]->size()
1596 << " particles)";
1597 count += m_system->groupData[*it]->size();
1598 }
1599 qDebug() << "Total count: " << count;
1600 }
1601 if (*node == nullptr)
1602 return false;
1603 }
1604 qint64 timeStamp = m_system->systemSync(this);
1605
1606 qreal time = timeStamp / 1000.;
1607
1608 switch (perfLevel){//Fall-through intended
1609 case Sprites:
1610 //Advance State
1611 if (m_spriteEngine)
1612 m_spriteEngine->updateSprites(timeStamp);//fires signals if anim changed
1613 spritesUpdate(time);
1614 Q_FALLTHROUGH();
1615 case Tabled:
1616 case Deformable:
1617 case Colored:
1618 case ColoredPoint:
1619 case SimplePoint:
1620 default: //Also Simple
1621 getState(m_material)->timestamp = time;
1622 break;
1623 }
1624
1625 bool active = false;
1626 for (auto groupId : groupIds()) {
1627 if (m_system->groupData[groupId]->isActive()) {
1628 active = true;
1629 break;
1630 }
1631 }
1632
1633 const bool dirty = active || m_previousActive;
1634 if (dirty) {
1635 foreach (QSGGeometryNode* node, m_nodes)
1637 }
1638
1639 m_previousActive = active;
1640 return dirty;
1641}
1642
1643void QQuickImageParticle::spritesUpdate(qreal time)
1644{
1645 ImageMaterialData *state = getState(m_material);
1646 // Sprite progression handled CPU side, so as to have per-frame control.
1647 for (auto groupId : groupIds()) {
1648 for (QQuickParticleData* mainDatum : std::as_const(m_system->groupData[groupId]->data)) {
1649 QSGGeometryNode *node = m_nodes[groupId];
1650 if (!node)
1651 continue;
1652 //TODO: Interpolate between two different animations if it's going to transition next frame
1653 // This is particularly important for cut-up sprites.
1654 QQuickParticleData* datum = (mainDatum->animationOwner == this ? mainDatum : getShadowDatum(mainDatum));
1655 int spriteIdx = 0;
1656 for (int i = 0; i<m_startsIdx.size(); i++) {
1657 if (m_startsIdx[i].second == groupId){
1658 spriteIdx = m_startsIdx[i].first + datum->index;
1659 break;
1660 }
1661 }
1662
1663 double frameAt;
1664 qreal progress = 0;
1665
1666 if (datum->frameDuration > 0) {
1667 qreal frame = (time - datum->animT)/(datum->frameDuration / 1000.0);
1668 frame = qBound((qreal)0.0, frame, (qreal)((qreal)datum->frameCount - 1.0));//Stop at count-1 frames until we have between anim interpolation
1669 if (m_spritesInterpolate)
1670 progress = std::modf(frame,&frameAt);
1671 else
1672 std::modf(frame,&frameAt);
1673 } else {
1674 datum->frameAt++;
1675 if (datum->frameAt >= datum->frameCount){
1676 datum->frameAt = 0;
1677 m_spriteEngine->advance(spriteIdx);
1678 }
1679 frameAt = datum->frameAt;
1680 }
1681 if (m_spriteEngine->sprite(spriteIdx)->reverse())//### Store this in datum too?
1682 frameAt = (datum->frameCount - 1) - frameAt;
1683 QSizeF sheetSize = state->animSheetSize;
1684 qreal y = datum->animY / sheetSize.height();
1685 qreal w = datum->animWidth / sheetSize.width();
1686 qreal h = datum->animHeight / sheetSize.height();
1687 qreal x1 = datum->animX / sheetSize.width();
1688 x1 += frameAt * w;
1689 qreal x2 = x1;
1690 if (frameAt < (datum->frameCount-1))
1691 x2 += w;
1692
1693 SpriteVertex *spriteVertices = (SpriteVertex *) node->geometry()->vertexData();
1694 spriteVertices += datum->index*4;
1695 for (int i=0; i<4; i++) {
1696 spriteVertices[i].animX1 = x1;
1697 spriteVertices[i].animY1 = y;
1698 spriteVertices[i].animX2 = x2;
1699 spriteVertices[i].animW = w;
1700 spriteVertices[i].animH = h;
1701 spriteVertices[i].animProgress = progress;
1702 }
1703 }
1704 }
1705}
1706
1707void QQuickImageParticle::spriteAdvance(int spriteIdx)
1708{
1709 if (!m_startsIdx.size())//Probably overly defensive
1710 return;
1711
1712 int gIdx = -1;
1713 int i;
1714 for (i = 0; i<m_startsIdx.size(); i++) {
1715 if (spriteIdx < m_startsIdx[i].first) {
1716 gIdx = m_startsIdx[i-1].second;
1717 break;
1718 }
1719 }
1720 if (gIdx == -1)
1721 gIdx = m_startsIdx[i-1].second;
1722 int pIdx = spriteIdx - m_startsIdx[i-1].first;
1723
1724 QQuickParticleData* mainDatum = m_system->groupData[gIdx]->data[pIdx];
1725 QQuickParticleData* datum = (mainDatum->animationOwner == this ? mainDatum : getShadowDatum(mainDatum));
1726
1727 datum->animIdx = m_spriteEngine->spriteState(spriteIdx);
1728 datum->animT = m_spriteEngine->spriteStart(spriteIdx)/1000.0;
1729 datum->frameCount = m_spriteEngine->spriteFrames(spriteIdx);
1730 datum->frameDuration = m_spriteEngine->spriteDuration(spriteIdx) / datum->frameCount;
1731 datum->animX = m_spriteEngine->spriteX(spriteIdx);
1732 datum->animY = m_spriteEngine->spriteY(spriteIdx);
1733 datum->animWidth = m_spriteEngine->spriteWidth(spriteIdx);
1734 datum->animHeight = m_spriteEngine->spriteHeight(spriteIdx);
1735}
1736
1737void QQuickImageParticle::initialize(int gIdx, int pIdx)
1738{
1740 QQuickParticleData* datum = m_system->groupData[gIdx]->data[pIdx];
1741 qreal redVariation = m_color_variation + m_redVariation;
1742 qreal greenVariation = m_color_variation + m_greenVariation;
1743 qreal blueVariation = m_color_variation + m_blueVariation;
1744 int spriteIdx = 0;
1745 if (m_spriteEngine) {
1746 spriteIdx = m_idxStarts[gIdx] + datum->index;
1747 if (spriteIdx >= m_spriteEngine->count())
1748 m_spriteEngine->setCount(spriteIdx+1);
1749 }
1750
1751 float rotation;
1752 float rotationVelocity;
1753 uchar autoRotate;
1754 switch (perfLevel){//Fall-through is intended on all of them
1755 case Sprites:
1756 // Initial Sprite State
1757 if (m_explicitAnimation && m_spriteEngine){
1758 if (!datum->animationOwner)
1759 datum->animationOwner = this;
1760 QQuickParticleData* writeTo = (datum->animationOwner == this ? datum : getShadowDatum(datum));
1761 writeTo->animT = writeTo->t;
1762 //writeTo->animInterpolate = m_spritesInterpolate;
1763 if (m_spriteEngine){
1764 m_spriteEngine->start(spriteIdx);
1765 writeTo->frameCount = m_spriteEngine->spriteFrames(spriteIdx);
1766 writeTo->frameDuration = m_spriteEngine->spriteDuration(spriteIdx) / writeTo->frameCount;
1767 writeTo->animIdx = 0;//Always starts at 0
1768 writeTo->frameAt = -1;
1769 writeTo->animX = m_spriteEngine->spriteX(spriteIdx);
1770 writeTo->animY = m_spriteEngine->spriteY(spriteIdx);
1771 writeTo->animWidth = m_spriteEngine->spriteWidth(spriteIdx);
1772 writeTo->animHeight = m_spriteEngine->spriteHeight(spriteIdx);
1773 }
1774 } else {
1775 ImageMaterialData *state = getState(m_material);
1776 QQuickParticleData* writeTo = getShadowDatum(datum);
1777 writeTo->animT = datum->t;
1778 writeTo->frameCount = 1;
1779 writeTo->frameDuration = 60000000.0;
1780 writeTo->frameAt = -1;
1781 writeTo->animIdx = 0;
1782 writeTo->animT = 0;
1783 writeTo->animX = writeTo->animY = 0;
1784 writeTo->animWidth = state->animSheetSize.width();
1785 writeTo->animHeight = state->animSheetSize.height();
1786 }
1787 Q_FALLTHROUGH();
1788 case Tabled:
1789 case Deformable:
1790 //Initial Rotation
1791 if (m_explicitDeformation){
1792 if (!datum->deformationOwner)
1793 datum->deformationOwner = this;
1794 if (m_xVector){
1795 const QPointF &ret = m_xVector->sample(QPointF(datum->x, datum->y));
1796 if (datum->deformationOwner == this) {
1797 datum->xx = ret.x();
1798 datum->xy = ret.y();
1799 } else {
1800 QQuickParticleData* shadow = getShadowDatum(datum);
1801 shadow->xx = ret.x();
1802 shadow->xy = ret.y();
1803 }
1804 }
1805 if (m_yVector){
1806 const QPointF &ret = m_yVector->sample(QPointF(datum->x, datum->y));
1807 if (datum->deformationOwner == this) {
1808 datum->yx = ret.x();
1809 datum->yy = ret.y();
1810 } else {
1811 QQuickParticleData* shadow = getShadowDatum(datum);
1812 shadow->yx = ret.x();
1813 shadow->yy = ret.y();
1814 }
1815 }
1816 }
1817
1818 if (m_explicitRotation){
1819 if (!datum->rotationOwner)
1820 datum->rotationOwner = this;
1822 m_rotation + (m_rotationVariation
1823 - 2 * QRandomGenerator::global()->bounded(m_rotationVariation)));
1825 m_rotationVelocity
1826 + (m_rotationVelocityVariation
1827 - 2 * QRandomGenerator::global()->bounded(m_rotationVelocityVariation)));
1828 autoRotate = m_autoRotation ? 1 : 0;
1829 if (datum->rotationOwner == this) {
1830 datum->rotation = rotation;
1832 datum->autoRotate = autoRotate;
1833 } else {
1834 QQuickParticleData* shadow = getShadowDatum(datum);
1835 shadow->rotation = rotation;
1837 shadow->autoRotate = autoRotate;
1838 }
1839 }
1840 Q_FALLTHROUGH();
1841 case Colored:
1842 Q_FALLTHROUGH();
1843 case ColoredPoint:
1844 //Color initialization
1845 // Particle color
1846 if (m_explicitColor) {
1847 if (!datum->colorOwner)
1848 datum->colorOwner = this;
1849 const auto rgbColor = m_color.toRgb();
1850 color.r = rgbColor.red() * (1 - redVariation) + QRandomGenerator::global()->bounded(256) * redVariation;
1851 color.g = rgbColor.green() * (1 - greenVariation) + QRandomGenerator::global()->bounded(256) * greenVariation;
1852 color.b = rgbColor.blue() * (1 - blueVariation) + QRandomGenerator::global()->bounded(256) * blueVariation;
1853 color.a = m_alpha * rgbColor.alpha() * (1 - m_alphaVariation) + QRandomGenerator::global()->bounded(256) * m_alphaVariation;
1854 if (datum->colorOwner == this)
1855 datum->color = color;
1856 else
1857 getShadowDatum(datum)->color = color;
1858 }
1859 break;
1860 default:
1861 break;
1862 }
1863}
1864
1865void QQuickImageParticle::commit(int gIdx, int pIdx)
1866{
1867 if (m_pleaseReset)
1868 return;
1869 QSGGeometryNode *node = m_nodes[gIdx];
1870 if (!node)
1871 return;
1872 QQuickParticleData* datum = m_system->groupData[gIdx]->data[pIdx];
1873 SpriteVertex *spriteVertices = (SpriteVertex *) node->geometry()->vertexData();
1874 DeformableVertex *deformableVertices = (DeformableVertex *) node->geometry()->vertexData();
1875 ColoredVertex *coloredVertices = (ColoredVertex *) node->geometry()->vertexData();
1876 ColoredPointVertex *coloredPointVertices = (ColoredPointVertex *) node->geometry()->vertexData();
1877 SimplePointVertex *simplePointVertices = (SimplePointVertex *) node->geometry()->vertexData();
1878 switch (perfLevel){//No automatic fall through intended on this one
1879 case Sprites:
1880 spriteVertices += pIdx*4;
1881 for (int i=0; i<4; i++){
1882 spriteVertices[i].x = datum->x - m_systemOffset.x();
1883 spriteVertices[i].y = datum->y - m_systemOffset.y();
1884 spriteVertices[i].t = datum->t;
1885 spriteVertices[i].lifeSpan = datum->lifeSpan;
1886 spriteVertices[i].size = datum->size;
1887 spriteVertices[i].endSize = datum->endSize;
1888 spriteVertices[i].vx = datum->vx;
1889 spriteVertices[i].vy = datum->vy;
1890 spriteVertices[i].ax = datum->ax;
1891 spriteVertices[i].ay = datum->ay;
1892 if (m_explicitDeformation && datum->deformationOwner != this) {
1893 QQuickParticleData* shadow = getShadowDatum(datum);
1894 spriteVertices[i].xx = shadow->xx;
1895 spriteVertices[i].xy = shadow->xy;
1896 spriteVertices[i].yx = shadow->yx;
1897 spriteVertices[i].yy = shadow->yy;
1898 } else {
1899 spriteVertices[i].xx = datum->xx;
1900 spriteVertices[i].xy = datum->xy;
1901 spriteVertices[i].yx = datum->yx;
1902 spriteVertices[i].yy = datum->yy;
1903 }
1904 if (m_explicitRotation && datum->rotationOwner != this) {
1905 QQuickParticleData* shadow = getShadowDatum(datum);
1906 spriteVertices[i].rotation = shadow->rotation;
1907 spriteVertices[i].rotationVelocity = shadow->rotationVelocity;
1908 spriteVertices[i].autoRotate = shadow->autoRotate;
1909 } else {
1910 spriteVertices[i].rotation = datum->rotation;
1911 spriteVertices[i].rotationVelocity = datum->rotationVelocity;
1912 spriteVertices[i].autoRotate = datum->autoRotate;
1913 }
1914 //Sprite-related vertices updated per-frame in spritesUpdate(), not on demand
1915 if (m_explicitColor && datum->colorOwner != this) {
1916 QQuickParticleData* shadow = getShadowDatum(datum);
1917 spriteVertices[i].color = shadow->color;
1918 } else {
1919 spriteVertices[i].color = datum->color;
1920 }
1921 }
1922 break;
1923 case Tabled: //Fall through until it has its own vertex class
1924 case Deformable:
1925 deformableVertices += pIdx*4;
1926 for (int i=0; i<4; i++){
1927 deformableVertices[i].x = datum->x - m_systemOffset.x();
1928 deformableVertices[i].y = datum->y - m_systemOffset.y();
1929 deformableVertices[i].t = datum->t;
1930 deformableVertices[i].lifeSpan = datum->lifeSpan;
1931 deformableVertices[i].size = datum->size;
1932 deformableVertices[i].endSize = datum->endSize;
1933 deformableVertices[i].vx = datum->vx;
1934 deformableVertices[i].vy = datum->vy;
1935 deformableVertices[i].ax = datum->ax;
1936 deformableVertices[i].ay = datum->ay;
1937 if (m_explicitDeformation && datum->deformationOwner != this) {
1938 QQuickParticleData* shadow = getShadowDatum(datum);
1939 deformableVertices[i].xx = shadow->xx;
1940 deformableVertices[i].xy = shadow->xy;
1941 deformableVertices[i].yx = shadow->yx;
1942 deformableVertices[i].yy = shadow->yy;
1943 } else {
1944 deformableVertices[i].xx = datum->xx;
1945 deformableVertices[i].xy = datum->xy;
1946 deformableVertices[i].yx = datum->yx;
1947 deformableVertices[i].yy = datum->yy;
1948 }
1949 if (m_explicitRotation && datum->rotationOwner != this) {
1950 QQuickParticleData* shadow = getShadowDatum(datum);
1951 deformableVertices[i].rotation = shadow->rotation;
1952 deformableVertices[i].rotationVelocity = shadow->rotationVelocity;
1953 deformableVertices[i].autoRotate = shadow->autoRotate;
1954 } else {
1955 deformableVertices[i].rotation = datum->rotation;
1956 deformableVertices[i].rotationVelocity = datum->rotationVelocity;
1957 deformableVertices[i].autoRotate = datum->autoRotate;
1958 }
1959 if (m_explicitColor && datum->colorOwner != this) {
1960 QQuickParticleData* shadow = getShadowDatum(datum);
1961 deformableVertices[i].color = shadow->color;
1962 } else {
1963 deformableVertices[i].color = datum->color;
1964 }
1965 }
1966 break;
1967 case Colored:
1968 coloredVertices += pIdx*4;
1969 for (int i=0; i<4; i++){
1970 coloredVertices[i].x = datum->x - m_systemOffset.x();
1971 coloredVertices[i].y = datum->y - m_systemOffset.y();
1972 coloredVertices[i].t = datum->t;
1973 coloredVertices[i].lifeSpan = datum->lifeSpan;
1974 coloredVertices[i].size = datum->size;
1975 coloredVertices[i].endSize = datum->endSize;
1976 coloredVertices[i].vx = datum->vx;
1977 coloredVertices[i].vy = datum->vy;
1978 coloredVertices[i].ax = datum->ax;
1979 coloredVertices[i].ay = datum->ay;
1980 if (m_explicitColor && datum->colorOwner != this) {
1981 QQuickParticleData* shadow = getShadowDatum(datum);
1982 coloredVertices[i].color = shadow->color;
1983 } else {
1984 coloredVertices[i].color = datum->color;
1985 }
1986 }
1987 break;
1988 case ColoredPoint:
1989 coloredPointVertices += pIdx*1;
1990 for (int i=0; i<1; i++){
1991 coloredPointVertices[i].x = datum->x - m_systemOffset.x();
1992 coloredPointVertices[i].y = datum->y - m_systemOffset.y();
1993 coloredPointVertices[i].t = datum->t;
1994 coloredPointVertices[i].lifeSpan = datum->lifeSpan;
1995 coloredPointVertices[i].size = datum->size;
1996 coloredPointVertices[i].endSize = datum->endSize;
1997 coloredPointVertices[i].vx = datum->vx;
1998 coloredPointVertices[i].vy = datum->vy;
1999 coloredPointVertices[i].ax = datum->ax;
2000 coloredPointVertices[i].ay = datum->ay;
2001 if (m_explicitColor && datum->colorOwner != this) {
2002 QQuickParticleData* shadow = getShadowDatum(datum);
2003 coloredPointVertices[i].color = shadow->color;
2004 } else {
2005 coloredPointVertices[i].color = datum->color;
2006 }
2007 }
2008 break;
2009 case SimplePoint:
2010 simplePointVertices += pIdx*1;
2011 for (int i=0; i<1; i++){
2012 simplePointVertices[i].x = datum->x - m_systemOffset.x();
2013 simplePointVertices[i].y = datum->y - m_systemOffset.y();
2014 simplePointVertices[i].t = datum->t;
2015 simplePointVertices[i].lifeSpan = datum->lifeSpan;
2016 simplePointVertices[i].size = datum->size;
2017 simplePointVertices[i].endSize = datum->endSize;
2018 simplePointVertices[i].vx = datum->vx;
2019 simplePointVertices[i].vy = datum->vy;
2020 simplePointVertices[i].ax = datum->ax;
2021 simplePointVertices[i].ay = datum->ay;
2022 }
2023 break;
2024 default:
2025 break;
2026 }
2027}
2028
2029
2030
2032
2033#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
int red() const noexcept
Returns the red color component of this color.
Definition qcolor.cpp:1528
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:1221
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
Definition qhash.h:1212
key_iterator keyBegin() const noexcept
Definition qhash.h:1220
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:951
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1303
\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:209
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:2493
@ Format_ARGB32_Premultiplied
Definition qimage.h:48
qsizetype size() const noexcept
Definition qlist.h:397
T & first()
Definition qlist.h:645
void append(parameter_type t)
Definition qlist.h:458
void clear()
Definition qlist.h:434
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:2960
\inmodule QtCore\reentrant
Definition qpoint.h:217
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:343
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:348
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
virtual QPointF sample(const QPointF &from)
void sceneGraphInvalidated() override
QQmlListProperty< QQuickSprite > sprites
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)
static QQuickItemPrivate * get(QQuickItem *item)
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:63
void rotationChanged()
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:73
void update()
Schedules a call to updatePaintNode() for this item.
QQuickImageParticle * deformationOwner
QQuickImageParticle * colorOwner
QQuickParticleGroupData::ID groupId
QQuickImageParticle * animationOwner
QQuickImageParticle * rotationOwner
const GroupIDs & groupIds() const
QQuickParticleSystem * m_system
QVarLengthArray< QQuickParticleGroupData *, 32 > groupData
int systemSync(QQuickParticlePainter *p)
QImage image() const
QString error() const
bool isLoading() const
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 stateChanged(int idx)
void start(int index=0, int state=0)
static Q_DECL_CONST_FUNCTION QRandomGenerator * global()
\threadsafe
Definition qrandom.h:275
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
Definition qrhi.h:1804
@ VertexShaderPointSize
Definition qrhi.h:1846
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:764
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:188
void setMaterial(QSGMaterial *material)
Sets the material of this geometry node to material.
Definition qsgnode.cpp:927
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 ...
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
int viewCount() const
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:624
void setFlag(Flag, bool=true)
Sets the flag f on this node if enabled is true; otherwise clears the flag.
Definition qsgnode.cpp:586
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)
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:208
\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:31
@ QueuedConnection
@ DirectConnection
Definition image.cpp:4
static void * context
#define Q_FALLTHROUGH()
#define qDebug
[1]
Definition qlogging.h:164
#define qWarning
Definition qlogging.h:166
return ret
constexpr float qDegreesToRadians(float degrees)
Definition qmath.h:260
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qBound(const T &min, const T &val, const T &max)
Definition qminmax.h:44
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
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint color
[2]
GLenum GLuint GLenum GLsizei const GLchar * buf
GLenum GLuint texture
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
QT_BEGIN_NAMESPACE 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:75
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:32
unsigned short quint16
Definition qtypes.h:48
long long qint64
Definition qtypes.h:60
double qreal
Definition qtypes.h:187
QImage scaled(const QImage &image)
[0]
QObject::connect nullptr
QSharedPointer< T > other(t)
[5]
QFrame frame
[0]
QNetworkRequestFactory api
[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.