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 "qboundingvolume.h" |
5 | #include "qboundingvolume_p.h" |
6 | #include <Qt3DCore/private/corelogging_p.h> |
7 | #include <Qt3DCore/private/calcboundingvolumejob_p.h> |
8 | |
9 | QT_BEGIN_NAMESPACE |
10 | |
11 | namespace Qt3DCore { |
12 | |
13 | bool operator<(const QVector3D &a, const QVector3D &b) { |
14 | return a.x() < b.x() && a.y() < b.y() && a.z() < b.z(); |
15 | } |
16 | |
17 | QBoundingVolumePrivate::QBoundingVolumePrivate() |
18 | : QComponentPrivate() |
19 | , m_view(nullptr) |
20 | , m_implicitRadius(0.0f) |
21 | , m_implicitPointsValid(false) |
22 | , m_explicitPointsValid(false) |
23 | , m_primaryProvider(true) |
24 | { |
25 | } |
26 | |
27 | void QBoundingVolumePrivate::setImplicitBounds(const QVector3D &minPoint, const QVector3D &maxPoint, |
28 | const QVector3D ¢er, float radius) |
29 | { |
30 | Q_Q(QBoundingVolume); |
31 | |
32 | if (!minPoint.isNull() && !maxPoint.isNull() && minPoint < maxPoint) { |
33 | if (m_implicitMinPoint != minPoint) { |
34 | m_implicitMinPoint = minPoint; |
35 | emit q->implicitMinPointChanged(implicitMinPoint: m_implicitMinPoint); |
36 | } |
37 | if (m_implicitMaxPoint != maxPoint) { |
38 | m_implicitMaxPoint = maxPoint; |
39 | emit q->implicitMaxPointChanged(implicitMaxPoint: m_implicitMaxPoint); |
40 | } |
41 | m_implicitCenter = center; |
42 | m_implicitRadius = radius; |
43 | if (!m_implicitPointsValid) { |
44 | m_implicitPointsValid = true; |
45 | emit q->implicitPointsValidChanged(implicitPointsValid: m_implicitPointsValid); |
46 | } |
47 | } else { |
48 | if (m_implicitPointsValid) { |
49 | m_implicitPointsValid = false; |
50 | emit q->implicitPointsValidChanged(implicitPointsValid: m_implicitPointsValid); |
51 | } |
52 | } |
53 | } |
54 | |
55 | void QBoundingVolumePrivate::setView(QGeometryView *view) |
56 | { |
57 | Q_Q(QBoundingVolume); |
58 | |
59 | if (m_view == view) |
60 | return; |
61 | |
62 | if (m_view) |
63 | unregisterDestructionHelper(node: m_view); |
64 | |
65 | if (view && !view->parent()) |
66 | view->setParent(q); |
67 | |
68 | m_view = view; |
69 | |
70 | // Ensures proper bookkeeping |
71 | if (m_view) |
72 | registerDestructionHelper(node: m_view, func: &QBoundingVolume::setView, m_view); |
73 | |
74 | emit q->viewChanged(view); |
75 | } |
76 | |
77 | QBoundingVolumePrivate *QBoundingVolumePrivate::get(QBoundingVolume *q) |
78 | { |
79 | return q->d_func(); |
80 | } |
81 | |
82 | /*! |
83 | * \qmltype BoundingVolume |
84 | * \instantiates Qt3DCore::QBoundingVolume |
85 | * \inqmlmodule Qt3D.Core |
86 | * \since 2.16 |
87 | * |
88 | * \brief can be used to override an entity's bounding volume. |
89 | * |
90 | * An entity's bounding volume is used for many operations such as |
91 | * picking or view frustum culling. It is normally computed by |
92 | * traversing the rendered geometry. |
93 | * |
94 | * BoundingVolume can be used when the extent of the geometry is |
95 | * known to the application so that Qt 3D does not have to |
96 | * compute it. |
97 | * |
98 | * A bounding volume can be provided either as minimum and maximum |
99 | * extent coordinates, or a separate, usually simpler, geometry |
100 | * that approximates the rendered mesh. |
101 | * |
102 | * When using minimum and maximum extents, these are considered |
103 | * to be the opposite corners of an axis aligned bounding box, |
104 | * in the geometry's local coordinate system. |
105 | * |
106 | * BoundingVolume can also be used to query the computed bounding |
107 | * volume of a GeometryView. The implicitMinPoint and implicitMaxPoint |
108 | * properties will be updated if the geometry changes. Note that this |
109 | * is done asynchronously on a background thread so you should check |
110 | * the value of implicitPointsValid before reading them. |
111 | * |
112 | * You can force the implicit extents to be updated by calling |
113 | * updateImplicitBounds. This will block on the calling thread until |
114 | * the results are available. |
115 | * |
116 | * \note GeometryRenderer inherits BoundingVolume and thus supports |
117 | * reading implicit bounds or setting explicit bounds also. |
118 | */ |
119 | |
120 | /*! |
121 | \class Qt3DCore::QBoundingVolume |
122 | \inheaderfile Qt3DCore/QBoundingVolume |
123 | \inmodule Qt3DCore |
124 | \inherits Qt3DCore::QComponent |
125 | \since 6.0 |
126 | \brief can be used to override the bounding volume of an entity. |
127 | |
128 | An entity's bounding volume is used for many operations such as |
129 | picking or view frustum culling. It is normally computed by |
130 | traversing the rendered geometry. |
131 | |
132 | QBoundingVolume can be used when the extent of the geometry is |
133 | known to the application so that Qt 3D does not have to |
134 | compute it. |
135 | |
136 | A bounding volume can be provided either as minimum and maximum |
137 | extent coordinates, or a separate, usually simpler, geometry |
138 | that approximates the rendered mesh. |
139 | |
140 | When using minimum and maximum extents, these are considered |
141 | to be the opposite corners of an axis aligned bounding box, |
142 | in the geometry's local coordinate system. |
143 | |
144 | QBoundingVolume can also be used to query the computed bounding |
145 | volume of a GeometryView. The implicitMinPoint and implicitMaxPoint |
146 | properties will be updated if the geometry changes. Note that this |
147 | is done asynchronously on a background thread so you should check |
148 | the value of implicitPointsValid before reading them. |
149 | |
150 | You can force the implicit extents to be updated by calling |
151 | updateImplicitBounds. This will block on the calling thread until |
152 | the results are available. |
153 | |
154 | \note GeometryRenderer inherits BoundingVolume and thus supports |
155 | reading implicit bounds or setting explicit bounds also. |
156 | */ |
157 | |
158 | /*! |
159 | * Constructs a new QBoundingVolume with \a parent. |
160 | */ |
161 | QBoundingVolume::QBoundingVolume(QNode *parent) |
162 | : QComponent(*new QBoundingVolumePrivate(), parent) |
163 | { |
164 | } |
165 | |
166 | /*! |
167 | * \internal |
168 | */ |
169 | QBoundingVolume::QBoundingVolume(QBoundingVolumePrivate &dd, QNode *parent) |
170 | : QComponent(dd, parent) |
171 | { |
172 | } |
173 | |
174 | /*! |
175 | * \internal |
176 | */ |
177 | QBoundingVolume::~QBoundingVolume() |
178 | { |
179 | } |
180 | |
181 | /*! |
182 | * \qmlproperty GeometryView BoundingVolume::view |
183 | * |
184 | * Holds a pointer to the instance of QGeometryView which will be used, if set, |
185 | * to compute the bounding volume. |
186 | */ |
187 | /*! |
188 | * \property QBoundingVolume::view |
189 | * |
190 | * Holds a pointer to the instance of QGeometryView which will be used, if set, |
191 | * to compute the bounding volume. |
192 | */ |
193 | QGeometryView *QBoundingVolume::view() const |
194 | { |
195 | Q_D(const QBoundingVolume); |
196 | return d->m_view; |
197 | } |
198 | |
199 | /*! |
200 | * \qmlproperty vector3d BoundingVolume::implicitMinPoint |
201 | * |
202 | * Holds minimum extent of the bounding volume computed from the specified view. |
203 | */ |
204 | /*! |
205 | * \property QBoundingVolume::implicitMinPoint |
206 | * |
207 | * Holds minimum extent of the bounding volume computed from the specified view. |
208 | */ |
209 | QVector3D QBoundingVolume::implicitMinPoint() const |
210 | { |
211 | Q_D(const QBoundingVolume); |
212 | return d->m_implicitMinPoint; |
213 | } |
214 | |
215 | /*! |
216 | * \qmlproperty vector3d BoundingVolume::implicitMaxPoint |
217 | * |
218 | * Holds maximum extent of the bounding volume computed from the specified view. |
219 | */ |
220 | /*! |
221 | * \property QBoundingVolume::implicitMaxPoint |
222 | * |
223 | * Holds maximum extent of the bounding volume computed from the specified view. |
224 | */ |
225 | QVector3D QBoundingVolume::implicitMaxPoint() const |
226 | { |
227 | Q_D(const QBoundingVolume); |
228 | return d->m_implicitMaxPoint; |
229 | } |
230 | |
231 | /*! |
232 | * \qmlproperty bool BoundingVolume::implicitPointsValid |
233 | * |
234 | * True if a view has been assigned and the implicit extent properties are up to date. |
235 | * |
236 | * \sa updateImplicitBounds |
237 | */ |
238 | /*! |
239 | * \property QBoundingVolume::implicitPointsValid |
240 | * |
241 | * True if a view has been assigned and the implicit extent properties are up to date. |
242 | * |
243 | * \sa updateImplicitBounds |
244 | */ |
245 | bool QBoundingVolume::areImplicitPointsValid() const |
246 | { |
247 | Q_D(const QBoundingVolume); |
248 | return d->m_implicitPointsValid; |
249 | } |
250 | |
251 | /*! |
252 | * \qmlproperty vector3d BoundingVolume::minPoint |
253 | * |
254 | * User specified minimum extent of the bounding volume. When set (along with maximum |
255 | * extent), this will be used internally to avoid computing the volume from the |
256 | * geometry. |
257 | */ |
258 | /*! |
259 | * \property QBoundingVolume::minPoint |
260 | * |
261 | * User specified minimum extent of the bounding volume. When set (along with maximum |
262 | * extent), this will be used internally to avoid computing the volume from the |
263 | * geometry. |
264 | */ |
265 | QVector3D QBoundingVolume::minPoint() const |
266 | { |
267 | Q_D(const QBoundingVolume); |
268 | return d->m_minPoint; |
269 | } |
270 | |
271 | /*! |
272 | * \qmlproperty vector3d BoundingVolume::maxPoint |
273 | * |
274 | * User specified maximum extent of the bounding volume. When set (along with minimum |
275 | * extent), this will be used internally to avoid computing the volume from the |
276 | * geometry. |
277 | */ |
278 | /*! |
279 | * \property QBoundingVolume::maxPoint |
280 | * |
281 | * User specified maximum extent of the bounding volume. When set (along with minimum |
282 | * extent), this will be used internally to avoid computing the volume from the |
283 | * geometry. |
284 | */ |
285 | QVector3D QBoundingVolume::maxPoint() const |
286 | { |
287 | Q_D(const QBoundingVolume); |
288 | return d->m_maxPoint; |
289 | } |
290 | |
291 | void QBoundingVolume::setView(QGeometryView *view) |
292 | { |
293 | Q_D(QBoundingVolume); |
294 | d->setView(view); |
295 | } |
296 | |
297 | void QBoundingVolume::setMinPoint(const QVector3D &minPoint) |
298 | { |
299 | Q_D(QBoundingVolume); |
300 | if (d->m_minPoint != minPoint) { |
301 | d->m_minPoint = minPoint; |
302 | d->m_explicitPointsValid = true; |
303 | d->markDirty(changes: QScene::GeometryDirty); |
304 | emit minPointChanged(minPoint: d->m_minPoint); |
305 | } |
306 | } |
307 | |
308 | void QBoundingVolume::setMaxPoint(const QVector3D &maxPoint) |
309 | { |
310 | Q_D(QBoundingVolume); |
311 | if (d->m_maxPoint != maxPoint) { |
312 | d->m_maxPoint = maxPoint; |
313 | d->m_explicitPointsValid = true; |
314 | d->markDirty(changes: QScene::GeometryDirty); |
315 | emit maxPointChanged(maxPoint: d->m_maxPoint); |
316 | } |
317 | } |
318 | |
319 | /*! |
320 | * \qmlmethod bool BoundingVolume::updateImplicitBounds() |
321 | * |
322 | * Updates the implicit bounds of the specified view. Returns |
323 | * \c true if the computation succeeded and false otherwise. |
324 | * |
325 | * \note The calculations are done in the call thread, this |
326 | * could take significant time for large meshes. |
327 | */ |
328 | |
329 | /*! |
330 | * Updates the implicit bounds of the specified view. Returns |
331 | * \c true if the computation succeeded and false otherwise. |
332 | * |
333 | * \note The calculations are done in the call thread, this |
334 | * could take significant time for large meshes. |
335 | */ |
336 | bool QBoundingVolume::updateImplicitBounds() |
337 | { |
338 | Q_D(QBoundingVolume); |
339 | if (!d->m_view) |
340 | return false; |
341 | |
342 | auto data = BoundingVolumeComputeData::fromView(view: d->m_view); |
343 | if (!data.valid()) |
344 | return false; |
345 | |
346 | auto res = data.compute(); |
347 | if (!res.valid()) |
348 | return false; |
349 | |
350 | d->setImplicitBounds(minPoint: res.m_min, maxPoint: res.m_max, center: res.m_center, radius: res.m_radius); |
351 | return true; |
352 | } |
353 | |
354 | } // namespace Qt3DCore |
355 | |
356 | QT_END_NAMESPACE |
357 | |
358 | #include "moc_qboundingvolume.cpp" |
359 | |