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)
223 if (m_asynchronous) {
224 m_geometryDataFuture = QtConcurrent::run(generatePlaneGeometryAsync,
231 m_geometryDataWatcher.setFuture(m_geometryDataFuture);
232 m_status = Status::Loading;
233 Q_EMIT statusChanged();
239 updateGeometry(generatePlaneGeometry(m_width, m_height, m_meshResolution, m_plane, m_reversed, m_mirrored));
243void PlaneGeometry::requestFinished()
245#if QT_CONFIG(concurrent)
246 const auto output = m_geometryDataFuture.takeResult();
247 updateGeometry(output);
251void PlaneGeometry::scheduleGeometryUpdate()
253 if (!m_geometryUpdateRequested) {
254 QMetaObject::invokeMethod(
this,
"doUpdateGeometry", Qt::QueuedConnection);
255 m_geometryUpdateRequested =
true;
259void PlaneGeometry::updateGeometry(
const GeometryData &geometryData)
261 setStride(
sizeof(
float) * 8);
262 setPrimitiveType(QQuick3DGeometry::PrimitiveType::Triangles);
263 addAttribute(QQuick3DGeometry::Attribute::PositionSemantic,
265 QQuick3DGeometry::Attribute::F32Type);
266 addAttribute(QQuick3DGeometry::Attribute::TexCoord0Semantic,
268 QQuick3DGeometry::Attribute::F32Type);
269 addAttribute(QQuick3DGeometry::Attribute::NormalSemantic,
271 QQuick3DGeometry::Attribute::F32Type);
272 addAttribute(QQuick3DGeometry::Attribute::IndexSemantic,
274 QQuick3DGeometry::Attribute::U16Type);
276 setBounds(geometryData.boundsMin, geometryData.boundsMax);
277 setVertexData(geometryData.vertexData);
278 setIndexData(geometryData.indexData);
282 if (m_pendingAsyncUpdate) {
283 m_pendingAsyncUpdate =
false;
284 scheduleGeometryUpdate();
286 m_status = Status::Ready;
287 Q_EMIT statusChanged();
290 emit geometryChanged();
293PlaneGeometry::GeometryData PlaneGeometry::generatePlaneGeometry(
float width,
float height, QSize meshResolution, Plane plane,
bool reversed,
bool mirrored)
295 GeometryData geometryData;
297 int quadsX = meshResolution.width();
298 int quadsY = meshResolution.height();
300 const int numVertices = (quadsX + 1) * (quadsY + 1);
301 const int numIndices = quadsX * quadsY * 6;
303 const int vertexStride =
sizeof(
float) * (3 + 2 + 3);
304 const int indexStride =
sizeof(uint16_t);
306 geometryData.vertexData.resize(numVertices * vertexStride);
307 geometryData.indexData.resize(numIndices * indexStride);
309 QVector3D boundsMin(std::numeric_limits<
float>::max(),
310 std::numeric_limits<
float>::max(),
311 std::numeric_limits<
float>::max());
313 QVector3D boundsMax(std::numeric_limits<
float>::lowest(),
314 std::numeric_limits<
float>::lowest(),
315 std::numeric_limits<
float>::lowest());
317 float* vertexPtr =
reinterpret_cast<
float*>(geometryData.vertexData.data());
318 uint16_t* indexPtr =
reinterpret_cast<uint16_t*>(geometryData.indexData.data());
323 normal = QVector3D(0, 0, 1);
326 normal = QVector3D(0, 1, 0);
329 normal = QVector3D(1, 0, 0);
337 for (
int y = 0; y <= quadsY; ++y) {
338 for (
int x = 0; x <= quadsX; ++x) {
340 float u =
static_cast<
float>(x) / quadsX;
341 float v =
static_cast<
float>(y) / quadsY;
344 float posX = width * (u - 0.5f);
345 float posY = height * (v - 0.5f);
357 position = QVector3D(posX, posY, 0.0f);
360 position = QVector3D(posX, 0.0f, -posY);
363 position = QVector3D(0.0f, posY, -posX);
368 *vertexPtr++ = position.x();
369 *vertexPtr++ = position.y();
370 *vertexPtr++ = position.z();
377 *vertexPtr++ = normal.x();
378 *vertexPtr++ = normal.y();
379 *vertexPtr++ = normal.z();
382 boundsMin.setX(std::min(boundsMin.x(), position.x()));
383 boundsMin.setY(std::min(boundsMin.y(), position.y()));
384 boundsMin.setZ(std::min(boundsMin.z(), position.z()));
386 boundsMax.setX(std::max(boundsMax.x(), position.x()));
387 boundsMax.setY(std::max(boundsMax.y(), position.y()));
388 boundsMax.setZ(std::max(boundsMax.z(), position.z()));
393 for (
int y = 0; y < quadsY; ++y) {
394 for (
int x = 0; x < quadsX; ++x) {
395 uint16_t a =
static_cast<uint16_t>(y * (quadsX + 1) + x);
396 uint16_t b =
static_cast<uint16_t>(a + quadsX + 1);
397 uint16_t c =
static_cast<uint16_t>(b + 1);
398 uint16_t d =
static_cast<uint16_t>(a + 1);
423 geometryData.boundsMax = boundsMax;
424 geometryData.boundsMin = boundsMin;
429#if QT_CONFIG(concurrent)
430void PlaneGeometry::generatePlaneGeometryAsync(QPromise<PlaneGeometry::GeometryData> &promise,
433 QSize meshResolution,
438 auto output = generatePlaneGeometry(width, height, meshResolution, plane, reversed, mirrored);
439 promise.addResult(output);