Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
capsulegeometry.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5
6// Based on:
7// https://behreajj.medium.com/making-a-capsule-mesh-via-script-in-five-3d-environments-c2214abf02db
8
10
11#if QT_CONFIG(concurrent)
12#include <QtConcurrentRun>
13#endif
14#include <QQuaternion>
15
16#include <cmath>
17
18QT_BEGIN_NAMESPACE
19
20/*!
21 \qmltype CapsuleGeometry
22 \inqmlmodule QtQuick3D.Helpers
23 \inherits Geometry
24 \since 6.10
25 \brief Provides geometry for a capsule.
26
27 A geometry for generating a capsule model. The capsule is centered
28 at \c{(0, 0, 0)} with the height of the capsule extending in the x
29 direction and the diameter on the yz plane.
30*/
31
32/*! \qmlproperty bool CapsuleGeometry::enableNormals
33 \default true
34
35 Generate mesh face normals.
36*/
37
38/*! \qmlproperty bool CapsuleGeometry::enableUV
39 \default false
40
41 Generate mesh uv coordinates.
42*/
43
44/*! \qmlproperty int CapsuleGeometry::longitudes
45 \default 32
46
47 Number of longitudes, or meridians, distributed by azimuth.
48*/
49
50/*! \qmlproperty int CapsuleGeometry::latitudes
51 \default 16
52
53 Number of latitudes, distributed by inclination. Will always be snapped to an even number.
54*/
55
56/*! \qmlproperty int CapsuleGeometry::rings
57 \default 1
58
59 Number of sections in cylinder between hemispheres.
60*/
61
62/*! \qmlproperty real CapsuleGeometry::height
63 \default 100
64
65 Height of the middle cylinder on the x axis, excluding the hemispheres.
66*/
67
68/*! \qmlproperty real CapsuleGeometry::diameter
69 \default 100
70
71 Diameter on the yz plane.
72*/
73
74/*!
75 \qmlproperty UVProfile CapsuleGeometry::uvProfile
76 \default CapsuleGeometry.Fixed
77
78 Manner in which UV coordinates are distributed along the length of the capsule.
79
80 \value CapsuleGeometry.Fixed The upper third of the UV texture is the North
81 hemisphere, the middle third is the cylinder and the last third is the
82 South hemisphere.
83 \value CapsuleGeometry.Aspect UVs match the height to radius ratio.
84 \value CapsuleGeometry.Uniform Uniform proportion for all UV cells,
85 according to the ratio of latitudes to rings.
86*/
87
88/*!
89 \qmlproperty bool CapsuleGeometry::asynchronous
90 \default true
91
92 This property holds whether the geometry generation should be asynchronous.
93*/
94
95/*!
96 \qmlproperty bool CapsuleGeometry::status
97 \readonly
98
99 This property holds the status of the geometry generation when asynchronous is true.
100
101 \value CapsuleGeometry.Null The geometry generation has not started
102 \value CapsuleGeometry.Ready The geometry generation is complete.
103 \value CapsuleGeometry.Loading The geometry generation is in progress.
104 \value CapsuleGeometry.Error The geometry generation failed.
105*/
106
107CapsuleGeometry::CapsuleGeometry(QQuick3DObject *parent) : QQuick3DGeometry(parent)
108{
109#if QT_CONFIG(concurrent)
110 connect(&m_geometryDataWatcher, &QFutureWatcher<GeometryData>::finished, this, &CapsuleGeometry::requestFinished);
111#endif
112 scheduleGeometryUpdate();
113}
114
115CapsuleGeometry::~CapsuleGeometry() = default;
116
117void CapsuleGeometry::setEnableNormals(bool enable)
118{
119 if (m_enableNormals == enable)
120 return;
121
122 m_enableNormals = enable;
123 emit enableNormalsChanged();
124 scheduleGeometryUpdate();
125}
126
127void CapsuleGeometry::setEnableUV(bool enable)
128{
129 if (m_enableUV == enable)
130 return;
131
132 m_enableUV = enable;
133 emit enableUVChanged();
134 scheduleGeometryUpdate();
135}
136
137void CapsuleGeometry::setLongitudes(int longitudes)
138{
139 if (m_longitudes == longitudes)
140 return;
141
142 m_longitudes = longitudes;
143 emit longitudesChanged();
144 scheduleGeometryUpdate();
145}
146
147void CapsuleGeometry::setLatitudes(int latitudes)
148{
149 if (m_latitudes == latitudes)
150 return;
151
152 m_latitudes = latitudes;
153 emit latitudesChanged();
154 scheduleGeometryUpdate();
155}
156
157void CapsuleGeometry::setRings(int rings)
158{
159 if (m_rings == rings)
160 return;
161
162 m_rings = rings;
163 emit ringsChanged();
164 scheduleGeometryUpdate();
165}
166
167void CapsuleGeometry::setHeight(float height)
168{
169 if (m_height == height)
170 return;
171
172 m_height = height;
173 emit heightChanged();
174 scheduleGeometryUpdate();
175}
176
177void CapsuleGeometry::setDiameter(float diameter)
178{
179 if (m_diameter == diameter)
180 return;
181
182 m_diameter = diameter;
183 emit diameterChanged();
184 scheduleGeometryUpdate();
185}
186
187CapsuleGeometry::UVProfile CapsuleGeometry::uvProfile() const
188{
189 return m_uvProfile;
190}
191
192void CapsuleGeometry::setUVProfile(UVProfile newUVProfile)
193{
194 if (m_uvProfile == newUVProfile)
195 return;
196 m_uvProfile = newUVProfile;
197 emit uvProfileChanged();
198 scheduleGeometryUpdate();
199}
200
201bool CapsuleGeometry::asynchronous() const
202{
203 return m_asynchronous;
204}
205
206void CapsuleGeometry::setAsynchronous(bool newAsynchronous)
207{
208 if (m_asynchronous == newAsynchronous)
209 return;
210 m_asynchronous = newAsynchronous;
211 emit asynchronousChanged();
212}
213
214CapsuleGeometry::Status CapsuleGeometry::status() const
215{
216 return m_status;
217}
218
219void CapsuleGeometry::doUpdateGeometry()
220{
221 // reset the flag since we are processing the update
222 m_geometryUpdateRequested = false;
223
224#if QT_CONFIG(concurrent)
225 if (m_geometryDataFuture.isRunning()) {
226 m_pendingAsyncUpdate = true;
227 return;
228 }
229#endif
230
231#if QT_CONFIG(concurrent)
232 if (m_asynchronous) {
233 m_geometryDataFuture = QtConcurrent::run(generateCapsuleGeometryAsync,
234 m_enableNormals,
235 m_enableUV,
236 m_longitudes,
237 m_latitudes,
238 m_rings,
239 m_height,
240 m_diameter,
241 m_uvProfile);
242 m_geometryDataWatcher.setFuture(m_geometryDataFuture);
243 m_status = Status::Loading;
244 Q_EMIT statusChanged();
245 } else {
246#else
247 {
248#endif // QT_CONFIG(concurrent)
249 updateGeometry(generateCapsuleGeometry(m_enableNormals, m_enableUV, m_longitudes, m_latitudes, m_rings, m_height, m_diameter, m_uvProfile));
250 }
251}
252
253void CapsuleGeometry::requestFinished()
254{
255#if QT_CONFIG(concurrent)
256 const auto output = m_geometryDataFuture.takeResult();
257 updateGeometry(output);
258#endif
259}
260
261void CapsuleGeometry::scheduleGeometryUpdate()
262{
263 if (!m_geometryUpdateRequested) {
264 QMetaObject::invokeMethod(this, "doUpdateGeometry", Qt::QueuedConnection);
265 m_geometryUpdateRequested = true;
266 }
267}
268
269void CapsuleGeometry::updateGeometry(const GeometryData &geometryData)
270{
271 clear();
272 setStride(geometryData.stride);
273 setPrimitiveType(QQuick3DGeometry::PrimitiveType::Triangles);
274 addAttribute(QQuick3DGeometry::Attribute::PositionSemantic, 0, QQuick3DGeometry::Attribute::ComponentType::F32Type);
275 if (geometryData.enableNormals) {
276 addAttribute(QQuick3DGeometry::Attribute::NormalSemantic,
277 geometryData.strideNormal,
278 QQuick3DGeometry::Attribute::ComponentType::F32Type);
279 }
280 if (geometryData.enableUV) {
281 addAttribute(QQuick3DGeometry::Attribute::TexCoordSemantic, geometryData.strideUV, QQuick3DGeometry::Attribute::ComponentType::F32Type);
282 }
283 addAttribute(QQuick3DGeometry::Attribute::IndexSemantic, 0, QQuick3DGeometry::Attribute::ComponentType::U32Type);
284
285 setBounds(geometryData.boundsMin, geometryData.boundsMax);
286 setVertexData(geometryData.vertexData);
287 setIndexData(geometryData.indexData);
288
289 // If the geometry update was requested while the geometry was being generated asynchronously,
290 // we need to schedule another geometry update now that the geometry is ready.
291 if (m_pendingAsyncUpdate) {
292 m_pendingAsyncUpdate = false;
293 scheduleGeometryUpdate();
294 } else {
295 m_status = Status::Ready;
296 Q_EMIT statusChanged();
297 }
298 update();
299 emit geometryChanged();
300}
301
302CapsuleGeometry::GeometryData CapsuleGeometry::generateCapsuleGeometry(bool enableNormals,
303 bool enableUV,
304 int longitudes,
305 int latitudes,
306 int rings,
307 float height,
308 float diameter,
309 UVProfile uvProfile)
310{
311 longitudes = qMax(3, longitudes);
312 latitudes = qMax(2, latitudes + (latitudes % 2)); // make even
313 rings = qMax(1, rings);
314 height = qMax(0.00001f, height);
315 diameter = qMax(0.00001f, diameter);
316
317 const UVProfile profile = uvProfile;
318 const float radius = diameter / 2;
319 const float depth = height;
320
321 bool calcMiddle = rings > 0;
322 int halfLats = latitudes / 2;
323 int halfLatsn1 = halfLats - 1;
324 int halfLatsn2 = halfLats - 2;
325 int ringsp1 = rings + 1;
326 int lonsp1 = longitudes + 1;
327 float halfDepth = depth * 0.5f;
328 float summit = halfDepth + radius;
329
330 // Vertex index offsets.
331 int vertOffsetNorthHemi = longitudes;
332 int vertOffsetNorthEquator = vertOffsetNorthHemi + lonsp1 * halfLatsn1;
333 int vertOffsetCylinder = vertOffsetNorthEquator + lonsp1;
334 int vertOffsetSouthEquator = calcMiddle ?
335 vertOffsetCylinder + lonsp1 * rings :
336 vertOffsetCylinder;
337 int vertOffsetSouthHemi = vertOffsetSouthEquator + lonsp1;
338 int vertOffsetSouthPolar = vertOffsetSouthHemi + lonsp1 * halfLatsn2;
339 int vertOffsetSouthCap = vertOffsetSouthPolar + lonsp1;
340
341 // Initialize arrays.
342 int vertLen = vertOffsetSouthCap + longitudes;
343 QList<QVector3D> vs = QList<QVector3D>(vertLen);
344 QList<QVector2D> vts = QList<QVector2D>(vertLen);
345 QList<QVector3D> vns = QList<QVector3D>(vertLen);
346
347 float toTheta = 2.0f * M_PI / longitudes;
348 float toPhi = M_PI / latitudes;
349 float toTexHorizontal = 1.0f / longitudes;
350 float toTexVertical = 1.0f / halfLats;
351
352 // Calculate positions for texture coordinates vertical.
353 float vtAspectRatio = 1.0f;
354 switch (profile)
355 {
356 case UVProfile::Aspect:
357 vtAspectRatio = radius / (depth + radius + radius);
358 break;
359
360 case UVProfile::Uniform:
361 vtAspectRatio = (float) halfLats / (ringsp1 + latitudes);
362 break;
363
364 case UVProfile::Fixed:
365 default:
366 vtAspectRatio = 1.0f / 3.0f;
367 break;
368 }
369
370 float vtAspectNorth = 1.0f - vtAspectRatio;
371 float vtAspectSouth = vtAspectRatio;
372
373 QList<QVector2D> thetaCartesian = QList<QVector2D>(longitudes);
374 QList<QVector2D> rhoThetaCartesian = QList<QVector2D>(longitudes);
375 QList<float> sTextureCache = QList<float>(lonsp1);
376
377 // Polar vertices.
378 for (int j = 0; j < longitudes; ++j)
379 {
380 float jf = j;
381 float sTexturePolar = 1.0f - ((jf + 0.5f) * toTexHorizontal);
382 float theta = jf * toTheta;
383
384 float cosTheta = std::cos(theta);
385 float sinTheta = std::sin(theta);
386
387 thetaCartesian[j] = QVector2D(cosTheta, sinTheta);
388 rhoThetaCartesian[j] = QVector2D(
389 radius * cosTheta,
390 radius * sinTheta);
391
392 // North.
393 vs[j] = QVector3D(0.0f, summit, 0.0f);
394 vts[j] = QVector2D(sTexturePolar, 1.0f);
395 vns[j] = QVector3D(0.0f, 1.0f, 0.0f);
396
397 // South.
398 int idx = vertOffsetSouthCap + j;
399 vs[idx] = QVector3D(0.0f, -summit, 0.0f);
400 vts[idx] = QVector2D(sTexturePolar, 0.0f);
401 vns[idx] = QVector3D(0.0f, -1.0f, 0.0f);
402 }
403
404 // Equatorial vertices.
405 for (int j = 0; j < lonsp1; ++j)
406 {
407 float sTexture = 1.0f - j * toTexHorizontal;
408 sTextureCache[j] = sTexture;
409
410 // Wrap to first element upon reaching last.
411 int jMod = j % longitudes;
412 QVector2D tc = thetaCartesian[jMod];
413 QVector2D rtc = rhoThetaCartesian[jMod];
414
415 // North equator.
416 int idxn = vertOffsetNorthEquator + j;
417 vs[idxn] = QVector3D(rtc.x(), halfDepth, -rtc.y());
418 vts[idxn] = QVector2D(sTexture, vtAspectNorth);
419 vns[idxn] = QVector3D(tc.x(), 0.0f, -tc.y());
420
421 // South equator.
422 int idxs = vertOffsetSouthEquator + j;
423 vs[idxs] = QVector3D(rtc.x(), -halfDepth, -rtc.y());
424 vts[idxs] = QVector2D(sTexture, vtAspectSouth);
425 vns[idxs] = QVector3D(tc.x(), 0.0f, -tc.y());
426 }
427
428 // Hemisphere vertices.
429 for (int i = 0; i < halfLatsn1; ++i)
430 {
431 float ip1f = i + 1.0f;
432 float phi = ip1f * toPhi;
433
434 // For coordinates.
435 float cosPhiSouth = std::cos(phi);
436 float sinPhiSouth = std::sin(phi);
437
438 // Symmetrical hemispheres mean cosine and sine only needs
439 // to be calculated once.
440 float cosPhiNorth = sinPhiSouth;
441 float sinPhiNorth = -cosPhiSouth;
442
443 float rhoCosPhiNorth = radius * cosPhiNorth;
444 float rhoSinPhiNorth = radius * sinPhiNorth;
445 float zOffsetNorth = halfDepth - rhoSinPhiNorth;
446
447 float rhoCosPhiSouth = radius * cosPhiSouth;
448 float rhoSinPhiSouth = radius * sinPhiSouth;
449 float zOffsetSouth = -halfDepth - rhoSinPhiSouth;
450
451 // For texture coordinates.
452 float tTexFac = ip1f * toTexVertical;
453 float cmplTexFac = 1.0f - tTexFac;
454 float tTexNorth = cmplTexFac + vtAspectNorth * tTexFac;
455 float tTexSouth = cmplTexFac * vtAspectSouth;
456
457 int iLonsp1 = i * lonsp1;
458 int vertCurrLatNorth = vertOffsetNorthHemi + iLonsp1;
459 int vertCurrLatSouth = vertOffsetSouthHemi + iLonsp1;
460
461 for (int j = 0; j < lonsp1; ++j)
462 {
463 int jMod = j % longitudes;
464
465 float sTexture = sTextureCache[j];
466 QVector2D tc = thetaCartesian[jMod];
467
468 // North hemisphere.
469 int idxn = vertCurrLatNorth + j;
470 vs[idxn] = QVector3D(
471 rhoCosPhiNorth * tc.x(),
472 zOffsetNorth,
473 -rhoCosPhiNorth * tc.y());
474 vts[idxn] = QVector2D(sTexture, tTexNorth);
475 vns[idxn] = QVector3D(
476 cosPhiNorth * tc.x(),
477 -sinPhiNorth,
478 -cosPhiNorth * tc.y());
479
480 // South hemisphere.
481 int idxs = vertCurrLatSouth + j;
482 vs[idxs] = QVector3D(
483 rhoCosPhiSouth * tc.x(),
484 zOffsetSouth,
485 -rhoCosPhiSouth * tc.y());
486 vts[idxs] = QVector2D(sTexture, tTexSouth);
487 vns[idxs] = QVector3D(
488 cosPhiSouth * tc.x(),
489 -sinPhiSouth,
490 -cosPhiSouth * tc.y());
491 }
492 }
493
494 // Cylinder vertices.
495 if (calcMiddle)
496 {
497 // Exclude both origin and destination edges
498 // (North and South equators) from the interpolation.
499 float toFac = 1.0f / ringsp1;
500 int idxCylLat = vertOffsetCylinder;
501
502 for (int h = 1; h < ringsp1; ++h)
503 {
504 float fac = h * toFac;
505 float cmplFac = 1.0f - fac;
506 float tTexture = cmplFac * vtAspectNorth + fac * vtAspectSouth;
507 float z = halfDepth - depth * fac;
508
509 for (int j = 0; j < lonsp1; ++j)
510 {
511 int jMod = j % longitudes;
512 QVector2D tc = thetaCartesian[jMod];
513 QVector2D rtc = rhoThetaCartesian[jMod];
514 float sTexture = sTextureCache[j];
515
516 vs[idxCylLat] = QVector3D(rtc.x(), z, -rtc.y());
517 vts[idxCylLat] = QVector2D(sTexture, tTexture);
518 vns[idxCylLat] = QVector3D(tc.x(), 0.0f, -tc.y());
519
520 ++idxCylLat;
521 }
522 }
523 }
524
525 // Triangle indices.
526 // Stride is 3 for polar triangles;
527 // stride is 6 for two triangles forming a quad.
528 int lons3 = longitudes * 3;
529 int lons6 = longitudes * 6;
530 int hemiLons = halfLatsn1 * lons6;
531
532 int triOffsetNorthHemi = lons3;
533 int triOffsetCylinder = triOffsetNorthHemi + hemiLons;
534 int triOffsetSouthHemi = triOffsetCylinder + ringsp1 * lons6;
535 int triOffsetSouthCap = triOffsetSouthHemi + hemiLons;
536
537 int fsLen = triOffsetSouthCap + lons3;
538 QList<int> tris = QList<int>(fsLen);
539
540 // Polar caps.
541 for (int i = 0, k = 0, m = triOffsetSouthCap; i < longitudes; ++i, k += 3, m += 3)
542 {
543 // North.
544 tris[k] = i;
545 tris[k + 1] = vertOffsetNorthHemi + i;
546 tris[k + 2] = vertOffsetNorthHemi + i + 1;
547
548 // South.
549 tris[m] = vertOffsetSouthCap + i;
550 tris[m + 1] = vertOffsetSouthPolar + i + 1;
551 tris[m + 2] = vertOffsetSouthPolar + i;
552 }
553
554 // Hemispheres.
555 for (int i = 0, k = triOffsetNorthHemi, m = triOffsetSouthHemi; i < halfLatsn1; ++i)
556 {
557 int iLonsp1 = i * lonsp1;
558
559 int vertCurrLatNorth = vertOffsetNorthHemi + iLonsp1;
560 int vertNextLatNorth = vertCurrLatNorth + lonsp1;
561
562 int vertCurrLatSouth = vertOffsetSouthEquator + iLonsp1;
563 int vertNextLatSouth = vertCurrLatSouth + lonsp1;
564
565 for (int j = 0; j < longitudes; ++j, k += 6, m += 6)
566 {
567 // North.
568 int north00 = vertCurrLatNorth + j;
569 int north01 = vertNextLatNorth + j;
570 int north11 = vertNextLatNorth + j + 1;
571 int north10 = vertCurrLatNorth + j + 1;
572
573 tris[k] = north00;
574 tris[k + 1] = north11;
575 tris[k + 2] = north10;
576
577 tris[k + 3] = north00;
578 tris[k + 4] = north01;
579 tris[k + 5] = north11;
580
581 // South.
582 int south00 = vertCurrLatSouth + j;
583 int south01 = vertNextLatSouth + j;
584 int south11 = vertNextLatSouth + j + 1;
585 int south10 = vertCurrLatSouth + j + 1;
586
587 tris[m] = south00;
588 tris[m + 1] = south11;
589 tris[m + 2] = south10;
590
591 tris[m + 3] = south00;
592 tris[m + 4] = south01;
593 tris[m + 5] = south11;
594 }
595 }
596
597 // Cylinder.
598 for (int i = 0, k = triOffsetCylinder; i < ringsp1; ++i)
599 {
600 int vertCurrLat = vertOffsetNorthEquator + i * lonsp1;
601 int vertNextLat = vertCurrLat + lonsp1;
602
603 for (int j = 0; j < longitudes; ++j, k += 6)
604 {
605 int cy00 = vertCurrLat + j;
606 int cy01 = vertNextLat + j;
607 int cy11 = vertNextLat + j + 1;
608 int cy10 = vertCurrLat + j + 1;
609
610 tris[k] = cy00;
611 tris[k + 1] = cy11;
612 tris[k + 2] = cy10;
613
614 tris[k + 3] = cy00;
615 tris[k + 4] = cy01;
616 tris[k + 5] = cy11;
617 }
618 }
619
620 auto vertices = vs;
621 auto vertexTextures = vts;
622 auto vertexNormals = vns;
623
624 uint32_t stride = 3 * sizeof(float);
625 uint32_t strideNormal = 0;
626 uint32_t strideUV = 0;
627
628 if (enableNormals) {
629 strideNormal = stride;
630 stride += 3 * sizeof(float);
631 }
632 if (enableUV) {
633 strideUV = stride;
634 stride += 2 * sizeof(float);
635 }
636
637 QByteArray vertexData(vertices.length() * stride, Qt::Initialization::Uninitialized);
638 QByteArray indexData(tris.length() * sizeof(int), Qt::Initialization::Uninitialized);
639
640 const auto getVertexPtr = [&](const int vertexIdx) {
641 return reinterpret_cast<QVector3D *>(vertexData.data() + stride * vertexIdx);
642 };
643 const auto getNormalPtr = [&](const int vertexIdx) {
644 return reinterpret_cast<QVector3D *>(vertexData.data() + stride * vertexIdx + strideNormal);
645 };
646 const auto getTexturePtr = [&](const int vertexIdx) {
647 return reinterpret_cast<QVector2D *>(vertexData.data() + stride * vertexIdx + strideUV);
648 };
649
650 const QQuaternion rotateZ = QQuaternion::fromEulerAngles(0, 0, 90);
651 uint32_t *indexPtr = reinterpret_cast<uint32_t *>(indexData.data());
652
653 for (qsizetype i = 0; i < vertices.length(); i++) {
654 *getVertexPtr(i) = rotateZ * vertices[i];
655 }
656
657 for (qsizetype i = 0; i < tris.length() / 3; i++) {
658 std::array<int, 3> triIndices = { tris[i * 3], tris[i * 3 + 1], tris[i * 3 + 2] };
659 *indexPtr = triIndices[0];
660 indexPtr++;
661 *indexPtr = triIndices[1];
662 indexPtr++;
663 *indexPtr = triIndices[2];
664 indexPtr++;
665
666 if (enableNormals) {
667 *getNormalPtr(triIndices[0]) = rotateZ * vertexNormals[triIndices[0]];
668 *getNormalPtr(triIndices[1]) = rotateZ * vertexNormals[triIndices[1]];
669 *getNormalPtr(triIndices[2]) = rotateZ * vertexNormals[triIndices[2]];
670 }
671
672 if (enableUV) {
673 *getTexturePtr(triIndices[0]) = vertexTextures[triIndices[0]];
674 *getTexturePtr(triIndices[1]) = vertexTextures[triIndices[1]];
675 *getTexturePtr(triIndices[2]) = vertexTextures[triIndices[2]];
676 }
677 }
678
679 GeometryData geometryData;
680 geometryData.indexData = indexData;
681 geometryData.vertexData = vertexData;
682 geometryData.boundsMin = QVector3D(-radius - halfDepth, -radius, -radius);
683 geometryData.boundsMax = QVector3D(radius + halfDepth, radius, radius);
684 geometryData.stride = stride;
685 geometryData.strideNormal = strideNormal;
686 geometryData.strideUV = strideUV;
687 geometryData.enableNormals = enableNormals;
688 geometryData.enableUV = enableUV;
689 return geometryData;
690}
691
692#if QT_CONFIG(concurrent)
693void CapsuleGeometry::generateCapsuleGeometryAsync(QPromise<CapsuleGeometry::GeometryData> &promise,
694 bool enableNormals,
695 bool enableUV,
696 int longitudes,
697 int latitudes,
698 int rings,
699 float height,
700 float diameter,
701 CapsuleGeometry::UVProfile uvProfile)
702{
703 auto output = generateCapsuleGeometry(enableNormals, enableUV, longitudes, latitudes, rings, height, diameter, uvProfile);
704 promise.addResult(output);
705}
706#endif
707
708QT_END_NAMESPACE
#define M_PI
Definition qmath.h:200