9#if QT_CONFIG(concurrent)
10#include <QtConcurrentRun>
16
17
18
19
20
21
22
23
24
25
28
29
30
33
34
35
39
40
41
44
45
46
47
48
49
50
51
52
53
56
57
58
59
60
61
62
65
66
67
70
71
72
73
76
77
78
79
80
81
82
83
84
85
87PlaneGeometry::PlaneGeometry(QQuick3DObject *parent)
88 : QQuick3DGeometry(parent)
90#if QT_CONFIG(concurrent)
91 connect(&m_geometryDataWatcher, &QFutureWatcher<GeometryData>::finished,
this, &PlaneGeometry::requestFinished);
93 scheduleGeometryUpdate();
96PlaneGeometry::~PlaneGeometry()
101float PlaneGeometry::width()
const
106void PlaneGeometry::setWidth(
float newWidth)
108 if (qFuzzyCompare(m_width, newWidth))
112 scheduleGeometryUpdate();
115float PlaneGeometry::height()
const
120void PlaneGeometry::setHeight(
float newHeight)
122 if (qFuzzyCompare(m_height, newHeight))
124 m_height = newHeight;
125 emit heightChanged();
126 scheduleGeometryUpdate();
129QSize PlaneGeometry::meshResolution()
const
131 return m_meshResolution;
134void PlaneGeometry::setMeshResolution(
const QSize &newMeshResolution)
136 if (m_meshResolution == newMeshResolution)
138 m_meshResolution = newMeshResolution;
139 emit meshResolutionChanged();
140 scheduleGeometryUpdate();
143PlaneGeometry::Plane PlaneGeometry::plane()
const
148void PlaneGeometry::setPlane(Plane newPlane)
150 if (m_plane == newPlane)
154 scheduleGeometryUpdate();
157bool PlaneGeometry::reversed()
const
162void PlaneGeometry::setReversed(
bool newReversed)
164 if (m_reversed == newReversed)
166 m_reversed = newReversed;
167 emit reversedChanged();
168 scheduleGeometryUpdate();
171bool PlaneGeometry::mirrored()
const
176void PlaneGeometry::setMirrored(
bool newMirrored)
178 if (m_mirrored == newMirrored)
180 m_mirrored = newMirrored;
181 emit mirroredChanged();
182 scheduleGeometryUpdate();
185bool PlaneGeometry::asynchronous()
const
187 return m_asynchronous;
190void PlaneGeometry::setAsynchronous(
bool newAsynchronous)
192 if (m_asynchronous == newAsynchronous)
194 m_asynchronous = newAsynchronous;
195 emit asynchronousChanged();
198PlaneGeometry::Status PlaneGeometry::status()
const
203void PlaneGeometry::doUpdateGeometry()
206 m_geometryUpdateRequested =
false;
208#if QT_CONFIG(concurrent)
209 if (m_geometryDataFuture.isRunning()) {
210 m_pendingAsyncUpdate =
true;
216 if (m_width <= 0 || m_height <= 0 || m_meshResolution.width() <= 0 || m_meshResolution.height() <= 0) {
222#if QT_CONFIG(concurrent)
224 if (m_asynchronous && QT_CONFIG(thread)) {
225 m_geometryDataFuture = QtConcurrent::run(generatePlaneGeometryAsync,
232 m_geometryDataWatcher.setFuture(m_geometryDataFuture);
233 m_status = Status::Loading;
234 Q_EMIT statusChanged();
240 updateGeometry(generatePlaneGeometry(m_width, m_height, m_meshResolution, m_plane, m_reversed, m_mirrored));
244void PlaneGeometry::requestFinished()
246#if QT_CONFIG(concurrent)
247 const auto output = m_geometryDataFuture.takeResult();
248 updateGeometry(output);
252void PlaneGeometry::scheduleGeometryUpdate()
254 if (!m_geometryUpdateRequested) {
255 QMetaObject::invokeMethod(
this,
"doUpdateGeometry", Qt::QueuedConnection);
256 m_geometryUpdateRequested =
true;
260void PlaneGeometry::updateGeometry(
const GeometryData &geometryData)
263 setStride(
sizeof(
float) * 8);
264 setPrimitiveType(QQuick3DGeometry::PrimitiveType::Triangles);
265 addAttribute(QQuick3DGeometry::Attribute::PositionSemantic,
267 QQuick3DGeometry::Attribute::F32Type);
268 addAttribute(QQuick3DGeometry::Attribute::TexCoord0Semantic,
270 QQuick3DGeometry::Attribute::F32Type);
271 addAttribute(QQuick3DGeometry::Attribute::NormalSemantic,
273 QQuick3DGeometry::Attribute::F32Type);
274 addAttribute(QQuick3DGeometry::Attribute::IndexSemantic,
276 QQuick3DGeometry::Attribute::U16Type);
278 setBounds(geometryData.boundsMin, geometryData.boundsMax);
279 setVertexData(geometryData.vertexData);
280 setIndexData(geometryData.indexData);
284 if (m_pendingAsyncUpdate) {
285 m_pendingAsyncUpdate =
false;
286 scheduleGeometryUpdate();
288 m_status = Status::Ready;
289 Q_EMIT statusChanged();
292 emit geometryChanged();
295PlaneGeometry::GeometryData PlaneGeometry::generatePlaneGeometry(
float width,
float height, QSize meshResolution, Plane plane,
bool reversed,
bool mirrored)
297 GeometryData geometryData;
299 int quadsX = meshResolution.width();
300 int quadsY = meshResolution.height();
302 const int numVertices = (quadsX + 1) * (quadsY + 1);
303 const int numIndices = quadsX * quadsY * 6;
305 const int vertexStride =
sizeof(
float) * (3 + 2 + 3);
306 const int indexStride =
sizeof(uint16_t);
308 geometryData.vertexData.resize(numVertices * vertexStride);
309 geometryData.indexData.resize(numIndices * indexStride);
311 QVector3D boundsMin(std::numeric_limits<
float>::max(),
312 std::numeric_limits<
float>::max(),
313 std::numeric_limits<
float>::max());
315 QVector3D boundsMax(std::numeric_limits<
float>::lowest(),
316 std::numeric_limits<
float>::lowest(),
317 std::numeric_limits<
float>::lowest());
319 float* vertexPtr =
reinterpret_cast<
float*>(geometryData.vertexData.data());
320 uint16_t* indexPtr =
reinterpret_cast<uint16_t*>(geometryData.indexData.data());
325 normal = QVector3D(0, 0, 1);
328 normal = QVector3D(0, 1, 0);
331 normal = QVector3D(1, 0, 0);
339 for (
int y = 0; y <= quadsY; ++y) {
340 for (
int x = 0; x <= quadsX; ++x) {
342 float u =
static_cast<
float>(x) / quadsX;
343 float v =
static_cast<
float>(y) / quadsY;
346 float posX = width * (u - 0.5f);
347 float posY = height * (v - 0.5f);
359 position = QVector3D(posX, posY, 0.0f);
362 position = QVector3D(posX, 0.0f, -posY);
365 position = QVector3D(0.0f, posY, -posX);
370 *vertexPtr++ = position.x();
371 *vertexPtr++ = position.y();
372 *vertexPtr++ = position.z();
379 *vertexPtr++ = normal.x();
380 *vertexPtr++ = normal.y();
381 *vertexPtr++ = normal.z();
384 boundsMin.setX(std::min(boundsMin.x(), position.x()));
385 boundsMin.setY(std::min(boundsMin.y(), position.y()));
386 boundsMin.setZ(std::min(boundsMin.z(), position.z()));
388 boundsMax.setX(std::max(boundsMax.x(), position.x()));
389 boundsMax.setY(std::max(boundsMax.y(), position.y()));
390 boundsMax.setZ(std::max(boundsMax.z(), position.z()));
395 for (
int y = 0; y < quadsY; ++y) {
396 for (
int x = 0; x < quadsX; ++x) {
397 uint16_t a =
static_cast<uint16_t>(y * (quadsX + 1) + x);
398 uint16_t b =
static_cast<uint16_t>(a + quadsX + 1);
399 uint16_t c =
static_cast<uint16_t>(b + 1);
400 uint16_t d =
static_cast<uint16_t>(a + 1);
425 geometryData.boundsMax = boundsMax;
426 geometryData.boundsMin = boundsMin;
431#if QT_CONFIG(concurrent)
432void PlaneGeometry::generatePlaneGeometryAsync(QPromise<PlaneGeometry::GeometryData> &promise,
435 QSize meshResolution,
440 auto output = generatePlaneGeometry(width, height, meshResolution, plane, reversed, mirrored);
441 promise.addResult(output);