7#if QT_CONFIG(concurrent)
8#include <QtConcurrentRun>
14
15
16
17
18
19
20
21
22
23
26
27
28
31
32
33
36
37
38
41
42
43
46
47
48
49
52
53
54
55
56
57
58
59
60
61
63TorusGeometry::TorusGeometry(QQuick3DObject *parent)
64 : QQuick3DGeometry(parent)
66#if QT_CONFIG(concurrent)
67 connect(&m_geometryDataWatcher, &QFutureWatcher<GeometryData>::finished,
this, &TorusGeometry::requestFinished);
69 scheduleGeometryUpdate();
72TorusGeometry::~TorusGeometry()
77int TorusGeometry::rings()
const
82void TorusGeometry::setRings(
int newRings)
84 if (m_rings == newRings)
88 scheduleGeometryUpdate();
91int TorusGeometry::segments()
const
96void TorusGeometry::setSegments(
int newSegments)
98 if (m_segments == newSegments)
100 m_segments = newSegments;
101 emit segmentsChanged();
102 scheduleGeometryUpdate();
105float TorusGeometry::radius()
const
110void TorusGeometry::setRadius(
float newRadius)
112 if (qFuzzyCompare(m_radius, newRadius))
114 m_radius = newRadius;
115 emit radiusChanged();
116 scheduleGeometryUpdate();
119float TorusGeometry::tubeRadius()
const
124void TorusGeometry::setTubeRadius(
float newTubeRadius)
126 if (qFuzzyCompare(m_tubeRadius, newTubeRadius))
128 m_tubeRadius = newTubeRadius;
129 emit tubeRadiusChanged();
130 scheduleGeometryUpdate();
133bool TorusGeometry::asynchronous()
const
135 return m_asynchronous;
138void TorusGeometry::setAsynchronous(
bool newAsynchronous)
140 if (m_asynchronous == newAsynchronous)
142 m_asynchronous = newAsynchronous;
143 emit asynchronousChanged();
146TorusGeometry::Status TorusGeometry::status()
const
151void TorusGeometry::doUpdateGeometry()
154 m_geometryUpdateRequested =
false;
156#if QT_CONFIG(concurrent)
157 if (m_geometryDataFuture.isRunning()) {
158 m_pendingAsyncUpdate =
true;
164 if (m_rings <= 0 || m_segments <= 0 || m_radius <= 0 || m_tubeRadius <= 0) {
170#if QT_CONFIG(concurrent)
172 if (m_asynchronous) {
173 m_geometryDataFuture = QtConcurrent::run(generateTorusGeometryAsync,
178 m_geometryDataWatcher.setFuture(m_geometryDataFuture);
179 m_status = Status::Loading;
180 Q_EMIT statusChanged();
186 updateGeometry(generateTorusGeometry(m_rings, m_segments, m_radius, m_tubeRadius));
190void TorusGeometry::requestFinished()
192#if QT_CONFIG(concurrent)
193 const auto output = m_geometryDataFuture.takeResult();
194 updateGeometry(output);
198void TorusGeometry::scheduleGeometryUpdate()
200 if (!m_geometryUpdateRequested) {
201 QMetaObject::invokeMethod(
this,
"doUpdateGeometry", Qt::QueuedConnection);
202 m_geometryUpdateRequested =
true;
206void TorusGeometry::updateGeometry(
const GeometryData &geometryData)
208 setStride(
sizeof(
float) * 8);
209 setPrimitiveType(QQuick3DGeometry::PrimitiveType::Triangles);
210 addAttribute(QQuick3DGeometry::Attribute::PositionSemantic,
212 QQuick3DGeometry::Attribute::F32Type);
213 addAttribute(QQuick3DGeometry::Attribute::NormalSemantic,
215 QQuick3DGeometry::Attribute::F32Type);
216 addAttribute(QQuick3DGeometry::Attribute::TexCoord0Semantic,
218 QQuick3DGeometry::Attribute::F32Type);
219 addAttribute(QQuick3DGeometry::Attribute::IndexSemantic,
221 QQuick3DGeometry::Attribute::U32Type);
223 setBounds(geometryData.boundsMin, geometryData.boundsMax);
224 setVertexData(geometryData.vertexData);
225 setIndexData(geometryData.indexData);
229 if (m_pendingAsyncUpdate) {
230 m_pendingAsyncUpdate =
false;
231 scheduleGeometryUpdate();
233 m_status = Status::Ready;
234 Q_EMIT statusChanged();
244TorusGeometry::GeometryData TorusGeometry::generateTorusGeometry(
int rings,
int segments,
float radius,
float tubeRadius)
246 GeometryData geomData;
249 QVector3D boundsMin(std::numeric_limits<
float>::max(),
250 std::numeric_limits<
float>::max(),
251 std::numeric_limits<
float>::max());
253 QVector3D boundsMax(std::numeric_limits<
float>::lowest(),
254 std::numeric_limits<
float>::lowest(),
255 std::numeric_limits<
float>::lowest());
258 int numVerts = (rings + 1) * (segments + 1);
259 int numIndices = rings * segments * 6;
262 int vertexDataSize = numVerts * (VEC3_SIZE + VEC3_SIZE + VEC2_SIZE);
263 geomData.vertexData.resize(vertexDataSize);
266 int indexDataSize = numIndices * UINT_SIZE;
267 geomData.indexData.resize(indexDataSize);
270 char* vertexPtr = geomData.vertexData.data();
271 char* indexPtr = geomData.indexData.data();
273 int vertexOffset = 0;
277 for (
int i = 0; i <= rings; ++i) {
278 for (
int j = 0; j <= segments; ++j) {
279 float u = (i / (
float)rings) * M_PI * 2;
280 float v = (j / (
float)segments) * M_PI * 2;
282 float centerX = radius * qCos(u);
283 float centerZ = radius * qSin(u);
285 float posX = centerX + tubeRadius * qCos(v) * qCos(u);
286 float posY = tubeRadius * qSin(v);
287 float posZ = centerZ + tubeRadius * qCos(v) * qSin(u);
290 boundsMin.setX(qMin(boundsMin.x(), posX));
291 boundsMin.setY(qMin(boundsMin.y(), posY));
292 boundsMin.setZ(qMin(boundsMin.z(), posZ));
294 boundsMax.setX(qMax(boundsMax.x(), posX));
295 boundsMax.setY(qMax(boundsMax.y(), posY));
296 boundsMax.setZ(qMax(boundsMax.z(), posZ));
299 memcpy(vertexPtr + vertexOffset, &posX, FLOAT_SIZE);
300 memcpy(vertexPtr + vertexOffset + FLOAT_SIZE, &posY, FLOAT_SIZE);
301 memcpy(vertexPtr + vertexOffset + 2 * FLOAT_SIZE, &posZ, FLOAT_SIZE);
302 vertexOffset += 3 * FLOAT_SIZE;
305 QVector3D normal = QVector3D(posX - centerX, posY, posZ - centerZ).normalized();
308 memcpy(vertexPtr + vertexOffset, &normal, VEC3_SIZE);
309 vertexOffset += VEC3_SIZE;
312 float uvX = 1.0f - (i / (
float)rings);
313 float uvY = j / (
float)segments;
314 memcpy(vertexPtr + vertexOffset, &uvX, FLOAT_SIZE);
315 memcpy(vertexPtr + vertexOffset + FLOAT_SIZE, &uvY, FLOAT_SIZE);
316 vertexOffset += 2 * FLOAT_SIZE;
321 for (
int i = 0; i < rings; ++i) {
322 for (
int j = 0; j < segments; ++j) {
323 int a = (segments + 1) * i + j;
324 int b = (segments + 1) * (i + 1) + j;
325 int c = (segments + 1) * (i + 1) + j + 1;
326 int d = (segments + 1) * i + j + 1;
329 memcpy(indexPtr + indexOffset, &a, UINT_SIZE);
330 memcpy(indexPtr + indexOffset + UINT_SIZE, &d, UINT_SIZE);
331 memcpy(indexPtr + indexOffset + 2 * UINT_SIZE, &b, UINT_SIZE);
332 indexOffset += 3 * UINT_SIZE;
335 memcpy(indexPtr + indexOffset, &b, UINT_SIZE);
336 memcpy(indexPtr + indexOffset + UINT_SIZE, &d, UINT_SIZE);
337 memcpy(indexPtr + indexOffset + 2 * UINT_SIZE, &c, UINT_SIZE);
338 indexOffset += 3 * UINT_SIZE;
343 geomData.boundsMin = boundsMin;
344 geomData.boundsMax = boundsMax;
349#if QT_CONFIG(concurrent)
350void TorusGeometry::generateTorusGeometryAsync(QPromise<TorusGeometry::GeometryData> &promise,
int rings,
int segments,
float radius,
float tubeRadius)
352 auto output = generateTorusGeometry(rings, segments, radius, tubeRadius);
353 promise.addResult(output);