1 | // Copyright (C) 2020 Klaralvdalens Datakonsult AB (KDAB). |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "qgeometryview.h" |
5 | #include "qgeometryview_p.h" |
6 | #include "qgeometry_p.h" |
7 | #include "buffervisitor_p.h" |
8 | |
9 | #include <Qt3DCore/QAttribute> |
10 | #include <Qt3DCore/QBuffer> |
11 | #include <Qt3DCore/private/vector3d_p.h> |
12 | |
13 | QT_BEGIN_NAMESPACE |
14 | |
15 | namespace Qt3DCore { |
16 | |
17 | namespace { |
18 | |
19 | class FindExtremePoints : public Buffer3fVisitor |
20 | { |
21 | public: |
22 | FindExtremePoints() |
23 | : Buffer3fVisitor() |
24 | , xMin(0.0f), xMax(0.0f), yMin(0.0f), yMax(0.0f), zMin(0.0f), zMax(0.0f) |
25 | { } |
26 | |
27 | float xMin, xMax, yMin, yMax, zMin, zMax; |
28 | Vector3D xMinPt, xMaxPt, yMinPt, yMaxPt, zMinPt, zMaxPt; |
29 | |
30 | void visit(uint ndx, float x, float y, float z) override |
31 | { |
32 | if (ndx) { |
33 | if (x < xMin) { |
34 | xMin = x; |
35 | xMinPt = Vector3D(x, y, z); |
36 | } |
37 | if (x > xMax) { |
38 | xMax = x; |
39 | xMaxPt = Vector3D(x, y, z); |
40 | } |
41 | if (y < yMin) { |
42 | yMin = y; |
43 | yMinPt = Vector3D(x, y, z); |
44 | } |
45 | if (y > yMax) { |
46 | yMax = y; |
47 | yMaxPt = Vector3D(x, y, z); |
48 | } |
49 | if (z < zMin) { |
50 | zMin = z; |
51 | zMinPt = Vector3D(x, y, z); |
52 | } |
53 | if (z > zMax) { |
54 | zMax = z; |
55 | zMaxPt = Vector3D(x, y, z); |
56 | } |
57 | } else { |
58 | xMin = xMax = x; |
59 | yMin = yMax = y; |
60 | zMin = zMax = z; |
61 | xMinPt = xMaxPt = yMinPt = yMaxPt = zMinPt = zMaxPt = Vector3D(x, y, z); |
62 | } |
63 | } |
64 | }; |
65 | |
66 | class FindMaxDistantPoint : public Buffer3fVisitor |
67 | { |
68 | public: |
69 | FindMaxDistantPoint() |
70 | : Buffer3fVisitor() |
71 | { } |
72 | |
73 | float maxLengthSquared = 0.0f; |
74 | bool setReferencePoint = false; |
75 | bool hasNoPoints = true; |
76 | Vector3D maxDistPt; |
77 | Vector3D referencePt; |
78 | |
79 | void visit(uint ndx, float x, float y, float z) override |
80 | { |
81 | Q_UNUSED(ndx); |
82 | const Vector3D p = Vector3D(x, y, z); |
83 | |
84 | if (hasNoPoints && setReferencePoint) { |
85 | maxLengthSquared = 0.0f; |
86 | referencePt = p; |
87 | } |
88 | const float lengthSquared = (p - referencePt).lengthSquared(); |
89 | if ( lengthSquared >= maxLengthSquared ) { |
90 | maxDistPt = p; |
91 | maxLengthSquared = lengthSquared; |
92 | } |
93 | hasNoPoints = false; |
94 | } |
95 | }; |
96 | |
97 | } |
98 | |
99 | bool BoundingVolumeCalculator::apply(QAttribute *positionAttribute, |
100 | QAttribute *indexAttribute, |
101 | int drawVertexCount, |
102 | bool primitiveRestartEnabled, |
103 | int primitiveRestartIndex) |
104 | { |
105 | m_radius = -1.f; |
106 | |
107 | FindExtremePoints findExtremePoints; |
108 | if (!findExtremePoints.apply(attribute: positionAttribute, indexAttribute, drawVertexCount, |
109 | primitiveRestartEnabled, primitiveRestartIndex)) { |
110 | return false; |
111 | } |
112 | |
113 | m_min = QVector3D(findExtremePoints.xMin, findExtremePoints.yMin, findExtremePoints.zMin); |
114 | m_max = QVector3D(findExtremePoints.xMax, findExtremePoints.yMax, findExtremePoints.zMax); |
115 | |
116 | FindMaxDistantPoint maxDistantPointY; |
117 | maxDistantPointY.setReferencePoint = true; |
118 | if (!maxDistantPointY.apply(attribute: positionAttribute, indexAttribute, drawVertexCount, |
119 | primitiveRestartEnabled, primitiveRestartIndex)) { |
120 | return false; |
121 | } |
122 | if (maxDistantPointY.hasNoPoints) |
123 | return false; |
124 | |
125 | //const Vector3D x = maxDistantPointY.referencePt; |
126 | const Vector3D y = maxDistantPointY.maxDistPt; |
127 | |
128 | FindMaxDistantPoint maxDistantPointZ; |
129 | maxDistantPointZ.setReferencePoint = false; |
130 | maxDistantPointZ.referencePt = y; |
131 | if (!maxDistantPointZ.apply(attribute: positionAttribute, indexAttribute, drawVertexCount, |
132 | primitiveRestartEnabled, primitiveRestartIndex)) |
133 | return false; |
134 | const Vector3D z = maxDistantPointZ.maxDistPt; |
135 | const Vector3D center = (y + z) * .5f; |
136 | |
137 | FindMaxDistantPoint maxDistantPointCenter; |
138 | maxDistantPointCenter.setReferencePoint = false; |
139 | maxDistantPointCenter.referencePt = center; |
140 | if (!maxDistantPointCenter.apply(attribute: positionAttribute, indexAttribute, drawVertexCount, |
141 | primitiveRestartEnabled, primitiveRestartIndex)) |
142 | return false; |
143 | |
144 | const float radius = (center - maxDistantPointCenter.maxDistPt).length(); |
145 | |
146 | if (center == Vector3D{} && radius < 0.f) |
147 | return false; |
148 | |
149 | m_radius = radius; |
150 | m_center = QVector3D{ center.x(), center.y(), center.z() }; |
151 | |
152 | return true; |
153 | } |
154 | |
155 | |
156 | QGeometryViewPrivate::QGeometryViewPrivate() |
157 | : QNodePrivate() |
158 | , m_instanceCount(1) |
159 | , m_vertexCount(0) |
160 | , m_indexOffset(0) |
161 | , m_firstInstance(0) |
162 | , m_firstVertex(0) |
163 | , m_indexBufferByteOffset(0) |
164 | , m_restartIndexValue(-1) |
165 | , m_verticesPerPatch(0) |
166 | , m_primitiveRestart(false) |
167 | , m_geometry(nullptr) |
168 | , m_primitiveType(QGeometryView::Triangles) |
169 | , m_dirty(false) |
170 | { |
171 | } |
172 | |
173 | QGeometryViewPrivate::~QGeometryViewPrivate() |
174 | { |
175 | } |
176 | |
177 | QGeometryViewPrivate *QGeometryViewPrivate::get(QGeometryView *q) |
178 | { |
179 | return q->d_func(); |
180 | } |
181 | |
182 | void QGeometryViewPrivate::update() |
183 | { |
184 | if (!m_blockNotifications) |
185 | m_dirty = true; |
186 | QNodePrivate::update(); |
187 | } |
188 | |
189 | /*! |
190 | \qmltype GeometryView |
191 | \instantiates Qt3DCore::QGeometryView |
192 | \inqmlmodule Qt3D.Core |
193 | \inherits Node |
194 | \since 6.0 |
195 | \brief Encapsulates geometry details. |
196 | |
197 | A GeometryView holds all the information necessary to handle |
198 | a Geometry. A Geometry holds the coordinates of the geometry data - |
199 | GeometryView specifies how to interpret that data. |
200 | */ |
201 | |
202 | /*! |
203 | \class Qt3DCore::QGeometryView |
204 | \inmodule Qt3DCore |
205 | \since 6.0 |
206 | \brief Encapsulates geometry details. |
207 | |
208 | A GeometryView holds all the information necessary to handle |
209 | a Geometry. A Geometry holds the coordinates of the geometry data - |
210 | GeometryView specifies how to interpret that data. |
211 | */ |
212 | |
213 | |
214 | /*! |
215 | \enum QGeometryView::PrimitiveType |
216 | |
217 | The type of the primitive. |
218 | |
219 | \value Points List of points |
220 | \value Lines List of lines |
221 | \value LineLoop Connected group of lines connected at ends forming a loop |
222 | \value LineStrip Connected group of lines |
223 | \value Triangles List of triangles |
224 | \value TriangleStrip List of connected triangles |
225 | \value TriangleFan List of connected triagles where all triangles share the first vertex |
226 | \value LinesAdjacency Allows geometry shader to access adjacent lines in a line list |
227 | \value TrianglesAdjacency Allows geometry shader to access adjacent triangles in a triangle list |
228 | \value LineStripAdjacency Allows geometry shader to access adjacent lines in a line strip |
229 | \value TriangleStripAdjacency Allows geometry shader to access adjacent triangles in a triangle strip |
230 | \value Patches Only primitive type accepted by tesselation shader where a patch consists of arbitrary number of vertices |
231 | */ |
232 | |
233 | /*! |
234 | \qmlproperty int GeometryView::instanceCount |
235 | |
236 | Holds the instance count. |
237 | */ |
238 | |
239 | /*! |
240 | \qmlproperty int GeometryView::vertexCount |
241 | |
242 | Holds the vertex count. |
243 | */ |
244 | |
245 | /*! |
246 | \qmlproperty int GeometryView::indexOffset |
247 | |
248 | Holds the base vertex. |
249 | */ |
250 | |
251 | /*! |
252 | \qmlproperty int GeometryView::firstInstance |
253 | |
254 | Holds the base instance. |
255 | */ |
256 | |
257 | /*! |
258 | \qmlproperty int GeometryView::firstVertex |
259 | |
260 | Holds the first vertex. |
261 | */ |
262 | |
263 | /*! |
264 | \qmlproperty int GeometryView::indexBufferByteOffset |
265 | |
266 | Holds the byte offset into the index buffer. |
267 | */ |
268 | |
269 | /*! |
270 | \qmlproperty int GeometryView::restartIndex |
271 | |
272 | Holds the restart index. |
273 | */ |
274 | |
275 | /*! |
276 | \qmlproperty int GeometryView::verticesPerPatch |
277 | |
278 | Holds vertices per patch. |
279 | */ |
280 | |
281 | /*! |
282 | \qmlproperty bool GeometryView::primitiveRestart |
283 | |
284 | Holds the primitive restart flag. |
285 | */ |
286 | |
287 | /*! |
288 | \qmlproperty Geometry GeometryView::geometry |
289 | |
290 | Holds the geometry. |
291 | */ |
292 | |
293 | /*! |
294 | \qmlproperty enumeration GeometryView::primitiveType |
295 | |
296 | Holds the primitive type. |
297 | |
298 | \list |
299 | \li QGeometryView.Points |
300 | \li QGeometryView.Lines |
301 | \li QGeometryView.LineLoop |
302 | \li QGeometryView.LineStrip |
303 | \li QGeometryView.Triangles |
304 | \li QGeometryView.TriangleStrip |
305 | \li QGeometryView.TriangleFan |
306 | \li QGeometryView.LinesAdjacency |
307 | \li QGeometryView.TrianglesAdjacency |
308 | \li QGeometryView.LineStripAdjacency |
309 | \li QGeometryView.TriangleStripAdjacency |
310 | \li QGeometryView.Patches |
311 | \endlist |
312 | \sa Qt3DCore::QGeometryView::PrimitiveType |
313 | */ |
314 | |
315 | |
316 | /*! |
317 | Constructs a new QGeometryView with \a parent. |
318 | */ |
319 | QGeometryView::QGeometryView(QNode *parent) |
320 | : QNode(*new QGeometryViewPrivate(), parent) |
321 | { |
322 | } |
323 | |
324 | /*! |
325 | \internal |
326 | */ |
327 | QGeometryView::~QGeometryView() |
328 | { |
329 | } |
330 | |
331 | /*! |
332 | \internal |
333 | */ |
334 | QGeometryView::QGeometryView(QGeometryViewPrivate &dd, QNode *parent) |
335 | : QNode(dd, parent) |
336 | { |
337 | } |
338 | |
339 | /*! |
340 | \property QGeometryView::instanceCount |
341 | |
342 | Holds the instance count. |
343 | */ |
344 | int QGeometryView::instanceCount() const |
345 | { |
346 | Q_D(const QGeometryView); |
347 | return d->m_instanceCount; |
348 | } |
349 | |
350 | /*! |
351 | \property QGeometryView::vertexCount |
352 | |
353 | Holds the primitive count. |
354 | */ |
355 | int QGeometryView::vertexCount() const |
356 | { |
357 | Q_D(const QGeometryView); |
358 | return d->m_vertexCount; |
359 | } |
360 | |
361 | /*! |
362 | \property QGeometryView::indexOffset |
363 | |
364 | Holds the base vertex. |
365 | */ |
366 | int QGeometryView::indexOffset() const |
367 | { |
368 | Q_D(const QGeometryView); |
369 | return d->m_indexOffset; |
370 | } |
371 | |
372 | /*! |
373 | \property QGeometryView::firstInstance |
374 | |
375 | Holds the base instance. |
376 | */ |
377 | int QGeometryView::firstInstance() const |
378 | { |
379 | Q_D(const QGeometryView); |
380 | return d->m_firstInstance; |
381 | } |
382 | |
383 | /*! |
384 | \property QGeometryView::firstVertex |
385 | |
386 | Holds the base vertex. |
387 | */ |
388 | int QGeometryView::firstVertex() const |
389 | { |
390 | Q_D(const QGeometryView); |
391 | return d->m_firstVertex; |
392 | } |
393 | |
394 | /*! |
395 | \property QGeometryView::indexBufferByteOffset |
396 | |
397 | Holds the byte offset into the index buffer. |
398 | */ |
399 | int QGeometryView::indexBufferByteOffset() const |
400 | { |
401 | Q_D(const QGeometryView); |
402 | return d->m_indexBufferByteOffset; |
403 | } |
404 | |
405 | /*! |
406 | \property QGeometryView::restartIndexValue |
407 | |
408 | Holds the restart index. |
409 | */ |
410 | int QGeometryView::restartIndexValue() const |
411 | { |
412 | Q_D(const QGeometryView); |
413 | return d->m_restartIndexValue; |
414 | } |
415 | |
416 | /*! |
417 | \property QGeometryView::verticesPerPatch |
418 | |
419 | Holds vertices per patch. |
420 | */ |
421 | int QGeometryView::verticesPerPatch() const |
422 | { |
423 | Q_D(const QGeometryView); |
424 | return d->m_verticesPerPatch; |
425 | } |
426 | |
427 | /*! |
428 | \property QGeometryView::primitiveRestartEnabled |
429 | |
430 | Holds the primitive restart flag. |
431 | */ |
432 | bool QGeometryView::primitiveRestartEnabled() const |
433 | { |
434 | Q_D(const QGeometryView); |
435 | return d->m_primitiveRestart; |
436 | } |
437 | |
438 | /*! |
439 | \property QGeometryView::geometry |
440 | |
441 | Holds the geometry. |
442 | */ |
443 | QGeometry *QGeometryView::geometry() const |
444 | { |
445 | Q_D(const QGeometryView); |
446 | return d->m_geometry; |
447 | } |
448 | |
449 | /*! |
450 | \property QGeometryView::primitiveType |
451 | |
452 | Holds the primitive type. |
453 | */ |
454 | QGeometryView::PrimitiveType QGeometryView::primitiveType() const |
455 | { |
456 | Q_D(const QGeometryView); |
457 | return d->m_primitiveType; |
458 | } |
459 | |
460 | void QGeometryView::setInstanceCount(int instanceCount) |
461 | { |
462 | Q_D(QGeometryView); |
463 | if (d->m_instanceCount == instanceCount) |
464 | return; |
465 | |
466 | d->m_instanceCount = instanceCount; |
467 | emit instanceCountChanged(instanceCount); |
468 | } |
469 | |
470 | void QGeometryView::setVertexCount(int vertexCount) |
471 | { |
472 | Q_D(QGeometryView); |
473 | if (d->m_vertexCount == vertexCount) |
474 | return; |
475 | |
476 | d->m_vertexCount = vertexCount; |
477 | emit vertexCountChanged(vertexCount); |
478 | } |
479 | |
480 | void QGeometryView::setIndexOffset(int indexOffset) |
481 | { |
482 | Q_D(QGeometryView); |
483 | if (d->m_indexOffset == indexOffset) |
484 | return; |
485 | |
486 | d->m_indexOffset = indexOffset; |
487 | emit indexOffsetChanged(indexOffset); |
488 | } |
489 | |
490 | void QGeometryView::setFirstInstance(int firstInstance) |
491 | { |
492 | Q_D(QGeometryView); |
493 | if (d->m_firstInstance == firstInstance) |
494 | return; |
495 | |
496 | d->m_firstInstance = firstInstance; |
497 | emit firstInstanceChanged(firstInstance); |
498 | } |
499 | |
500 | void QGeometryView::setFirstVertex(int firstVertex) |
501 | { |
502 | Q_D(QGeometryView); |
503 | if (d->m_firstVertex == firstVertex) |
504 | return; |
505 | |
506 | d->m_firstVertex = firstVertex; |
507 | emit firstVertexChanged(firstVertex); |
508 | } |
509 | |
510 | void QGeometryView::setIndexBufferByteOffset(int offset) |
511 | { |
512 | Q_D(QGeometryView); |
513 | if (d->m_indexBufferByteOffset == offset) |
514 | return; |
515 | |
516 | d->m_indexBufferByteOffset = offset; |
517 | emit indexBufferByteOffsetChanged(offset); |
518 | } |
519 | |
520 | void QGeometryView::setRestartIndexValue(int index) |
521 | { |
522 | Q_D(QGeometryView); |
523 | if (index == d->m_restartIndexValue) |
524 | return; |
525 | |
526 | d->m_restartIndexValue = index; |
527 | emit restartIndexValueChanged(restartIndexValue: index); |
528 | } |
529 | |
530 | void QGeometryView::setVerticesPerPatch(int verticesPerPatch) |
531 | { |
532 | Q_D(QGeometryView); |
533 | if (d->m_verticesPerPatch != verticesPerPatch) { |
534 | d->m_verticesPerPatch = verticesPerPatch; |
535 | emit verticesPerPatchChanged(verticesPerPatch); |
536 | } |
537 | } |
538 | |
539 | void QGeometryView::setPrimitiveRestartEnabled(bool enabled) |
540 | { |
541 | Q_D(QGeometryView); |
542 | if (enabled == d->m_primitiveRestart) |
543 | return; |
544 | |
545 | d->m_primitiveRestart = enabled; |
546 | emit primitiveRestartEnabledChanged(primitiveRestartEnabled: enabled); |
547 | } |
548 | |
549 | void QGeometryView::setGeometry(QGeometry *geometry) |
550 | { |
551 | Q_D(QGeometryView); |
552 | if (d->m_geometry == geometry) |
553 | return; |
554 | |
555 | if (d->m_geometry) |
556 | d->unregisterDestructionHelper(node: d->m_geometry); |
557 | |
558 | if (geometry && !geometry->parent()) |
559 | geometry->setParent(this); |
560 | |
561 | d->m_geometry = geometry; |
562 | |
563 | // Ensures proper bookkeeping |
564 | if (d->m_geometry) |
565 | d->registerDestructionHelper(node: d->m_geometry, func: &QGeometryView::setGeometry, d->m_geometry); |
566 | |
567 | emit geometryChanged(geometry); |
568 | } |
569 | |
570 | void QGeometryView::setPrimitiveType(QGeometryView::PrimitiveType primitiveType) |
571 | { |
572 | Q_D(QGeometryView); |
573 | if (d->m_primitiveType == primitiveType) |
574 | return; |
575 | |
576 | d->m_primitiveType = primitiveType; |
577 | emit primitiveTypeChanged(primitiveType); |
578 | } |
579 | |
580 | } // namespace Qt3DCore |
581 | |
582 | QT_END_NAMESPACE |
583 | |
584 | #include "moc_qgeometryview.cpp" |
585 | |