...
[xonotic/netradiant.git] / contrib / ufoai / ufoai_filters.cpp
1 /*
2 This file is part of GtkRadiant.
3
4 GtkRadiant is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 GtkRadiant is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with GtkRadiant; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17 */
18
19 #include "ufoai_filters.h"
20
21 #include "ibrush.h"
22 #include "ientity.h"
23 #include "iscenegraph.h"
24
25 // believe me, i'm sorry
26 #include "../../radiant/brush.h"
27
28 #include "generic/callback.h"
29
30 #include <list>
31
32 bool actorclip_active = false;
33 bool stepon_active = false;
34 int level_active = 0;
35
36 // TODO: This should be added to ibrush.h
37 // like already done for Node_getEntity in ientity.h
38 // FIXME: Doesn't belong here
39 inline Brush* Node_getBrush(scene::Node& node)
40 {
41         return NodeTypeCast<Brush>::cast(node);
42 }
43
44 void hide_node(scene::Node& node, bool hide)
45 {
46         hide
47         ? node.enable(scene::Node::eHidden)
48         : node.disable(scene::Node::eHidden);
49 }
50
51 typedef std::list<Entity*> entitylist_t;
52
53 class EntityFindByName : public scene::Graph::Walker
54 {
55         const char* m_name;
56         entitylist_t& m_entitylist;
57         /* this starts at 1 << level */
58         int m_flag;
59         int m_hide;
60 public:
61         EntityFindByName(const char* name, entitylist_t& entitylist, int flag, bool hide)
62                 : m_name(name), m_entitylist(entitylist), m_flag(flag), m_hide(hide)
63         {
64         }
65         bool pre(const scene::Path& path, scene::Instance& instance) const
66         {
67                 int spawnflagsInt;
68                 Entity* entity = Node_getEntity(path.top());
69                 if (entity != 0)
70                 {
71                         if (string_equal(m_name, entity->getKeyValue("classname")))
72                         {
73                                 const char *spawnflags = entity->getKeyValue("spawnflags");
74                                 globalOutputStream() << "spawnflags for " << m_name << ": " << spawnflags << ".\n";
75
76                                 if (!string_empty(spawnflags)) {
77                                         spawnflagsInt = atoi(spawnflags);
78                                         if (!(spawnflagsInt & m_flag))
79                                         {
80                                                 hide_node(path.top(), m_hide); // hide/unhide
81                                                 m_entitylist.push_back(entity);
82                                         }
83                                 }
84                                 else
85                                 {
86                                         globalOutputStream() << "UFO:AI: Warning: no spawnflags for " << m_name << ".\n";
87                                 }
88                         }
89                 }
90                 return true;
91         }
92 };
93
94 class ForEachFace : public BrushVisitor
95 {
96         Brush &m_brush;
97 public:
98         mutable int m_contentFlagsVis;
99         mutable int m_surfaceFlagsVis;
100
101         ForEachFace(Brush& brush)
102                 : m_brush(brush)
103         {
104                 m_contentFlagsVis = -1;
105                 m_surfaceFlagsVis = -1;
106         }
107
108         void visit(Face& face) const
109         {
110 #if _DEBUG
111                 if (m_surfaceFlagsVis < 0)
112                         m_surfaceFlagsVis = face.getShader().m_flags.m_surfaceFlags;
113                 else if (m_surfaceFlagsVis >= 0 && m_surfaceFlagsVis != face.getShader().m_flags.m_surfaceFlags)
114                         globalOutputStream() << "Faces with different surfaceflags at brush\n";
115                 if (m_contentFlagsVis < 0)
116                         m_contentFlagsVis = face.getShader().m_flags.m_contentFlags;
117                 else if (m_contentFlagsVis >= 0 && m_contentFlagsVis != face.getShader().m_flags.m_contentFlags)
118                         globalOutputStream() << "Faces with different contentflags at brush\n";
119 #else
120                 m_surfaceFlagsVis = face.getShader().m_flags.m_surfaceFlags;
121                 m_contentFlagsVis = face.getShader().m_flags.m_contentFlags;
122 #endif
123         }
124 };
125
126 typedef std::list<Brush*> brushlist_t;
127
128 class BrushGetLevel : public scene::Graph::Walker
129 {
130         brushlist_t& m_brushlist;
131         int m_flag;
132         bool m_content; // if true - use m_contentFlags - otherwise m_surfaceFlags
133         mutable bool m_notset;
134         mutable bool m_hide;
135 public:
136         BrushGetLevel(brushlist_t& brushlist, int flag, bool content, bool notset, bool hide)
137                 : m_brushlist(brushlist), m_flag(flag), m_content(content), m_notset(notset), m_hide(hide)
138         {
139         }
140         bool pre(const scene::Path& path, scene::Instance& instance) const
141         {
142                 Brush* brush = Node_getBrush(path.top());
143                 if (brush != 0)
144                 {
145                         ForEachFace faces(*brush);
146                         brush->forEachFace(faces);
147                         // contentflags?
148                         if (m_content)
149                         {
150                                 // are any flags set?
151                                 if (faces.m_contentFlagsVis > 0)
152                                 {
153                                         // flag should not be set
154                                         if (m_notset && (!(faces.m_contentFlagsVis & m_flag)))
155                                         {
156                                                 hide_node(path.top(), m_hide);
157                                                 m_brushlist.push_back(brush);
158                                         }
159                                         // check whether flag is set
160                                         else if (!m_notset && ((faces.m_contentFlagsVis & m_flag)))
161                                         {
162                                                 hide_node(path.top(), m_hide);
163                                                 m_brushlist.push_back(brush);
164                                         }
165                                 }
166                         }
167                         // surfaceflags?
168                         else
169                         {
170                                 // are any flags set?
171                                 if (faces.m_surfaceFlagsVis > 0)
172                                 {
173                                         // flag should not be set
174                                         if (m_notset && (!(faces.m_surfaceFlagsVis & m_flag)))
175                                         {
176                                                 hide_node(path.top(), m_hide);
177                                                 m_brushlist.push_back(brush);
178                                         }
179                                         // check whether flag is set
180                                         else if (!m_notset && ((faces.m_surfaceFlagsVis & m_flag)))
181                                         {
182                                                 hide_node(path.top(), m_hide);
183                                                 m_brushlist.push_back(brush);
184                                         }
185                                 }
186                         }
187
188                 }
189                 return true;
190         }
191 };
192
193 /**
194  * @brief Activates the level filter for the given level
195  * @param[in] level Which level to show?
196  * @todo Entities
197  */
198 void filter_level(int flag)
199 {
200         int level;
201         brushlist_t brushes;
202         entitylist_t entities;
203
204         level = (flag >> 8);
205
206         if (level_active)
207         {
208                 GlobalSceneGraph().traverse(BrushGetLevel(brushes, (level_active << 8), true, true, false));
209                 GlobalSceneGraph().traverse(EntityFindByName("func_breakable", entities, level_active, false));
210                 GlobalSceneGraph().traverse(EntityFindByName("misc_model", entities, level_active, false));
211                 entities.erase(entities.begin(), entities.end());
212                 brushes.erase(brushes.begin(), brushes.end());
213                 if (level_active == level)
214                 {
215                         level_active = 0;
216                         // just disabĺe level filter
217                         return;
218                 }
219         }
220         level_active = level;
221         globalOutputStream() << "UFO:AI: level_active: " << level_active << ", flag: " << flag << ".\n";
222
223         // first all brushes
224         GlobalSceneGraph().traverse(BrushGetLevel(brushes, flag, true, true, true));
225
226         // now all entities
227         GlobalSceneGraph().traverse(EntityFindByName("func_breakable", entities, level, true));
228         GlobalSceneGraph().traverse(EntityFindByName("misc_model", entities, level, true));
229
230 #ifdef _DEBUG
231         if (brushes.empty())
232         {
233                 globalOutputStream() << "UFO:AI: No brushes.\n";
234         }
235         else
236         {
237                 globalOutputStream() << "UFO:AI: Found " << Unsigned(brushes.size()) << " brushes.\n";
238         }
239
240         // now let's filter all entities like misc_model and func_breakable that have the spawnflags set
241         if (entities.empty())
242         {
243                 globalOutputStream() << "UFO:AI: No entities.\n";
244         }
245         else
246         {
247                 globalOutputStream() << "UFO:AI: Found " << Unsigned(entities.size()) << " entities.\n";
248         }
249 #endif
250 }
251
252 void filter_stepon (void)
253 {
254         if (stepon_active) {
255                 stepon_active = false;
256         } else {
257                 stepon_active = true;
258         }
259         brushlist_t brushes;
260         GlobalSceneGraph().traverse(BrushGetLevel(brushes, CONTENTS_STEPON, true, false, stepon_active));
261
262         if (brushes.empty())
263         {
264                 globalOutputStream() << "UFO:AI: No brushes.\n";
265         }
266         else
267         {
268                 globalOutputStream() << "UFO:AI: Hiding " << Unsigned(brushes.size()) << " stepon brushes.\n";
269         }
270 }
271
272 void filter_actorclip (void)
273 {
274         if (actorclip_active) {
275                 actorclip_active = false;
276         } else {
277                 actorclip_active = true;
278         }
279         brushlist_t brushes;
280         GlobalSceneGraph().traverse(BrushGetLevel(brushes, CONTENTS_ACTORCLIP, true, false, actorclip_active));
281
282 #ifdef _DEBUG
283         if (brushes.empty())
284         {
285                 globalOutputStream() << "UFO:AI: No brushes.\n";
286         }
287         else
288         {
289                 globalOutputStream() << "UFO:AI: Hiding " << Unsigned(brushes.size()) << " actorclip brushes.\n";
290         }
291 #endif
292 }