1/****************************************************************************
2**
3** Copyright (C) 2018 Klaralvdalens Datakonsult AB (KDAB).
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt3D module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qabstractraycaster.h"
41#include "qabstractraycaster_p.h"
42#include <Qt3DCore/qentity.h>
43#include <Qt3DCore/qpropertyupdatedchange.h>
44#include <Qt3DCore/qpropertynodeaddedchange.h>
45#include <Qt3DCore/qpropertynoderemovedchange.h>
46#include <Qt3DCore/private/qcomponent_p.h>
47#include <Qt3DCore/private/qscene_p.h>
48#include <Qt3DRender/qlayer.h>
49
50QT_BEGIN_NAMESPACE
51
52namespace Qt3DRender {
53
54QAbstractRayCasterPrivate::QAbstractRayCasterPrivate()
55 : QComponentPrivate()
56{
57 m_enabled = false;
58 m_shareable = false;
59}
60
61QAbstractRayCasterPrivate *QAbstractRayCasterPrivate::get(QAbstractRayCaster *obj)
62{
63 return obj->d_func();
64}
65
66const QAbstractRayCasterPrivate *QAbstractRayCasterPrivate::get(const QAbstractRayCaster *obj)
67{
68 return obj->d_func();
69}
70
71void QAbstractRayCasterPrivate::updateHitEntites(QAbstractRayCaster::Hits &hits, Qt3DCore::QScene *scene)
72{
73 for (int i = 0; i < hits.size(); i++)
74 hits[i].setEntity(qobject_cast<Qt3DCore::QEntity *>(object: scene->lookupNode(id: hits[i].entityId())));
75}
76
77void QAbstractRayCasterPrivate::dispatchHits(const QAbstractRayCaster::Hits &hits)
78{
79 Q_Q(QAbstractRayCaster);
80 m_hits = hits;
81 updateHitEntites(hits&: m_hits, scene: m_scene);
82 bool v = q->blockNotifications(block: true);
83 emit q->hitsChanged(hits: m_hits);
84 q->blockNotifications(block: v);
85}
86
87/*!
88 \class Qt3DRender::QAbstractRayCaster
89 \brief An abstract base class for ray casting in 3d scenes.
90 \inmodule Qt3DRender
91 \since 5.11
92 \inherits QComponent
93
94 Qt3DRender::QAbstractRayCaster is an abstract base class for casting rays into a 3d scene.
95 Qt3DRender::QAbstractRayCaster can not be directly instantiated, but rather
96 through its subclasses. QAbstractRayCaster specifies common properties
97 for all ray casters, such as run mode and layer handling, while leaving the actual
98 ray casting details to the subclasses.
99
100 Ray castings differs from picking (using Qt3DRender::QObjectPicker) in that it does not
101 require mouse events to trigger.
102
103 By default, the instances of Qt3DRender::QAbstractRayCaster are disabled. When enabled,
104 the specified ray will be tested for intersecting objects at every frame. The
105 QAbstractRayCaster::hits property will be updated with the results of the ray casting,
106 even if no objects are found.
107
108 The Qt3DRender::QPickingSettings can be used to control the ray casting, such as which
109 primitives are tested and how the results are returned.
110
111 Furthermore, Qt3DRender::QLayer components can be used to control how entities, or entity
112 sub-graphs, react to ray casting.
113
114 \note Components derived from QAbstractRayCaster should not be shared amount multiple entities.
115
116 \sa Qt3DRender::QRayCaster, Qt3DRender::QScreenRayCaster, Qt3DRender::QObjectPicker,
117 Qt3DRender::QPickingSettings, Qt3DRender::QNoPicking
118*/
119/*!
120 \qmltype AbstractRayCaster
121 \brief An abstract base class for ray casting in 3d scenes.
122 \inqmlmodule Qt3D.Render
123 \since 5.11
124 \instantiates Qt3DRender::QAbstractRayCaster
125
126 AbstractRayCaster is an abstract base class for casting rays into a 3d scene.
127 AbstractRayCaster can not be directly instantiated, but rather
128 through its subclasses. QAbstractRayCaster specifies common properties
129 for all ray casters, such as run mode and layer handling, while leaving the actual
130 ray casting details to the subclasses.
131
132 Ray castings differs from picking (using ObjectPicker) in that it does not
133 require mouse events to trigger.
134
135 By default, the instances of AbstractRayCaster are disabled. When enabled,
136 the specified ray will be tested for intersecting objects at every frame. The
137 AbstractRayCaster.hits property will be updated with the results of the ray casting,
138 even if no objects are found.
139
140 The Qt3D.Render::PickingSettings can be used to control the ray casting, such as which
141 primitives are tested and how the results are returned.
142
143 Furthermore, Qt3D.Render::Layer components can be used to control how entities, or entity
144 sub-graphs, react to ray casting.
145
146 Note: components derived from AbstractRayCaster should not be shared amount multiple entities.
147
148 \sa Qt3D.Render::RayCaster, Qt3D.Render::ScreenRayCaster, Qt3D.Render::ObjectPicker,
149 Qt3D.Render::PickingSettings, Qt3D.Render::NoPicking
150*/
151
152/*!
153 \enum QAbstractRayCaster::RunMode
154
155 This enumeration specifies how often ray casting is performed
156 \value Continuous Ray casting is performed at every frame as long as the component is enabled.
157 \value SingleShot Ray casting is done once then the component disables itself. This is the default
158*/
159/*!
160 \enum QAbstractRayCaster::FilterMode
161
162 Specifies the rules for selecting entities to test for raycasting.
163
164 \value AcceptAnyMatchingLayers
165 Accept entities that reference one or more \l QLayer objects added to this
166 QAbstractRayCaster. This is the default
167
168 \value AcceptAllMatchingLayers
169 Accept entities that reference all the \l QLayer objects added to this QAbstractRayCaster
170
171 \value DiscardAnyMatchingLayers
172 Discard entities that reference one or more \l QLayer objects added to this QAbstractRayCaster
173
174 \value DiscardAllMatchingLayers
175 Discard entities that reference all \l QLayer objects added to this QAbstractRayCaster
176*/
177
178/*!
179 \property Qt3DRender::QAbstractRayCaster::filterMode
180
181 Holds the filter mode specifying the entities to select for ray casting tests.
182
183 The default value is AcceptMatchingLayers.
184*/
185/*!
186 \qmlproperty enumeration AbstractRayCaster::filterMode
187
188 Holds the filter mode specifying the entities to select for ray casting tests.
189
190 The default value is \c {AbstractRayCaster.AcceptMatchingLayers}.
191
192 \value AcceptAnyMatchingLayers
193 Accept entities that reference one or more \l Layer objects added to this
194 AbstractRayCaster. This is the default
195
196 \value AcceptAllMatchingLayers
197 Accept entities that reference all the \l Layer objects added to this AbstractRayCaster
198
199 \value DiscardAnyMatchingLayers
200 Discard entities that reference one or more \l Layer objects added to this AbstractRayCaster
201
202 \value DiscardAllMatchingLayers
203 Discard entities that reference all \l Layer objects added to this AbstractRayCaster
204*/
205
206/*!
207 \property Qt3DRender::QAbstractRayCaster::runMode
208
209 Holds the run mode controlling how often ray casting tests are performed.
210
211 If set to SingleShot (the default), when the component is enabled, a single ray casting
212 test will be performed and the component will automatically disable itself.
213
214 If set to Continuous, ray casting tests will be performed at every frame as long as
215 the component is enabled.
216*/
217/*!
218 \qmlproperty enumeration AbstractRayCaster::runMode
219 Holds the run mode controlling how often ray casting tests are performed.
220
221 \value Continuous Ray casting is performed at every frame as long as the component is enabled.
222
223 \value SingleShot Ray casting is done once then the component disables itself. This is the default
224*/
225
226/*!
227 \property Qt3DRender::QAbstractRayCaster::hits
228
229 Holds the results of last ray casting test as a vector of Qt3DRender::QRayCasterHit instances.
230
231 Note that even if successive tests return the exact same results (or empty results), a
232 change notification will be emitted at every test.
233*/
234
235/*!
236 \qmlproperty array AbstractRayCaster::hits
237
238 Holds the results of last ray casting test as an array of javascript objects. The fields
239 defined on the objects are defined below.
240
241 \code
242 {
243 type // enum value of RayCasterHit.HitType
244 entity // entity that was intersected
245 distance // distance from ray origin to intersection
246 localIntersection.x: // coordinate of intersection in the entity's coordinate system
247 localIntersection.y
248 localIntersection.z
249 worldIntersection.x // coordinate of intersection in the model's coordinate system
250 worldIntersection.y
251 worldIntersection.z
252 primitiveIndex // index of the primitive (triangle, line, point) that was intersected;
253 // (undefined if the picking mode is set to bounding volume)
254 vertex1Index // index of the first point of the triangle or line that was intersected
255 // (undefined if the picking mode is set to bounding volume or points)
256 vertex2Index // index of the second point of the triangle or line that was intersected
257 // (undefined if the picking mode is set to bounding volume or points)
258 vertex3Index // index of the second point of the triangle that was intersected
259 // (undefined if the picking mode is set to bounding volume, points or lines)
260 }
261 \endcode
262
263 Note that even if successive tests return the exact same results (or empty results), a
264 change notification will be emitted at every test.
265*/
266
267
268QAbstractRayCaster::QAbstractRayCaster(Qt3DCore::QNode *parent)
269 : Qt3DCore::QComponent(*new QAbstractRayCasterPrivate(), parent)
270{
271}
272
273/*! \internal */
274QAbstractRayCaster::QAbstractRayCaster(QAbstractRayCasterPrivate &dd, Qt3DCore::QNode *parent)
275 : Qt3DCore::QComponent(dd, parent)
276{
277}
278
279/*! \internal */
280QAbstractRayCaster::~QAbstractRayCaster()
281{
282}
283
284QAbstractRayCaster::RunMode QAbstractRayCaster::runMode() const
285{
286 Q_D(const QAbstractRayCaster);
287 return d->m_runMode;
288}
289
290void QAbstractRayCaster::setRunMode(QAbstractRayCaster::RunMode runMode)
291{
292 Q_D(QAbstractRayCaster);
293 if (d->m_runMode != runMode) {
294 d->m_runMode = runMode;
295 emit runModeChanged(runMode: d->m_runMode);
296 }
297}
298
299QAbstractRayCaster::FilterMode QAbstractRayCaster::filterMode() const
300{
301 Q_D(const QAbstractRayCaster);
302 return d->m_filterMode;
303}
304
305void QAbstractRayCaster::setFilterMode(QAbstractRayCaster::FilterMode filterMode)
306{
307 Q_D(QAbstractRayCaster);
308 if (d->m_filterMode != filterMode) {
309 d->m_filterMode = filterMode;
310 emit filterModeChanged(filterMode: d->m_filterMode);
311 }
312}
313
314QAbstractRayCaster::Hits QAbstractRayCaster::hits() const
315{
316 Q_D(const QAbstractRayCaster);
317 return d->m_hits;
318}
319
320/*!
321 Add \a layer to the current list of layers
322 */
323void QAbstractRayCaster::addLayer(QLayer *layer)
324{
325 Q_ASSERT(layer);
326 Q_D(QAbstractRayCaster);
327 if (!d->m_layers.contains(t: layer)) {
328 d->m_layers.append(t: layer);
329
330 // Ensures proper bookkeeping
331 d->registerDestructionHelper(node: layer, func: &QAbstractRayCaster::removeLayer, d->m_layers);
332
333 // We need to add it as a child of the current node if it has been declared inline
334 // Or not previously added as a child of the current node so that
335 // 1) The backend gets notified about it's creation
336 // 2) When the current node is destroyed, it gets destroyed as well
337 if (!layer->parent())
338 layer->setParent(this);
339
340 d->updateNode(node: layer, property: "layer", change: Qt3DCore::PropertyValueAdded);
341 }
342}
343
344/*!
345 Remove \a layer from the current list of layers
346 */
347void QAbstractRayCaster::removeLayer(QLayer *layer)
348{
349 Q_ASSERT(layer);
350 Q_D(QAbstractRayCaster);
351 if (!d->m_layers.removeOne(t: layer))
352 return;
353 d->updateNode(node: layer, property: "layer", change: Qt3DCore::PropertyValueRemoved);
354 // Remove bookkeeping connection
355 d->unregisterDestructionHelper(node: layer);
356}
357
358/*!
359 \return the current list of layers
360 */
361QVector<QLayer *> QAbstractRayCaster::layers() const
362{
363 Q_D(const QAbstractRayCaster);
364 return d->m_layers;
365}
366
367/*! \internal */
368void QAbstractRayCaster::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
369{
370 Q_D(QAbstractRayCaster);
371 Qt3DCore::QPropertyUpdatedChangePtr e = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(src: change);
372 if (e->type() == Qt3DCore::PropertyUpdated) {
373 const QByteArray propertyName = e->propertyName();
374 if (propertyName == QByteArrayLiteral("hits")) {
375 Hits hits = e->value().value<Hits>();
376 d->dispatchHits(hits);
377 }
378 }
379
380 QComponent::sceneChangeEvent(change);
381}
382
383/*! \internal */
384Qt3DCore::QNodeCreatedChangeBasePtr QAbstractRayCaster::createNodeCreationChange() const
385{
386 auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QAbstractRayCasterData>::create(arguments: this);
387 auto &data = creationChange->data;
388 Q_D(const QAbstractRayCaster);
389 data.casterType = d->m_rayCasterType;
390 data.runMode = d->m_runMode;
391 data.origin = d->m_origin;
392 data.direction = d->m_direction;
393 data.length = d->m_length;
394 data.position = d->m_position;
395 data.filterMode = d->m_filterMode;
396 data.layerIds = qIdsForNodes(nodes: d->m_layers);
397 return creationChange;
398}
399
400} // Qt3DRender
401
402QT_END_NAMESPACE
403

source code of qt3d/src/render/picking/qabstractraycaster.cpp