9#if QT_CONFIG(concurrent)
10#include <QtConcurrentRun>
16
17
18
19
20
21
22
23
24
25
28
29
30
33
34
35
38
39
40
43
44
45
48
49
50
51
54
55
56
57
58
59
60
61
62
63
65TorusGeometry::TorusGeometry(QQuick3DObject *parent)
66 : QQuick3DGeometry(parent)
68#if QT_CONFIG(concurrent)
69 connect(&m_geometryDataWatcher, &QFutureWatcher<GeometryData>::finished,
this, &TorusGeometry::requestFinished);
71 scheduleGeometryUpdate();
74TorusGeometry::~TorusGeometry()
79int TorusGeometry::rings()
const
84void TorusGeometry::setRings(
int newRings)
86 if (m_rings == newRings)
90 scheduleGeometryUpdate();
93int TorusGeometry::segments()
const
98void TorusGeometry::setSegments(
int newSegments)
100 if (m_segments == newSegments)
102 m_segments = newSegments;
103 emit segmentsChanged();
104 scheduleGeometryUpdate();
107float TorusGeometry::radius()
const
112void TorusGeometry::setRadius(
float newRadius)
114 if (qFuzzyCompare(m_radius, newRadius))
116 m_radius = newRadius;
117 emit radiusChanged();
118 scheduleGeometryUpdate();
121float TorusGeometry::tubeRadius()
const
126void TorusGeometry::setTubeRadius(
float newTubeRadius)
128 if (qFuzzyCompare(m_tubeRadius, newTubeRadius))
130 m_tubeRadius = newTubeRadius;
131 emit tubeRadiusChanged();
132 scheduleGeometryUpdate();
135bool TorusGeometry::asynchronous()
const
137 return m_asynchronous;
140void TorusGeometry::setAsynchronous(
bool newAsynchronous)
142 if (m_asynchronous == newAsynchronous)
144 m_asynchronous = newAsynchronous;
145 emit asynchronousChanged();
148TorusGeometry::Status TorusGeometry::status()
const
153void TorusGeometry::doUpdateGeometry()
156 m_geometryUpdateRequested =
false;
158#if QT_CONFIG(concurrent)
159 if (m_geometryDataFuture.isRunning()) {
160 m_pendingAsyncUpdate =
true;
166 if (m_rings <= 0 || m_segments <= 0 || m_radius <= 0 || m_tubeRadius <= 0) {
172#if QT_CONFIG(concurrent)
174 if (m_asynchronous) {
175 m_geometryDataFuture = QtConcurrent::run(generateTorusGeometryAsync,
180 m_geometryDataWatcher.setFuture(m_geometryDataFuture);
181 m_status = Status::Loading;
182 Q_EMIT statusChanged();
188 updateGeometry(generateTorusGeometry(m_rings, m_segments, m_radius, m_tubeRadius));
192void TorusGeometry::requestFinished()
194#if QT_CONFIG(concurrent)
195 const auto output = m_geometryDataFuture.takeResult();
196 updateGeometry(output);
200void TorusGeometry::scheduleGeometryUpdate()
202 if (!m_geometryUpdateRequested) {
203 QMetaObject::invokeMethod(
this,
"doUpdateGeometry", Qt::QueuedConnection);
204 m_geometryUpdateRequested =
true;
208void TorusGeometry::updateGeometry(
const GeometryData &geometryData)
211 setStride(
sizeof(
float) * 8);
212 setPrimitiveType(QQuick3DGeometry::PrimitiveType::Triangles);
213 addAttribute(QQuick3DGeometry::Attribute::PositionSemantic,
215 QQuick3DGeometry::Attribute::F32Type);
216 addAttribute(QQuick3DGeometry::Attribute::NormalSemantic,
218 QQuick3DGeometry::Attribute::F32Type);
219 addAttribute(QQuick3DGeometry::Attribute::TexCoord0Semantic,
221 QQuick3DGeometry::Attribute::F32Type);
222 addAttribute(QQuick3DGeometry::Attribute::IndexSemantic,
224 QQuick3DGeometry::Attribute::U32Type);
226 setBounds(geometryData.boundsMin, geometryData.boundsMax);
227 setVertexData(geometryData.vertexData);
228 setIndexData(geometryData.indexData);
232 if (m_pendingAsyncUpdate) {
233 m_pendingAsyncUpdate =
false;
234 scheduleGeometryUpdate();
236 m_status = Status::Ready;
237 Q_EMIT statusChanged();
240 emit geometryChanged();
248TorusGeometry::GeometryData TorusGeometry::generateTorusGeometry(
int rings,
int segments,
float radius,
float tubeRadius)
250 GeometryData geomData;
253 QVector3D boundsMin(std::numeric_limits<
float>::max(),
254 std::numeric_limits<
float>::max(),
255 std::numeric_limits<
float>::max());
257 QVector3D boundsMax(std::numeric_limits<
float>::lowest(),
258 std::numeric_limits<
float>::lowest(),
259 std::numeric_limits<
float>::lowest());
262 int numVerts = (rings + 1) * (segments + 1);
263 int numIndices = rings * segments * 6;
266 int vertexDataSize = numVerts * (VEC3_SIZE + VEC3_SIZE + VEC2_SIZE);
267 geomData.vertexData.resize(vertexDataSize);
270 int indexDataSize = numIndices * UINT_SIZE;
271 geomData.indexData.resize(indexDataSize);
274 char* vertexPtr = geomData.vertexData.data();
275 char* indexPtr = geomData.indexData.data();
277 int vertexOffset = 0;
281 for (
int i = 0; i <= rings; ++i) {
282 for (
int j = 0; j <= segments; ++j) {
283 float u = (i / (
float)rings) * M_PI * 2;
284 float v = (j / (
float)segments) * M_PI * 2;
286 float centerX = radius * qCos(u);
287 float centerZ = radius * qSin(u);
289 float posX = centerX + tubeRadius * qCos(v) * qCos(u);
290 float posY = tubeRadius * qSin(v);
291 float posZ = centerZ + tubeRadius * qCos(v) * qSin(u);
294 boundsMin.setX(qMin(boundsMin.x(), posX));
295 boundsMin.setY(qMin(boundsMin.y(), posY));
296 boundsMin.setZ(qMin(boundsMin.z(), posZ));
298 boundsMax.setX(qMax(boundsMax.x(), posX));
299 boundsMax.setY(qMax(boundsMax.y(), posY));
300 boundsMax.setZ(qMax(boundsMax.z(), posZ));
303 memcpy(vertexPtr + vertexOffset, &posX, FLOAT_SIZE);
304 memcpy(vertexPtr + vertexOffset + FLOAT_SIZE, &posY, FLOAT_SIZE);
305 memcpy(vertexPtr + vertexOffset + 2 * FLOAT_SIZE, &posZ, FLOAT_SIZE);
306 vertexOffset += 3 * FLOAT_SIZE;
309 QVector3D normal = QVector3D(posX - centerX, posY, posZ - centerZ).normalized();
312 memcpy(vertexPtr + vertexOffset, &normal, VEC3_SIZE);
313 vertexOffset += VEC3_SIZE;
316 float uvX = 1.0f - (i / (
float)rings);
317 float uvY = j / (
float)segments;
318 memcpy(vertexPtr + vertexOffset, &uvX, FLOAT_SIZE);
319 memcpy(vertexPtr + vertexOffset + FLOAT_SIZE, &uvY, FLOAT_SIZE);
320 vertexOffset += 2 * FLOAT_SIZE;
325 for (
int i = 0; i < rings; ++i) {
326 for (
int j = 0; j < segments; ++j) {
327 int a = (segments + 1) * i + j;
328 int b = (segments + 1) * (i + 1) + j;
329 int c = (segments + 1) * (i + 1) + j + 1;
330 int d = (segments + 1) * i + j + 1;
333 memcpy(indexPtr + indexOffset, &a, UINT_SIZE);
334 memcpy(indexPtr + indexOffset + UINT_SIZE, &d, UINT_SIZE);
335 memcpy(indexPtr + indexOffset + 2 * UINT_SIZE, &b, UINT_SIZE);
336 indexOffset += 3 * UINT_SIZE;
339 memcpy(indexPtr + indexOffset, &b, UINT_SIZE);
340 memcpy(indexPtr + indexOffset + UINT_SIZE, &d, UINT_SIZE);
341 memcpy(indexPtr + indexOffset + 2 * UINT_SIZE, &c, UINT_SIZE);
342 indexOffset += 3 * UINT_SIZE;
347 geomData.boundsMin = boundsMin;
348 geomData.boundsMax = boundsMax;
353#if QT_CONFIG(concurrent)
354void TorusGeometry::generateTorusGeometryAsync(QPromise<TorusGeometry::GeometryData> &promise,
int rings,
int segments,
float radius,
float tubeRadius)
356 auto output = generateTorusGeometry(rings, segments, radius, tubeRadius);
357 promise.addResult(output);