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 | |
11 | QT_BEGIN_NAMESPACE |
12 | |
13 | namespace Qt3DRender { |
14 | |
15 | namespace Render { |
16 | |
17 | namespace { |
18 | int layerFilterJobCounter = 0; |
19 | } // anonymous |
20 | |
21 | FilterLayerEntityJob::FilterLayerEntityJob() |
22 | : Qt3DCore::QAspectJob() |
23 | , m_manager(nullptr) |
24 | { |
25 | SET_JOB_RUN_STAT_TYPE(this, JobTypes::LayerFiltering, layerFilterJobCounter++) |
26 | } |
27 | |
28 | |
29 | void 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 | |
42 | void 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 |
70 | void 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 |
87 | void 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 |
106 | void 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 |
127 | void 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 | |
143 | void 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 |
186 | void 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 | |
203 | QT_END_NAMESPACE |
204 | |