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

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