1// Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
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 "filterproximitydistancejob_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/proximityfilter_p.h>
9#include <Qt3DRender/private/job_common_p.h>
10#include <Qt3DRender/private/sphere_p.h>
11
12QT_BEGIN_NAMESPACE
13
14namespace Qt3DRender {
15
16namespace Render {
17
18namespace {
19int instanceCounter = 0;
20} // anonymous
21
22
23FilterProximityDistanceJob::FilterProximityDistanceJob()
24 : m_manager(nullptr)
25 , m_targetEntity(nullptr)
26 , m_distanceThresholdSquared(0.)
27{
28 SET_JOB_RUN_STAT_TYPE(this, JobTypes::ProximityFiltering, instanceCounter++)
29}
30
31FilterProximityDistanceJob::~FilterProximityDistanceJob()
32{
33 --instanceCounter;
34}
35
36bool FilterProximityDistanceJob::isRequired()
37{
38 return hasProximityFilter();
39}
40
41void FilterProximityDistanceJob::run()
42{
43 Q_ASSERT(m_manager != nullptr);
44 m_filteredEntities.clear();
45
46 // Fill m_filteredEntities
47 // If no filtering needs to be done, this will be the output value
48 // otherwise it will be used as the base list of entities to filter
49
50 if (hasProximityFilter()) {
51 selectAllEntities();
52 std::vector<Entity *> entitiesToFilter = std::move(m_filteredEntities);
53 FrameGraphManager *frameGraphManager = m_manager->frameGraphManager();
54 EntityManager *entityManager = m_manager->renderNodesManager();
55
56 for (const Qt3DCore::QNodeId &proximityFilterId : std::as_const(t&: m_proximityFilterIds)) {
57 ProximityFilter *proximityFilter = static_cast<ProximityFilter *>(frameGraphManager->lookupNode(id: proximityFilterId));
58 m_targetEntity = entityManager->lookupResource(id: proximityFilter->entityId());
59 m_distanceThresholdSquared = proximityFilter->distanceThreshold();
60 m_distanceThresholdSquared *= m_distanceThresholdSquared;
61
62 // We can't filter, select nothings
63 if (m_targetEntity == nullptr || m_distanceThresholdSquared <= 0.0f) {
64 m_filteredEntities.clear();
65 return;
66 }
67 // Otherwise we filter
68 filterEntities(entitiesToFilter);
69
70 // And we make the filtered subset be the list of entities to filter
71 // for the next loop
72 entitiesToFilter = std::move(m_filteredEntities);
73 }
74 m_filteredEntities = std::move(entitiesToFilter);
75 }
76
77 // sort needed for set_intersection in RenderViewBuilder
78 std::sort(first: m_filteredEntities.begin(), last: m_filteredEntities.end());
79}
80
81void FilterProximityDistanceJob::selectAllEntities()
82{
83 EntityManager *entityManager = m_manager->renderNodesManager();
84 const std::vector<HEntity> &handles = entityManager->activeHandles();
85
86 m_filteredEntities.reserve(n: handles.size());
87 for (const HEntity &handle : handles) {
88 Entity *e = entityManager->data(handle);
89 m_filteredEntities.push_back(x: e);
90 }
91}
92
93void FilterProximityDistanceJob::filterEntities(const std::vector<Entity *> &entitiesToFilter)
94{
95 const Sphere *target = m_targetEntity->worldBoundingVolumeWithChildren();
96
97 for (Entity *entity : entitiesToFilter) {
98 // Note: The target entity is always selected as distance will be 0
99
100 // Retrieve center of bounding volume for entity
101 const Sphere *s = entity->worldBoundingVolumeWithChildren();
102
103 // If distance between entity and target is less than threshold, we keep the entity
104 if ((s->center() - target->center()).lengthSquared() <= m_distanceThresholdSquared)
105 m_filteredEntities.push_back(x: entity);
106 }
107}
108
109} // Render
110
111} // Qt3DRender
112
113QT_END_NAMESPACE
114

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