/
InstanceUpdateWalker.h
147 lines (119 loc) · 3.11 KB
/
InstanceUpdateWalker.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#pragma once
#include "inode.h"
#include "ientity.h"
#include "iselectable.h"
#include "ipatch.h"
#include "ibrush.h"
namespace filters
{
// Walker: de-selects a complete subgraph
class Deselector :
public scene::NodeVisitor
{
public:
bool pre(const scene::INodePtr& node) override
{
Node_setSelected(node, false);
return true;
}
};
// Walker: Shows or hides a complete subgraph
class NodeVisibilityUpdater :
public scene::NodeVisitor
{
private:
bool _filtered;
public:
NodeVisibilityUpdater(bool setFiltered) :
_filtered(setFiltered)
{}
bool pre(const scene::INodePtr& node) override
{
node->setFiltered(_filtered);
return true;
}
};
/**
* Scenegraph walker to update filtered status of nodes based on the
* currently active set of filters.
*/
class InstanceUpdateWalker :
public scene::NodeVisitor
{
private:
FilterSystem& _filterSystem;
// Helper visitors to update subgraphs
NodeVisibilityUpdater _hideWalker;
NodeVisibilityUpdater _showWalker;
Deselector _deselector;
// Cached boolean to avoid FilterSystem queries for each node
bool _patchesAreVisible;
bool _brushesAreVisible;
public:
InstanceUpdateWalker(FilterSystem& filterSystem) :
_filterSystem(filterSystem),
_hideWalker(true),
_showWalker(false),
_patchesAreVisible(_filterSystem.isVisible(FilterRule::TYPE_OBJECT, "patch")),
_brushesAreVisible(_filterSystem.isVisible(FilterRule::TYPE_OBJECT, "brush"))
{}
bool pre(const scene::INodePtr& node) override
{
// Check entity eclass and spawnargs
if (Node_isEntity(node))
{
bool isVisible = evaluateEntity(node);
setSubgraphFilterStatus(node, isVisible);
// If the entity is hidden, don't traverse its child nodes
return isVisible;
}
// greebo: Check visibility of Patches
if (Node_isPatch(node))
{
bool isVisible = evaluatePatch(node);
setSubgraphFilterStatus(node, isVisible);
}
// greebo: Check visibility of Brushes
else if (Node_isBrush(node))
{
bool isVisible = evaluateBrush(node);
setSubgraphFilterStatus(node, isVisible);
// In case the brush has at least one visible material trigger a fine-grained update
if (isVisible)
{
Node_getIBrush(node)->updateFaceVisibility();
}
}
// Continue the traversal
return true;
}
private:
bool evaluateEntity(const scene::INodePtr& node)
{
assert(Node_isEntity(node));
Entity* entity = Node_getEntity(node);
// Check the eclass first
return _filterSystem.isEntityVisible(FilterRule::TYPE_ENTITYCLASS, *entity) &&
_filterSystem.isEntityVisible(FilterRule::TYPE_ENTITYKEYVALUE, *entity);
}
bool evaluatePatch(const scene::INodePtr& node)
{
assert(Node_isPatch(node));
return _patchesAreVisible && Node_getIPatch(node)->hasVisibleMaterial();
}
bool evaluateBrush(const scene::INodePtr& node)
{
assert(Node_isBrush(node));
return _brushesAreVisible && Node_getIBrush(node)->hasVisibleMaterial();
}
void setSubgraphFilterStatus(const scene::INodePtr& node, bool isVisible)
{
node->traverse(isVisible ? _showWalker : _hideWalker);
if (!isVisible)
{
// de-select this node and all children
node->traverse(_deselector);
}
}
};
} // namespace filters