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)
210 setStride(
sizeof(
float) * 8);
211 setPrimitiveType(QQuick3DGeometry::PrimitiveType::Triangles);
212 addAttribute(QQuick3DGeometry::Attribute::PositionSemantic,
214 QQuick3DGeometry::Attribute::F32Type);
215 addAttribute(QQuick3DGeometry::Attribute::NormalSemantic,
217 QQuick3DGeometry::Attribute::F32Type);
218 addAttribute(QQuick3DGeometry::Attribute::TexCoord0Semantic,
220 QQuick3DGeometry::Attribute::F32Type);
221 addAttribute(QQuick3DGeometry::Attribute::IndexSemantic,
223 QQuick3DGeometry::Attribute::U32Type);
225 setBounds(geometryData.boundsMin, geometryData.boundsMax);
226 setVertexData(geometryData.vertexData);
227 setIndexData(geometryData.indexData);
231 if (m_pendingAsyncUpdate) {
232 m_pendingAsyncUpdate =
false;
233 scheduleGeometryUpdate();
235 m_status = Status::Ready;
236 Q_EMIT statusChanged();
239 emit geometryChanged();
247TorusGeometry::GeometryData TorusGeometry::generateTorusGeometry(
int rings,
int segments,
float radius,
float tubeRadius)
249 GeometryData geomData;
252 QVector3D boundsMin(std::numeric_limits<
float>::max(),
253 std::numeric_limits<
float>::max(),
254 std::numeric_limits<
float>::max());
256 QVector3D boundsMax(std::numeric_limits<
float>::lowest(),
257 std::numeric_limits<
float>::lowest(),
258 std::numeric_limits<
float>::lowest());
261 int numVerts = (rings + 1) * (segments + 1);
262 int numIndices = rings * segments * 6;
265 int vertexDataSize = numVerts * (VEC3_SIZE + VEC3_SIZE + VEC2_SIZE);
266 geomData.vertexData.resize(vertexDataSize);
269 int indexDataSize = numIndices * UINT_SIZE;
270 geomData.indexData.resize(indexDataSize);
273 char* vertexPtr = geomData.vertexData.data();
274 char* indexPtr = geomData.indexData.data();
276 int vertexOffset = 0;
280 for (
int i = 0; i <= rings; ++i) {
281 for (
int j = 0; j <= segments; ++j) {
282 float u = (i / (
float)rings) * M_PI * 2;
283 float v = (j / (
float)segments) * M_PI * 2;
285 float centerX = radius * qCos(u);
286 float centerZ = radius * qSin(u);
288 float posX = centerX + tubeRadius * qCos(v) * qCos(u);
289 float posY = tubeRadius * qSin(v);
290 float posZ = centerZ + tubeRadius * qCos(v) * qSin(u);
293 boundsMin.setX(qMin(boundsMin.x(), posX));
294 boundsMin.setY(qMin(boundsMin.y(), posY));
295 boundsMin.setZ(qMin(boundsMin.z(), posZ));
297 boundsMax.setX(qMax(boundsMax.x(), posX));
298 boundsMax.setY(qMax(boundsMax.y(), posY));
299 boundsMax.setZ(qMax(boundsMax.z(), posZ));
302 memcpy(vertexPtr + vertexOffset, &posX, FLOAT_SIZE);
303 memcpy(vertexPtr + vertexOffset + FLOAT_SIZE, &posY, FLOAT_SIZE);
304 memcpy(vertexPtr + vertexOffset + 2 * FLOAT_SIZE, &posZ, FLOAT_SIZE);
305 vertexOffset += 3 * FLOAT_SIZE;
308 QVector3D normal = QVector3D(posX - centerX, posY, posZ - centerZ).normalized();
311 memcpy(vertexPtr + vertexOffset, &normal, VEC3_SIZE);
312 vertexOffset += VEC3_SIZE;
315 float uvX = 1.0f - (i / (
float)rings);
316 float uvY = j / (
float)segments;
317 memcpy(vertexPtr + vertexOffset, &uvX, FLOAT_SIZE);
318 memcpy(vertexPtr + vertexOffset + FLOAT_SIZE, &uvY, FLOAT_SIZE);
319 vertexOffset += 2 * FLOAT_SIZE;
324 for (
int i = 0; i < rings; ++i) {
325 for (
int j = 0; j < segments; ++j) {
326 int a = (segments + 1) * i + j;
327 int b = (segments + 1) * (i + 1) + j;
328 int c = (segments + 1) * (i + 1) + j + 1;
329 int d = (segments + 1) * i + j + 1;
332 memcpy(indexPtr + indexOffset, &a, UINT_SIZE);
333 memcpy(indexPtr + indexOffset + UINT_SIZE, &d, UINT_SIZE);
334 memcpy(indexPtr + indexOffset + 2 * UINT_SIZE, &b, UINT_SIZE);
335 indexOffset += 3 * UINT_SIZE;
338 memcpy(indexPtr + indexOffset, &b, UINT_SIZE);
339 memcpy(indexPtr + indexOffset + UINT_SIZE, &d, UINT_SIZE);
340 memcpy(indexPtr + indexOffset + 2 * UINT_SIZE, &c, UINT_SIZE);
341 indexOffset += 3 * UINT_SIZE;
346 geomData.boundsMin = boundsMin;
347 geomData.boundsMax = boundsMax;
352#if QT_CONFIG(concurrent)
353void TorusGeometry::generateTorusGeometryAsync(QPromise<TorusGeometry::GeometryData> &promise,
int rings,
int segments,
float radius,
float tubeRadius)
355 auto output = generateTorusGeometry(rings, segments, radius, tubeRadius);
356 promise.addResult(output);