/
SelectionTestWalkers.cpp
214 lines (166 loc) · 5.05 KB
/
SelectionTestWalkers.cpp
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
#include "SelectionTestWalkers.h"
#include "itextstream.h"
#include "iselectable.h"
#include "imodel.h"
#include "igroupnode.h"
#include "iselectiontest.h"
#include "entitylib.h"
#include "debugging/ScenegraphUtils.h"
namespace selection
{
void SelectionTestWalker::printNodeName(const scene::INodePtr& node)
{
rMessage() << "Node: " << getNameForNodeType(node->getNodeType()) << " ";
if (node->getNodeType() == scene::INode::Type::Entity)
{
rMessage() << " - " << Node_getEntity(node)->getKeyValue("name");
}
rMessage() << std::endl;
}
scene::INodePtr SelectionTestWalker::getEntityNode(const scene::INodePtr& node)
{
return (Node_isEntity(node)) ? node : scene::INodePtr();
}
scene::INodePtr SelectionTestWalker::getParentGroupEntity(const scene::INodePtr& node)
{
scene::INodePtr parent = node->getParent();
return (Node_getGroupNode(parent) != NULL) ? parent : scene::INodePtr();
}
bool SelectionTestWalker::entityIsWorldspawn(const scene::INodePtr& node)
{
return Node_isWorldspawn(node);
}
void SelectionTestWalker::performSelectionTest(const scene::INodePtr& selectableNode,
const scene::INodePtr& nodeToBeTested)
{
if (!nodeIsEligibleForTesting(nodeToBeTested))
{
return;
}
auto selectable = Node_getSelectable(selectableNode);
if (!selectable) return; // skip non-selectables
_selector.pushSelectable(*selectable);
// Test the entity for selection, this will add an intersection to the selector
auto selectionTestable = Node_getSelectionTestable(nodeToBeTested);
if (selectionTestable)
{
selectionTestable->testSelect(_selector, _test);
}
_selector.popSelectable();
}
bool EntitySelector::visit(const scene::INodePtr& node)
{
// Check directly for an entity
scene::INodePtr entity = getEntityNode(node);
if (entity == NULL)
{
// Skip any models, the parent entity is taking care of the selection test
if (Node_isModel(node))
{
return true;
}
// Second chance check: is the parent a group node?
entity = getParentGroupEntity(node);
}
// Skip worldspawn in any case
if (entity == NULL || entityIsWorldspawn(entity)) return true;
// Comment out to hide debugging output
//printNodeName(node);
// The entity is the selectable, but the actual node will be tested for selection
performSelectionTest(entity, node);
return true;
}
bool PrimitiveSelector::visit(const scene::INodePtr& node)
{
// Skip all entities
if (Node_isEntity(node)) return true;
// Node is not an entity, check parent
scene::INodePtr parent = getParentGroupEntity(node);
// Don't select primitives of non-worldspawn entities,
// the EntitySelector is taking care of that case
if (parent == NULL || entityIsWorldspawn(parent))
{
performSelectionTest(node, node);
}
return true;
}
bool GroupChildPrimitiveSelector::visit(const scene::INodePtr& node)
{
// Skip all entities
if (Node_isEntity(node)) return true;
// Node is not an entity, check parent
scene::INodePtr parent = getParentGroupEntity(node);
if (parent != NULL && !entityIsWorldspawn(parent))
{
performSelectionTest(node, node);
}
return true;
}
bool AnySelector::visit(const scene::INodePtr& node)
{
scene::INodePtr entity = getEntityNode(node);
scene::INodePtr candidate;
if (entity != NULL)
{
// skip worldspawn
if (entityIsWorldspawn(entity)) return true;
// Use this entity as selectable
candidate = entity;
}
else if (Node_isPrimitive(node))
{
// Primitives are ok, check for func_static children
scene::INodePtr parentEntity = getParentGroupEntity(node);
if (parentEntity != NULL)
{
// If this node is a child of worldspawn, it can be directly selected
// Otherwise this node is a child primitve of a non-worldspawn entity,
// in which case we want to select the parent entity
candidate = (entityIsWorldspawn(parentEntity)) ? node : parentEntity;
}
else
{
// A primitive without parent group entity? Error?
return true; // skip
}
}
// The entity is the selectable, but the actual node will be tested for selection
performSelectionTest(candidate, node);
return true;
}
// scene::Graph::Walker
bool ComponentSelector::visit(const scene::INodePtr& node)
{
performComponentselectionTest(node);
return true;
}
// SelectionSystem::Visitor
void ComponentSelector::visit(const scene::INodePtr& node) const
{
performComponentselectionTest(node);
}
void ComponentSelector::performComponentselectionTest(const scene::INodePtr& node) const
{
ComponentSelectionTestablePtr testable = Node_getComponentSelectionTestable(node);
if (testable != NULL)
{
testable->testSelectComponents(_selector, _test, _mode);
}
}
MergeActionSelector::MergeActionSelector(Selector& selector, SelectionTest& test) :
SelectionTestWalker(selector, test)
{}
bool MergeActionSelector::visit(const scene::INodePtr& node)
{
if (node->getNodeType() != scene::INode::Type::MergeAction)
{
return true; // skip over every mismatching type
}
performSelectionTest(node, node);
return false;
}
bool MergeActionSelector::nodeIsEligibleForTesting(const scene::INodePtr& node)
{
return node->getNodeType() == scene::INode::Type::MergeAction;
}
}