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)
175 if (m_asynchronous && QT_CONFIG(thread)) {
176 m_geometryDataFuture = QtConcurrent::run(generateTorusGeometryAsync,
181 m_geometryDataWatcher.setFuture(m_geometryDataFuture);
182 m_status = Status::Loading;
183 Q_EMIT statusChanged();
189 updateGeometry(generateTorusGeometry(m_rings, m_segments, m_radius, m_tubeRadius));
193void TorusGeometry::requestFinished()
195#if QT_CONFIG(concurrent)
196 const auto output = m_geometryDataFuture.takeResult();
197 updateGeometry(output);
201void TorusGeometry::scheduleGeometryUpdate()
203 if (!m_geometryUpdateRequested) {
204 QMetaObject::invokeMethod(
this,
"doUpdateGeometry", Qt::QueuedConnection);
205 m_geometryUpdateRequested =
true;
209void TorusGeometry::updateGeometry(
const GeometryData &geometryData)
212 setStride(
sizeof(
float) * 8);
213 setPrimitiveType(QQuick3DGeometry::PrimitiveType::Triangles);
214 addAttribute(QQuick3DGeometry::Attribute::PositionSemantic,
216 QQuick3DGeometry::Attribute::F32Type);
217 addAttribute(QQuick3DGeometry::Attribute::NormalSemantic,
219 QQuick3DGeometry::Attribute::F32Type);
220 addAttribute(QQuick3DGeometry::Attribute::TexCoord0Semantic,
222 QQuick3DGeometry::Attribute::F32Type);
223 addAttribute(QQuick3DGeometry::Attribute::IndexSemantic,
225 QQuick3DGeometry::Attribute::U32Type);
227 setBounds(geometryData.boundsMin, geometryData.boundsMax);
228 setVertexData(geometryData.vertexData);
229 setIndexData(geometryData.indexData);
233 if (m_pendingAsyncUpdate) {
234 m_pendingAsyncUpdate =
false;
235 scheduleGeometryUpdate();
237 m_status = Status::Ready;
238 Q_EMIT statusChanged();
241 emit geometryChanged();
249TorusGeometry::GeometryData TorusGeometry::generateTorusGeometry(
int rings,
int segments,
float radius,
float tubeRadius)
251 GeometryData geomData;
254 QVector3D boundsMin(std::numeric_limits<
float>::max(),
255 std::numeric_limits<
float>::max(),
256 std::numeric_limits<
float>::max());
258 QVector3D boundsMax(std::numeric_limits<
float>::lowest(),
259 std::numeric_limits<
float>::lowest(),
260 std::numeric_limits<
float>::lowest());
263 int numVerts = (rings + 1) * (segments + 1);
264 int numIndices = rings * segments * 6;
267 int vertexDataSize = numVerts * (VEC3_SIZE + VEC3_SIZE + VEC2_SIZE);
268 geomData.vertexData.resize(vertexDataSize);
271 int indexDataSize = numIndices * UINT_SIZE;
272 geomData.indexData.resize(indexDataSize);
275 char* vertexPtr = geomData.vertexData.data();
276 char* indexPtr = geomData.indexData.data();
278 int vertexOffset = 0;
282 for (
int i = 0; i <= rings; ++i) {
283 for (
int j = 0; j <= segments; ++j) {
284 float u = (i / (
float)rings) * M_PI * 2;
285 float v = (j / (
float)segments) * M_PI * 2;
287 float centerX = radius * qCos(u);
288 float centerZ = radius * qSin(u);
290 float posX = centerX + tubeRadius * qCos(v) * qCos(u);
291 float posY = tubeRadius * qSin(v);
292 float posZ = centerZ + tubeRadius * qCos(v) * qSin(u);
295 boundsMin.setX(qMin(boundsMin.x(), posX));
296 boundsMin.setY(qMin(boundsMin.y(), posY));
297 boundsMin.setZ(qMin(boundsMin.z(), posZ));
299 boundsMax.setX(qMax(boundsMax.x(), posX));
300 boundsMax.setY(qMax(boundsMax.y(), posY));
301 boundsMax.setZ(qMax(boundsMax.z(), posZ));
304 memcpy(vertexPtr + vertexOffset, &posX, FLOAT_SIZE);
305 memcpy(vertexPtr + vertexOffset + FLOAT_SIZE, &posY, FLOAT_SIZE);
306 memcpy(vertexPtr + vertexOffset + 2 * FLOAT_SIZE, &posZ, FLOAT_SIZE);
307 vertexOffset += 3 * FLOAT_SIZE;
310 QVector3D normal = QVector3D(posX - centerX, posY, posZ - centerZ).normalized();
313 memcpy(vertexPtr + vertexOffset, &normal, VEC3_SIZE);
314 vertexOffset += VEC3_SIZE;
317 float uvX = 1.0f - (i / (
float)rings);
318 float uvY = j / (
float)segments;
319 memcpy(vertexPtr + vertexOffset, &uvX, FLOAT_SIZE);
320 memcpy(vertexPtr + vertexOffset + FLOAT_SIZE, &uvY, FLOAT_SIZE);
321 vertexOffset += 2 * FLOAT_SIZE;
326 for (
int i = 0; i < rings; ++i) {
327 for (
int j = 0; j < segments; ++j) {
328 int a = (segments + 1) * i + j;
329 int b = (segments + 1) * (i + 1) + j;
330 int c = (segments + 1) * (i + 1) + j + 1;
331 int d = (segments + 1) * i + j + 1;
334 memcpy(indexPtr + indexOffset, &a, UINT_SIZE);
335 memcpy(indexPtr + indexOffset + UINT_SIZE, &d, UINT_SIZE);
336 memcpy(indexPtr + indexOffset + 2 * UINT_SIZE, &b, UINT_SIZE);
337 indexOffset += 3 * UINT_SIZE;
340 memcpy(indexPtr + indexOffset, &b, UINT_SIZE);
341 memcpy(indexPtr + indexOffset + UINT_SIZE, &d, UINT_SIZE);
342 memcpy(indexPtr + indexOffset + 2 * UINT_SIZE, &c, UINT_SIZE);
343 indexOffset += 3 * UINT_SIZE;
348 geomData.boundsMin = boundsMin;
349 geomData.boundsMax = boundsMax;
354#if QT_CONFIG(concurrent)
355void TorusGeometry::generateTorusGeometryAsync(QPromise<TorusGeometry::GeometryData> &promise,
int rings,
int segments,
float radius,
float tubeRadius)
357 auto output = generateTorusGeometry(rings, segments, radius, tubeRadius);
358 promise.addResult(output);