| /**************************************************************************** |
| ** |
| ** Copyright (C) 2018 Klaralvdalens Datakonsult AB (KDAB). |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the Qt3D module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU Lesser General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Lesser |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
| ** packaging of this file. Please review the following information to |
| ** ensure the GNU Lesser General Public License version 3 requirements |
| ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 2.0 or (at your option) the GNU General |
| ** Public license version 3 or any later version approved by the KDE Free |
| ** Qt Foundation. The licenses are as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
| ** https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "qabstractraycaster.h" |
| #include "qabstractraycaster_p.h" |
| #include <Qt3DCore/qentity.h> |
| #include <Qt3DCore/qpropertyupdatedchange.h> |
| #include <Qt3DCore/qpropertynodeaddedchange.h> |
| #include <Qt3DCore/qpropertynoderemovedchange.h> |
| #include <Qt3DCore/private/qcomponent_p.h> |
| #include <Qt3DCore/private/qscene_p.h> |
| #include <Qt3DRender/qlayer.h> |
| |
| QT_BEGIN_NAMESPACE |
| |
| namespace Qt3DRender { |
| |
| QAbstractRayCasterPrivate::QAbstractRayCasterPrivate() |
| : QComponentPrivate() |
| { |
| m_enabled = false; |
| m_shareable = false; |
| } |
| |
| QAbstractRayCasterPrivate *QAbstractRayCasterPrivate::get(QAbstractRayCaster *obj) |
| { |
| return obj->d_func(); |
| } |
| |
| const QAbstractRayCasterPrivate *QAbstractRayCasterPrivate::get(const QAbstractRayCaster *obj) |
| { |
| return obj->d_func(); |
| } |
| |
| void QAbstractRayCasterPrivate::updateHitEntites(QAbstractRayCaster::Hits &hits, Qt3DCore::QScene *scene) |
| { |
| for (int i = 0; i < hits.size(); i++) |
| hits[i].setEntity(qobject_cast<Qt3DCore::QEntity *>(scene->lookupNode(hits[i].entityId()))); |
| } |
| |
| void QAbstractRayCasterPrivate::dispatchHits(const QAbstractRayCaster::Hits &hits) |
| { |
| Q_Q(QAbstractRayCaster); |
| m_hits = hits; |
| updateHitEntites(m_hits, m_scene); |
| bool v = q->blockNotifications(true); |
| emit q->hitsChanged(m_hits); |
| q->blockNotifications(v); |
| } |
| |
| /*! |
| \class Qt3DRender::QAbstractRayCaster |
| \brief An abstract base class for ray casting in 3d scenes. |
| \inmodule Qt3DRender |
| \since 5.11 |
| \inherits QComponent |
| |
| Qt3DRender::QAbstractRayCaster is an abstract base class for casting rays into a 3d scene. |
| Qt3DRender::QAbstractRayCaster can not be directly instantiated, but rather |
| through its subclasses. QAbstractRayCaster specifies common properties |
| for all ray casters, such as run mode and layer handling, while leaving the actual |
| ray casting details to the subclasses. |
| |
| Ray castings differs from picking (using Qt3DRender::QObjectPicker) in that it does not |
| require mouse events to trigger. |
| |
| By default, the instances of Qt3DRender::QAbstractRayCaster are disabled. When enabled, |
| the specified ray will be tested for intersecting objects at every frame. The |
| QAbstractRayCaster::hits property will be updated with the results of the ray casting, |
| even if no objects are found. |
| |
| The Qt3DRender::QPickingSettings can be used to control the ray casting, such as which |
| primitives are tested and how the results are returned. |
| |
| Furthermore, Qt3DRender::QLayer components can be used to control how entities, or entity |
| sub-graphs, react to ray casting. |
| |
| \note Components derived from QAbstractRayCaster should not be shared amount multiple entities. |
| |
| \sa Qt3DRender::QRayCaster, Qt3DRender::QScreenRayCaster, Qt3DRender::QObjectPicker, |
| Qt3DRender::QPickingSettings, Qt3DRender::QNoPicking |
| */ |
| /*! |
| \qmltype AbstractRayCaster |
| \brief An abstract base class for ray casting in 3d scenes. |
| \inqmlmodule Qt3D.Render |
| \since 5.11 |
| \instantiates Qt3DRender::QAbstractRayCaster |
| |
| AbstractRayCaster is an abstract base class for casting rays into a 3d scene. |
| AbstractRayCaster can not be directly instantiated, but rather |
| through its subclasses. QAbstractRayCaster specifies common properties |
| for all ray casters, such as run mode and layer handling, while leaving the actual |
| ray casting details to the subclasses. |
| |
| Ray castings differs from picking (using ObjectPicker) in that it does not |
| require mouse events to trigger. |
| |
| By default, the instances of AbstractRayCaster are disabled. When enabled, |
| the specified ray will be tested for intersecting objects at every frame. The |
| AbstractRayCaster.hits property will be updated with the results of the ray casting, |
| even if no objects are found. |
| |
| The Qt3D.Render::PickingSettings can be used to control the ray casting, such as which |
| primitives are tested and how the results are returned. |
| |
| Furthermore, Qt3D.Render::Layer components can be used to control how entities, or entity |
| sub-graphs, react to ray casting. |
| |
| Note: components derived from AbstractRayCaster should not be shared amount multiple entities. |
| |
| \sa Qt3D.Render::RayCaster, Qt3D.Render::ScreenRayCaster, Qt3D.Render::ObjectPicker, |
| Qt3D.Render::PickingSettings, Qt3D.Render::NoPicking |
| */ |
| |
| /*! |
| \enum QAbstractRayCaster::RunMode |
| |
| This enumeration specifies how often ray casting is performed |
| \value Continuous Ray casting is performed at every frame as long as the component is enabled. |
| \value SingleShot Ray casting is done once then the component disables itself. This is the default |
| */ |
| /*! |
| \enum QAbstractRayCaster::FilterMode |
| |
| Specifies the rules for selecting entities to test for raycasting. |
| |
| \value AcceptAnyMatchingLayers |
| Accept entities that reference one or more \l QLayer objects added to this |
| QAbstractRayCaster. This is the default |
| |
| \value AcceptAllMatchingLayers |
| Accept entities that reference all the \l QLayer objects added to this QAbstractRayCaster |
| |
| \value DiscardAnyMatchingLayers |
| Discard entities that reference one or more \l QLayer objects added to this QAbstractRayCaster |
| |
| \value DiscardAllMatchingLayers |
| Discard entities that reference all \l QLayer objects added to this QAbstractRayCaster |
| */ |
| |
| /*! |
| \property Qt3DRender::QAbstractRayCaster::filterMode |
| |
| Holds the filter mode specifying the entities to select for ray casting tests. |
| |
| The default value is AcceptMatchingLayers. |
| */ |
| /*! |
| \qmlproperty enumeration AbstractRayCaster::filterMode |
| |
| Holds the filter mode specifying the entities to select for ray casting tests. |
| |
| The default value is \c {AbstractRayCaster.AcceptMatchingLayers}. |
| |
| \value AcceptAnyMatchingLayers |
| Accept entities that reference one or more \l Layer objects added to this |
| AbstractRayCaster. This is the default |
| |
| \value AcceptAllMatchingLayers |
| Accept entities that reference all the \l Layer objects added to this AbstractRayCaster |
| |
| \value DiscardAnyMatchingLayers |
| Discard entities that reference one or more \l Layer objects added to this AbstractRayCaster |
| |
| \value DiscardAllMatchingLayers |
| Discard entities that reference all \l Layer objects added to this AbstractRayCaster |
| */ |
| |
| /*! |
| \property Qt3DRender::QAbstractRayCaster::runMode |
| |
| Holds the run mode controlling how often ray casting tests are performed. |
| |
| If set to SingleShot (the default), when the component is enabled, a single ray casting |
| test will be performed and the component will automatically disable itself. |
| |
| If set to Continuous, ray casting tests will be performed at every frame as long as |
| the component is enabled. |
| */ |
| /*! |
| \qmlproperty enumeration AbstractRayCaster::runMode |
| Holds the run mode controlling how often ray casting tests are performed. |
| |
| \value Continuous Ray casting is performed at every frame as long as the component is enabled. |
| |
| \value SingleShot Ray casting is done once then the component disables itself. This is the default |
| */ |
| |
| /*! |
| \property Qt3DRender::QAbstractRayCaster::hits |
| |
| Holds the results of last ray casting test as a vector of Qt3DRender::QRayCasterHit instances. |
| |
| Note that even if successive tests return the exact same results (or empty results), a |
| change notification will be emitted at every test. |
| */ |
| |
| /*! |
| \qmlproperty array AbstractRayCaster::hits |
| |
| Holds the results of last ray casting test as an array of javascript objects. The fields |
| defined on the objects are defined below. |
| |
| \code |
| { |
| type // enum value of RayCasterHit.HitType |
| entity // entity that was intersected |
| distance // distance from ray origin to intersection |
| localIntersection.x: // coordinate of intersection in the entity's coordinate system |
| localIntersection.y |
| localIntersection.z |
| worldIntersection.x // coordinate of intersection in the model's coordinate system |
| worldIntersection.y |
| worldIntersection.z |
| primitiveIndex // index of the primitive (triangle, line, point) that was intersected; |
| // (undefined if the picking mode is set to bounding volume) |
| vertex1Index // index of the first point of the triangle or line that was intersected |
| // (undefined if the picking mode is set to bounding volume or points) |
| vertex2Index // index of the second point of the triangle or line that was intersected |
| // (undefined if the picking mode is set to bounding volume or points) |
| vertex3Index // index of the second point of the triangle that was intersected |
| // (undefined if the picking mode is set to bounding volume, points or lines) |
| } |
| \endcode |
| |
| Note that even if successive tests return the exact same results (or empty results), a |
| change notification will be emitted at every test. |
| */ |
| |
| |
| QAbstractRayCaster::QAbstractRayCaster(Qt3DCore::QNode *parent) |
| : Qt3DCore::QComponent(*new QAbstractRayCasterPrivate(), parent) |
| { |
| } |
| |
| /*! \internal */ |
| QAbstractRayCaster::QAbstractRayCaster(QAbstractRayCasterPrivate &dd, Qt3DCore::QNode *parent) |
| : Qt3DCore::QComponent(dd, parent) |
| { |
| } |
| |
| /*! \internal */ |
| QAbstractRayCaster::~QAbstractRayCaster() |
| { |
| } |
| |
| QAbstractRayCaster::RunMode QAbstractRayCaster::runMode() const |
| { |
| Q_D(const QAbstractRayCaster); |
| return d->m_runMode; |
| } |
| |
| void QAbstractRayCaster::setRunMode(QAbstractRayCaster::RunMode runMode) |
| { |
| Q_D(QAbstractRayCaster); |
| if (d->m_runMode != runMode) { |
| d->m_runMode = runMode; |
| emit runModeChanged(d->m_runMode); |
| } |
| } |
| |
| QAbstractRayCaster::FilterMode QAbstractRayCaster::filterMode() const |
| { |
| Q_D(const QAbstractRayCaster); |
| return d->m_filterMode; |
| } |
| |
| void QAbstractRayCaster::setFilterMode(QAbstractRayCaster::FilterMode filterMode) |
| { |
| Q_D(QAbstractRayCaster); |
| if (d->m_filterMode != filterMode) { |
| d->m_filterMode = filterMode; |
| emit filterModeChanged(d->m_filterMode); |
| } |
| } |
| |
| QAbstractRayCaster::Hits QAbstractRayCaster::hits() const |
| { |
| Q_D(const QAbstractRayCaster); |
| return d->m_hits; |
| } |
| |
| /*! |
| Add \a layer to the current list of layers |
| */ |
| void QAbstractRayCaster::addLayer(QLayer *layer) |
| { |
| Q_ASSERT(layer); |
| Q_D(QAbstractRayCaster); |
| if (!d->m_layers.contains(layer)) { |
| d->m_layers.append(layer); |
| |
| // Ensures proper bookkeeping |
| d->registerDestructionHelper(layer, &QAbstractRayCaster::removeLayer, d->m_layers); |
| |
| // We need to add it as a child of the current node if it has been declared inline |
| // Or not previously added as a child of the current node so that |
| // 1) The backend gets notified about it's creation |
| // 2) When the current node is destroyed, it gets destroyed as well |
| if (!layer->parent()) |
| layer->setParent(this); |
| |
| d->updateNode(layer, "layer", Qt3DCore::PropertyValueAdded); |
| } |
| } |
| |
| /*! |
| Remove \a layer from the current list of layers |
| */ |
| void QAbstractRayCaster::removeLayer(QLayer *layer) |
| { |
| Q_ASSERT(layer); |
| Q_D(QAbstractRayCaster); |
| if (!d->m_layers.removeOne(layer)) |
| return; |
| d->updateNode(layer, "layer", Qt3DCore::PropertyValueRemoved); |
| // Remove bookkeeping connection |
| d->unregisterDestructionHelper(layer); |
| } |
| |
| /*! |
| \return the current list of layers |
| */ |
| QVector<QLayer *> QAbstractRayCaster::layers() const |
| { |
| Q_D(const QAbstractRayCaster); |
| return d->m_layers; |
| } |
| |
| /*! \internal */ |
| void QAbstractRayCaster::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) |
| { |
| Q_D(QAbstractRayCaster); |
| Qt3DCore::QPropertyUpdatedChangePtr e = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(change); |
| if (e->type() == Qt3DCore::PropertyUpdated) { |
| const QByteArray propertyName = e->propertyName(); |
| if (propertyName == QByteArrayLiteral("hits")) { |
| Hits hits = e->value().value<Hits>(); |
| d->dispatchHits(hits); |
| } |
| } |
| |
| QComponent::sceneChangeEvent(change); |
| } |
| |
| /*! \internal */ |
| Qt3DCore::QNodeCreatedChangeBasePtr QAbstractRayCaster::createNodeCreationChange() const |
| { |
| auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QAbstractRayCasterData>::create(this); |
| auto &data = creationChange->data; |
| Q_D(const QAbstractRayCaster); |
| data.casterType = d->m_rayCasterType; |
| data.runMode = d->m_runMode; |
| data.origin = d->m_origin; |
| data.direction = d->m_direction; |
| data.length = d->m_length; |
| data.position = d->m_position; |
| data.filterMode = d->m_filterMode; |
| data.layerIds = qIdsForNodes(d->m_layers); |
| return creationChange; |
| } |
| |
| } // Qt3DRender |
| |
| QT_END_NAMESPACE |