1/****************************************************************************
2**
3** Copyright (C) 2016 Paul Lemire
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 "filterlayerentityjob_p.h"
41#include <Qt3DRender/private/managers_p.h>
42#include <Qt3DRender/private/nodemanagers_p.h>
43#include <Qt3DRender/private/entity_p.h>
44#include <Qt3DRender/private/job_common_p.h>
45#include <Qt3DRender/private/layerfilternode_p.h>
46
47QT_BEGIN_NAMESPACE
48
49namespace Qt3DRender {
50
51namespace Render {
52
53namespace {
54int layerFilterJobCounter = 0;
55} // anonymous
56
57FilterLayerEntityJob::FilterLayerEntityJob()
58 : Qt3DCore::QAspectJob()
59 , m_manager(nullptr)
60{
61 SET_JOB_RUN_STAT_TYPE(this, JobTypes::LayerFiltering, layerFilterJobCounter++)
62}
63
64
65void FilterLayerEntityJob::run()
66{
67
68 m_filteredEntities.clear();
69 if (hasLayerFilter()) // LayerFilter set -> filter
70 filterLayerAndEntity();
71 else // No LayerFilter set -> retrieve all
72 selectAllEntities();
73
74 // sort needed for set_intersection in RenderViewBuilder
75 std::sort(first: m_filteredEntities.begin(), last: m_filteredEntities.end());
76}
77
78void FilterLayerEntityJob::filterEntityAgainstLayers(Entity *entity,
79 const Qt3DCore::QNodeIdVector &layerIds,
80 const QLayerFilter::FilterMode filterMode)
81{
82 // Perform filtering
83 switch (filterMode) {
84 case QLayerFilter::AcceptAnyMatchingLayers: {
85 filterAcceptAnyMatchingLayers(entity, layerIds);
86 break;
87 }
88 case QLayerFilter::AcceptAllMatchingLayers: {
89 filterAcceptAllMatchingLayers(entity, layerIds);
90 break;
91 }
92 case QLayerFilter::DiscardAnyMatchingLayers: {
93 filterDiscardAnyMatchingLayers(entity, layerIds);
94 break;
95 }
96 case QLayerFilter::DiscardAllMatchingLayers: {
97 filterDiscardAllMatchingLayers(entity, layerIds);
98 break;
99 }
100 default:
101 Q_UNREACHABLE();
102 }
103}
104
105// We accept the entity if it contains any of the layers that are in the layer filter
106void FilterLayerEntityJob::filterAcceptAnyMatchingLayers(Entity *entity,
107 const Qt3DCore::QNodeIdVector &layerIds)
108{
109 const Qt3DCore::QNodeIdVector entityLayers = entity->layerIds();
110
111 for (const Qt3DCore::QNodeId id : entityLayers) {
112 const bool layerAccepted = layerIds.contains(t: id);
113
114 if (layerAccepted) {
115 m_filteredEntities.push_back(t: entity);
116 break;
117 }
118 }
119}
120
121// We accept the entity if it contains all the layers that are in the layer
122// filter
123void FilterLayerEntityJob::filterAcceptAllMatchingLayers(Entity *entity,
124 const Qt3DCore::QNodeIdVector &layerIds)
125{
126 const Qt3DCore::QNodeIdVector entityLayers = entity->layerIds();
127 int layersAccepted = 0;
128
129 for (const Qt3DCore::QNodeId id : entityLayers) {
130 if (layerIds.contains(t: id))
131 ++layersAccepted;
132 }
133
134 if (layersAccepted == layerIds.size())
135 m_filteredEntities.push_back(t: entity);
136}
137
138// We discard the entity if it contains any of the layers that are in the layer
139// filter
140// In other words that means we select an entity if one of its layers is not on
141// the layer filter
142void FilterLayerEntityJob::filterDiscardAnyMatchingLayers(Entity *entity,
143 const Qt3DCore::QNodeIdVector &layerIds)
144{
145 const Qt3DCore::QNodeIdVector entityLayers = entity->layerIds();
146 bool entityCanBeDiscarded = false;
147
148 for (const Qt3DCore::QNodeId id : entityLayers) {
149 if (layerIds.contains(t: id)) {
150 entityCanBeDiscarded = true;
151 break;
152 }
153 }
154
155 if (!entityCanBeDiscarded)
156 m_filteredEntities.push_back(t: entity);
157}
158
159// We discard the entity if it contains all of the layers that are in the layer
160// filter
161// In other words that means we select an entity if none of its layers are on
162// the layer filter
163void FilterLayerEntityJob::filterDiscardAllMatchingLayers(Entity *entity,
164 const Qt3DCore::QNodeIdVector &layerIds)
165{
166 const Qt3DCore::QNodeIdVector entityLayers = entity->layerIds();
167
168 int containedLayers = 0;
169
170 for (const Qt3DCore::QNodeId id : layerIds) {
171 if (entityLayers.contains(t: id))
172 ++containedLayers;
173 }
174
175 if (containedLayers != layerIds.size())
176 m_filteredEntities.push_back(t: entity);
177}
178
179void FilterLayerEntityJob::filterLayerAndEntity()
180{
181 EntityManager *entityManager = m_manager->renderNodesManager();
182 const std::vector<HEntity> &handles = entityManager->activeHandles();
183
184 QVector<Entity *> entitiesToFilter;
185 entitiesToFilter.reserve(asize: handles.size());
186
187 for (const HEntity &handle : handles) {
188 Entity *entity = entityManager->data(handle);
189
190 if (entity->isTreeEnabled())
191 entitiesToFilter.push_back(t: entity);
192 }
193
194 FrameGraphManager *frameGraphManager = m_manager->frameGraphManager();
195 LayerManager *layerManager = m_manager->layerManager();
196
197 for (const Qt3DCore::QNodeId layerFilterId : qAsConst(t&: m_layerFilterIds)) {
198 LayerFilterNode *layerFilter = static_cast<LayerFilterNode *>(frameGraphManager->lookupNode(id: layerFilterId));
199 Qt3DCore::QNodeIdVector layerIds = layerFilter->layerIds();
200
201 // Remove layerIds which are not active/enabled
202 for (int i = layerIds.size() - 1; i >= 0; --i) {
203 Layer *backendLayer = layerManager->lookupResource(id: layerIds.at(i));
204 if (backendLayer == nullptr || !backendLayer->isEnabled())
205 layerIds.removeAt(i);
206 }
207
208 const QLayerFilter::FilterMode filterMode = layerFilter->filterMode();
209
210 // Perform filtering
211 for (Entity *entity : entitiesToFilter)
212 filterEntityAgainstLayers(entity, layerIds, filterMode);
213
214 // Entities to filter for the next frame are the filtered result of the
215 // current LayerFilter
216 entitiesToFilter = std::move(m_filteredEntities);
217 }
218 m_filteredEntities = std::move(entitiesToFilter);
219}
220
221// No layer filter -> retrieve all entities
222void FilterLayerEntityJob::selectAllEntities()
223{
224 EntityManager *entityManager = m_manager->renderNodesManager();
225 const std::vector<HEntity> &handles = entityManager->activeHandles();
226
227 m_filteredEntities.reserve(asize: handles.size());
228 for (const HEntity &handle : handles) {
229 Entity *e = entityManager->data(handle);
230 if (e->isTreeEnabled())
231 m_filteredEntities.push_back(t: e);
232 }
233}
234
235} // Render
236
237} // Qt3DRender
238
239QT_END_NAMESPACE
240

source code of qt3d/src/render/jobs/filterlayerentityjob.cpp