6#include <QtQuick3D/private/qquick3dobject_p.h>
8#include <QtQuick/QQuickWindow>
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
94
95
96
97
100
101
102
105
106
107
110
111
112
115
116
117
120
121
122
125
126
127
130
131
132
135
136
137
140
141
142
143
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
163
164
165
166
167
168
169
170
171
172
173
176
177
178
179
180
181
182
183
184
185
186
187
190
191
192
195
196
197
198
199
202
203
204
205
207ProceduralMesh::ProceduralMesh()
212QList<QVector3D> ProceduralMesh::positions()
const
217void ProceduralMesh::setPositions(
const QList<QVector3D> &newPositions)
219 if (m_positions == newPositions)
221 m_positions = newPositions;
222 Q_EMIT positionsChanged();
226ProceduralMesh::PrimitiveMode ProceduralMesh::primitiveMode()
const
228 return m_primitiveMode;
231void ProceduralMesh::setPrimitiveMode(PrimitiveMode newPrimitiveMode)
233 if (m_primitiveMode == newPrimitiveMode)
237 if (newPrimitiveMode < Points || newPrimitiveMode > Triangles) {
238 qWarning() <<
"Invalid primitive mode specified";
242 if (newPrimitiveMode == PrimitiveMode::TriangleFan) {
243 if (!supportsTriangleFanPrimitive()) {
244 qWarning() <<
"TriangleFan is not supported by the current backend";
249 m_primitiveMode = newPrimitiveMode;
250 Q_EMIT primitiveModeChanged();
254void ProceduralMesh::requestUpdate()
256 if (!m_updateRequested) {
257 QMetaObject::invokeMethod(
this,
"updateGeometry", Qt::QueuedConnection);
258 m_updateRequested =
true;
262void ProceduralMesh::updateGeometry()
264 m_updateRequested =
false;
268 setPrimitiveType(PrimitiveType(m_primitiveMode));
271 const auto expectedLength = m_positions.size();
272 bool hasPositions = !m_positions.isEmpty();
278 bool hasNormals = m_normals.size() >= expectedLength;
279 bool hasTangents = m_tangents.size() >= expectedLength;
280 bool hasBinormals = m_binormals.size() >= expectedLength;
281 bool hasUV0s = m_uv0s.size() >= expectedLength;
282 bool hasUV1s = m_uv1s.size() >= expectedLength;
283 bool hasColors = m_colors.size() >= expectedLength;
284 bool hasJoints = m_joints.size() >= expectedLength;
285 bool hasWeights = m_weights.size() >= expectedLength;
286 bool hasIndexes = !m_indexes.isEmpty();
290 addAttribute(Attribute::Semantic::PositionSemantic, offset, Attribute::ComponentType::F32Type);
291 offset += 3 *
sizeof(
float);
295 addAttribute(Attribute::Semantic::NormalSemantic, offset, Attribute::ComponentType::F32Type);
296 offset += 3 *
sizeof(
float);
300 addAttribute(Attribute::Semantic::TangentSemantic, offset, Attribute::ComponentType::F32Type);
301 offset += 3 *
sizeof(
float);
305 addAttribute(Attribute::Semantic::BinormalSemantic, offset, Attribute::ComponentType::F32Type);
306 offset += 3 *
sizeof(
float);
310 addAttribute(Attribute::Semantic::TexCoord0Semantic, offset, Attribute::ComponentType::F32Type);
311 offset += 2 *
sizeof(
float);
315 addAttribute(Attribute::Semantic::TexCoord1Semantic, offset, Attribute::ComponentType::F32Type);
316 offset += 2 *
sizeof(
float);
320 addAttribute(Attribute::Semantic::ColorSemantic, offset, Attribute::ComponentType::F32Type);
321 offset += 4 *
sizeof(
float);
325 addAttribute(Attribute::Semantic::JointSemantic, offset, Attribute::ComponentType::F32Type);
326 offset += 4 *
sizeof(
float);
330 addAttribute(Attribute::Semantic::WeightSemantic, offset, Attribute::ComponentType::F32Type);
331 offset += 4 *
sizeof(
float);
335 addAttribute(Attribute::Semantic::IndexSemantic, 0, Attribute::ComponentType::U32Type);
338 const int stride = offset;
339 const qsizetype bufferSize = expectedLength * stride;
342 QVector<
float> vertexBufferData;
343 vertexBufferData.reserve(bufferSize /
sizeof(
float));
348 for (qsizetype i = 0; i < expectedLength; ++i) {
351 const auto &position = m_positions[i];
352 vertexBufferData.append(position.x());
353 vertexBufferData.append(position.y());
354 vertexBufferData.append(position.z());
355 minBounds.setX(qMin(minBounds.x(), position.x()));
356 maxBounds.setX(qMax(maxBounds.x(), position.x()));
357 minBounds.setY(qMin(minBounds.y(), position.y()));
358 maxBounds.setY(qMax(maxBounds.y(), position.y()));
359 minBounds.setZ(qMin(minBounds.z(), position.z()));
360 maxBounds.setZ(qMax(maxBounds.z(), position.z()));
363 const auto &normal = m_normals[i];
364 vertexBufferData.append(normal.x());
365 vertexBufferData.append(normal.y());
366 vertexBufferData.append(normal.z());
370 const auto &binormal = m_binormals[i];
371 vertexBufferData.append(binormal.x());
372 vertexBufferData.append(binormal.y());
373 vertexBufferData.append(binormal.z());
377 const auto &tangent = m_tangents[i];
378 vertexBufferData.append(tangent.x());
379 vertexBufferData.append(tangent.y());
380 vertexBufferData.append(tangent.z());
384 const auto &uv0 = m_uv0s[i];
385 vertexBufferData.append(uv0.x());
386 vertexBufferData.append(uv0.y());
390 const auto &uv1 = m_uv1s[i];
391 vertexBufferData.append(uv1.x());
392 vertexBufferData.append(uv1.y());
396 const auto &color = m_colors[i];
397 vertexBufferData.append(color.x());
398 vertexBufferData.append(color.y());
399 vertexBufferData.append(color.z());
400 vertexBufferData.append(color.w());
404 const auto &joint = m_joints[i];
405 vertexBufferData.append(joint.x());
406 vertexBufferData.append(joint.y());
407 vertexBufferData.append(joint.z());
408 vertexBufferData.append(joint.w());
412 const auto &weight = m_weights[i];
413 vertexBufferData.append(weight.x());
414 vertexBufferData.append(weight.y());
415 vertexBufferData.append(weight.z());
416 vertexBufferData.append(weight.w());
420 setBounds(minBounds, maxBounds);
421 QByteArray vertexBuffer(
reinterpret_cast<
char *>(vertexBufferData.data()), bufferSize);
422 setVertexData(vertexBuffer);
426 const qsizetype indexLength = m_indexes.size();
427 QByteArray indexBuffer;
428 indexBuffer.reserve(indexLength *
sizeof(
unsigned int));
429 for (qsizetype i = 0; i < indexLength; ++i) {
430 const auto &index = m_indexes[i];
431 indexBuffer.append(
reinterpret_cast<
const char *>(&index),
sizeof(
unsigned int));
433 setIndexData(indexBuffer);
438 if (!m_subsets.isEmpty()) {
439 for (
const auto &subset : m_subsets) {
440 QVector3D subsetMinBounds;
441 QVector3D subsetMaxBounds;
444 bool outOfRange =
false;
445 for (qsizetype i = subset->offset(); i < subset->offset() + subset->count(); ++i) {
449 if (i < m_indexes.size()) {
450 index = m_indexes[i];
456 if (index < m_positions.size()) {
457 const auto &position = m_positions[index];
458 subsetMinBounds.setX(qMin(subsetMinBounds.x(), position.x()));
459 subsetMaxBounds.setX(qMax(subsetMaxBounds.x(), position.x()));
460 subsetMinBounds.setY(qMin(subsetMinBounds.y(), position.y()));
461 subsetMaxBounds.setY(qMax(subsetMaxBounds.y(), position.y()));
462 subsetMinBounds.setZ(qMin(subsetMinBounds.z(), position.z()));
463 subsetMaxBounds.setZ(qMax(subsetMaxBounds.z(), position.z()));
471 addSubset(subset->offset(), subset->count(), subsetMinBounds, subsetMaxBounds, subset->name());
473 qWarning(
"Skipping invalid subset: Out of Range");
480void ProceduralMesh::subsetDestroyed(QObject *subset)
482 if (m_subsets.removeAll(subset))
486bool ProceduralMesh::supportsTriangleFanPrimitive()
const
488 static bool supportQueried =
false;
489 static bool triangleFanSupported =
false;
490 if (!supportQueried) {
491 const auto &manager = QQuick3DObjectPrivate::get(
this)->sceneManager;
493 auto window = manager->window();
495 auto rhi = window->rhi();
497 triangleFanSupported = rhi->isFeatureSupported(QRhi::TriangleFanTopology);
498 supportQueried =
true;
504 return triangleFanSupported;
507void ProceduralMesh::qmlAppendProceduralMeshSubset(QQmlListProperty<ProceduralMeshSubset> *list, ProceduralMeshSubset *subset)
509 if (subset ==
nullptr)
511 ProceduralMesh *self =
static_cast<ProceduralMesh *>(list->object);
512 self->m_subsets.push_back(subset);
514 connect(subset, &ProceduralMeshSubset::isDirty, self, &ProceduralMesh::requestUpdate);
515 connect(subset, &QObject::destroyed, self, &ProceduralMesh::subsetDestroyed);
517 self->requestUpdate();
520ProceduralMeshSubset *ProceduralMesh::qmlProceduralMeshSubsetAt(QQmlListProperty<ProceduralMeshSubset> *list, qsizetype index)
522 ProceduralMesh *self =
static_cast<ProceduralMesh *>(list->object);
523 return self->m_subsets.at(index);
527qsizetype ProceduralMesh::qmlProceduralMeshSubsetCount(QQmlListProperty<ProceduralMeshSubset> *list)
529 ProceduralMesh *self =
static_cast<ProceduralMesh *>(list->object);
530 return self->m_subsets.count();
533void ProceduralMesh::qmlClearProceduralMeshSubset(QQmlListProperty<ProceduralMeshSubset> *list)
535 ProceduralMesh *self =
static_cast<ProceduralMesh *>(list->object);
536 self->m_subsets.clear();
537 self->requestUpdate();
540QList<
unsigned int> ProceduralMesh::indexes()
const
545void ProceduralMesh::setIndexes(
const QList<
unsigned int> &newIndexes)
547 if (m_indexes == newIndexes)
549 m_indexes = newIndexes;
550 Q_EMIT indexesChanged();
554QList<QVector3D> ProceduralMesh::normals()
const
559void ProceduralMesh::setNormals(
const QList<QVector3D> &newNormals)
561 if (m_normals == newNormals)
563 m_normals = newNormals;
564 Q_EMIT normalsChanged();
568QList<QVector3D> ProceduralMesh::tangents()
const
573void ProceduralMesh::setTangents(
const QList<QVector3D> &newTangents)
575 if (m_tangents == newTangents)
577 m_tangents = newTangents;
578 Q_EMIT tangentsChanged();
582QList<QVector3D> ProceduralMesh::binormals()
const
587void ProceduralMesh::setBinormals(
const QList<QVector3D> &newBinormals)
589 if (m_binormals == newBinormals)
591 m_binormals = newBinormals;
592 Q_EMIT binormalsChanged();
596QList<QVector2D> ProceduralMesh::uv0s()
const
601void ProceduralMesh::setUv0s(
const QList<QVector2D> &newUv0s)
603 if (m_uv0s == newUv0s)
606 Q_EMIT uv0sChanged();
610QList<QVector2D> ProceduralMesh::uv1s()
const
615void ProceduralMesh::setUv1s(
const QList<QVector2D> &newUv1s)
617 if (m_uv1s == newUv1s)
620 Q_EMIT uv1sChanged();
624QList<QVector4D> ProceduralMesh::colors()
const
629void ProceduralMesh::setColors(
const QList<QVector4D> &newColors)
631 if (m_colors == newColors)
633 m_colors = newColors;
634 Q_EMIT colorsChanged();
638QList<QVector4D> ProceduralMesh::joints()
const
643void ProceduralMesh::setJoints(
const QList<QVector4D> &newJoints)
645 if (m_joints == newJoints)
647 m_joints = newJoints;
648 Q_EMIT jointsChanged();
652QList<QVector4D> ProceduralMesh::weights()
const
657void ProceduralMesh::setWeights(
const QList<QVector4D> &newWeights)
659 if (m_weights == newWeights)
661 m_weights = newWeights;
662 Q_EMIT weightsChanged();
666QQmlListProperty<ProceduralMeshSubset> ProceduralMesh::subsets()
668 return QQmlListProperty<ProceduralMeshSubset>(
this,
670 ProceduralMesh::qmlAppendProceduralMeshSubset,
671 ProceduralMesh::qmlProceduralMeshSubsetCount,
672 ProceduralMesh::qmlProceduralMeshSubsetAt,
673 ProceduralMesh::qmlClearProceduralMeshSubset);
676int ProceduralMeshSubset::offset()
const
681void ProceduralMeshSubset::setOffset(
int newOffset)
683 if (m_offset == newOffset)
686 m_offset = newOffset;
687 Q_EMIT offsetChanged();
691int ProceduralMeshSubset::count()
const
696void ProceduralMeshSubset::setCount(
int newCount)
698 if (m_count == newCount)
702 Q_EMIT countChanged();
706QString ProceduralMeshSubset::name()
const
711void ProceduralMeshSubset::setName(
const QString &newName)
713 if (m_name == newName)
717 Q_EMIT nameChanged();