1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2017 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:GPL-EXCEPT$ |
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 General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | #include "filterproximitydistancejob_p.h" |
30 | #include <Qt3DRender/private/managers_p.h> |
31 | #include <Qt3DRender/private/nodemanagers_p.h> |
32 | #include <Qt3DRender/private/entity_p.h> |
33 | #include <Qt3DRender/private/proximityfilter_p.h> |
34 | #include <Qt3DRender/private/job_common_p.h> |
35 | #include <Qt3DRender/private/sphere_p.h> |
36 | |
37 | QT_BEGIN_NAMESPACE |
38 | |
39 | namespace Qt3DRender { |
40 | |
41 | namespace Render { |
42 | |
43 | namespace { |
44 | int instanceCounter = 0; |
45 | } // anonymous |
46 | |
47 | |
48 | FilterProximityDistanceJob::FilterProximityDistanceJob() |
49 | : m_manager(nullptr) |
50 | , m_targetEntity(nullptr) |
51 | , m_distanceThresholdSquared(0.) |
52 | { |
53 | SET_JOB_RUN_STAT_TYPE(this, JobTypes::ProximityFiltering, instanceCounter++) |
54 | } |
55 | |
56 | FilterProximityDistanceJob::~FilterProximityDistanceJob() |
57 | { |
58 | --instanceCounter; |
59 | } |
60 | |
61 | void FilterProximityDistanceJob::run() |
62 | { |
63 | Q_ASSERT(m_manager != nullptr); |
64 | m_filteredEntities.clear(); |
65 | |
66 | // Fill m_filteredEntities |
67 | // If no filtering needs to be done, this will be the output value |
68 | // otherwise it will be used as the base list of entities to filter |
69 | |
70 | if (hasProximityFilter()) { |
71 | selectAllEntities(); |
72 | QVector<Entity *> entitiesToFilter = std::move(m_filteredEntities); |
73 | FrameGraphManager *frameGraphManager = m_manager->frameGraphManager(); |
74 | EntityManager *entityManager = m_manager->renderNodesManager(); |
75 | |
76 | for (const Qt3DCore::QNodeId proximityFilterId : qAsConst(t&: m_proximityFilterIds)) { |
77 | ProximityFilter *proximityFilter = static_cast<ProximityFilter *>(frameGraphManager->lookupNode(id: proximityFilterId)); |
78 | m_targetEntity = entityManager->lookupResource(id: proximityFilter->entityId()); |
79 | m_distanceThresholdSquared = proximityFilter->distanceThreshold(); |
80 | m_distanceThresholdSquared *= m_distanceThresholdSquared; |
81 | |
82 | // We can't filter, select nothings |
83 | if (m_targetEntity == nullptr || m_distanceThresholdSquared <= 0.0f) { |
84 | m_filteredEntities.clear(); |
85 | return; |
86 | } |
87 | // Otherwise we filter |
88 | filterEntities(entitiesToFilter); |
89 | |
90 | // And we make the filtered subset be the list of entities to filter |
91 | // for the next loop |
92 | entitiesToFilter = std::move(m_filteredEntities); |
93 | } |
94 | m_filteredEntities = std::move(entitiesToFilter); |
95 | } |
96 | |
97 | // sort needed for set_intersection in RenderViewBuilder |
98 | std::sort(first: m_filteredEntities.begin(), last: m_filteredEntities.end()); |
99 | } |
100 | |
101 | void FilterProximityDistanceJob::selectAllEntities() |
102 | { |
103 | EntityManager *entityManager = m_manager->renderNodesManager(); |
104 | const std::vector<HEntity> &handles = entityManager->activeHandles(); |
105 | |
106 | m_filteredEntities.reserve(asize: handles.size()); |
107 | for (const HEntity &handle : handles) { |
108 | Entity *e = entityManager->data(handle); |
109 | m_filteredEntities.push_back(t: e); |
110 | } |
111 | } |
112 | |
113 | void FilterProximityDistanceJob::filterEntities(const QVector<Entity *> &entitiesToFilter) |
114 | { |
115 | const Sphere *target = m_targetEntity->worldBoundingVolumeWithChildren(); |
116 | |
117 | for (Entity *entity : entitiesToFilter) { |
118 | // Note: The target entity is always selected as distance will be 0 |
119 | |
120 | // Retrieve center of bounding volume for entity |
121 | const Sphere *s = entity->worldBoundingVolumeWithChildren(); |
122 | |
123 | // If distance between entity and target is less than threshold, we keep the entity |
124 | if ((s->center() - target->center()).lengthSquared() <= m_distanceThresholdSquared) |
125 | m_filteredEntities.push_back(t: entity); |
126 | } |
127 | } |
128 | |
129 | } // Render |
130 | |
131 | } // Qt3DRender |
132 | |
133 | QT_END_NAMESPACE |
134 | |