2 This file is part of GtkRadiant.
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.
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.
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
19 #include "ufoai_filters.h"
20 #include "globaldefs.h"
24 #include "iscenegraph.h"
26 // believe me, i'm sorry
27 #include "../../radiant/brush.h"
29 #include "generic/callback.h"
33 bool actorclip_active = false;
34 bool stepon_active = false;
35 bool nodraw_active = false;
36 bool weaponclip_active = false;
39 // TODO: This should be added to ibrush.h
40 // like already done for Node_getEntity in ientity.h
41 // FIXME: Doesn't belong here
42 inline Brush *Node_getBrush(scene::Node &node)
44 return NodeTypeCast<Brush>::cast(node);
47 void hide_node(scene::Node &node, bool hide)
50 ? node.enable(scene::Node::eHidden)
51 : node.disable(scene::Node::eHidden);
54 typedef std::list<Entity *> entitylist_t;
56 class EntityFindByName : public scene::Graph::Walker {
58 entitylist_t &m_entitylist;
59 /* this starts at 1 << level */
63 EntityFindByName(const char *name, entitylist_t &entitylist, int flag, bool hide)
64 : m_name(name), m_entitylist(entitylist), m_flag(flag), m_hide(hide)
68 bool pre(const scene::Path &path, scene::Instance &instance) const
71 Entity *entity = Node_getEntity(path.top());
73 if (string_equal(m_name, entity->getKeyValue("classname"))) {
74 const char *spawnflags = entity->getKeyValue("spawnflags");
75 globalOutputStream() << "spawnflags for " << m_name << ": " << spawnflags << ".\n";
77 if (!string_empty(spawnflags)) {
78 spawnflagsInt = atoi(spawnflags);
79 if (!(spawnflagsInt & m_flag)) {
80 hide_node(path.top(), m_hide); // hide/unhide
81 m_entitylist.push_back(entity);
84 globalOutputStream() << "UFO:AI: Warning: no spawnflags for " << m_name << ".\n";
92 class ForEachFace : public BrushVisitor {
95 mutable int m_contentFlagsVis;
96 mutable int m_surfaceFlagsVis;
98 ForEachFace(Brush &brush)
101 m_contentFlagsVis = -1;
102 m_surfaceFlagsVis = -1;
105 void visit(Face &face) const
108 if (m_surfaceFlagsVis < 0) {
109 m_surfaceFlagsVis = face.getShader().m_flags.m_surfaceFlags;
110 } else if (m_surfaceFlagsVis >= 0 && m_surfaceFlagsVis != face.getShader().m_flags.m_surfaceFlags) {
111 globalOutputStream() << "Faces with different surfaceflags at brush\n";
113 if (m_contentFlagsVis < 0) {
114 m_contentFlagsVis = face.getShader().m_flags.m_contentFlags;
115 } else if (m_contentFlagsVis >= 0 && m_contentFlagsVis != face.getShader().m_flags.m_contentFlags) {
116 globalOutputStream() << "Faces with different contentflags at brush\n";
119 m_surfaceFlagsVis = face.getShader().m_flags.m_surfaceFlags;
120 m_contentFlagsVis = face.getShader().m_flags.m_contentFlags;
125 typedef std::list<Brush *> brushlist_t;
127 class BrushGetLevel : public scene::Graph::Walker {
128 brushlist_t &m_brushlist;
130 bool m_content; // if true - use m_contentFlags - otherwise m_surfaceFlags
131 mutable bool m_notset;
134 BrushGetLevel(brushlist_t &brushlist, int flag, bool content, bool notset, bool hide)
135 : m_brushlist(brushlist), m_flag(flag), m_content(content), m_notset(notset), m_hide(hide)
139 bool pre(const scene::Path &path, scene::Instance &instance) const
141 Brush *brush = Node_getBrush(path.top());
143 ForEachFace faces(*brush);
144 brush->forEachFace(faces);
147 // are any flags set?
148 if (faces.m_contentFlagsVis > 0) {
149 // flag should not be set
150 if (m_notset && (!(faces.m_contentFlagsVis & m_flag))) {
151 hide_node(path.top(), m_hide);
152 m_brushlist.push_back(brush);
154 // check whether flag is set
155 else if (!m_notset && ((faces.m_contentFlagsVis & m_flag))) {
156 hide_node(path.top(), m_hide);
157 m_brushlist.push_back(brush);
163 // are any flags set?
164 if (faces.m_surfaceFlagsVis > 0) {
165 // flag should not be set
166 if (m_notset && (!(faces.m_surfaceFlagsVis & m_flag))) {
167 hide_node(path.top(), m_hide);
168 m_brushlist.push_back(brush);
170 // check whether flag is set
171 else if (!m_notset && ((faces.m_surfaceFlagsVis & m_flag))) {
172 hide_node(path.top(), m_hide);
173 m_brushlist.push_back(brush);
184 * @brief Activates the level filter for the given level
185 * @param[in] level Which level to show?
188 void filter_level(int flag)
192 entitylist_t entities;
197 GlobalSceneGraph().traverse(BrushGetLevel(brushes, (level_active << 8), true, true, false));
198 GlobalSceneGraph().traverse(EntityFindByName("func_door", entities, level_active, false));
199 GlobalSceneGraph().traverse(EntityFindByName("func_breakable", entities, level_active, false));
200 GlobalSceneGraph().traverse(EntityFindByName("misc_model", entities, level_active, false));
201 GlobalSceneGraph().traverse(EntityFindByName("misc_particle", entities, level_active, false));
202 entities.erase(entities.begin(), entities.end());
203 brushes.erase(brushes.begin(), brushes.end());
204 if (level_active == level) {
206 // just disabĺe level filter
210 level_active = level;
211 globalOutputStream() << "UFO:AI: level_active: " << level_active << ", flag: " << flag << ".\n";
214 GlobalSceneGraph().traverse(BrushGetLevel(brushes, flag, true, true, true));
217 GlobalSceneGraph().traverse(EntityFindByName("func_door", entities, level, true));
218 GlobalSceneGraph().traverse(EntityFindByName("func_breakable", entities, level, true));
219 GlobalSceneGraph().traverse(EntityFindByName("misc_model", entities, level, true));
220 GlobalSceneGraph().traverse(EntityFindByName("misc_particle", entities, level, true));
223 if (brushes.empty()) {
224 globalOutputStream() << "UFO:AI: No brushes.\n";
226 globalOutputStream() << "UFO:AI: Found " << Unsigned(brushes.size()) << " brushes.\n";
229 // now let's filter all entities like misc_model, func_breakable and func_door that have the spawnflags set
230 if (entities.empty()) {
231 globalOutputStream() << "UFO:AI: No entities.\n";
233 globalOutputStream() << "UFO:AI: Found " << Unsigned(entities.size()) << " entities.\n";
238 void filter_stepon(void)
241 stepon_active = false;
243 stepon_active = true;
246 GlobalSceneGraph().traverse(BrushGetLevel(brushes, CONTENTS_STEPON, true, false, stepon_active));
248 if (brushes.empty()) {
249 globalOutputStream() << "UFO:AI: No brushes.\n";
251 globalOutputStream() << "UFO:AI: Hiding " << Unsigned(brushes.size()) << " stepon brushes.\n";
255 void filter_nodraw(void)
258 nodraw_active = false;
260 nodraw_active = true;
263 GlobalSceneGraph().traverse(BrushGetLevel(brushes, SURF_NODRAW, false, false, nodraw_active));
266 if (brushes.empty()) {
267 globalOutputStream() << "UFO:AI: No brushes.\n";
269 globalOutputStream() << "UFO:AI: Hiding " << Unsigned(brushes.size()) << " nodraw brushes.\n";
274 void filter_actorclip(void)
276 if (actorclip_active) {
277 actorclip_active = false;
279 actorclip_active = true;
282 GlobalSceneGraph().traverse(BrushGetLevel(brushes, CONTENTS_ACTORCLIP, true, false, actorclip_active));
285 if (brushes.empty()) {
286 globalOutputStream() << "UFO:AI: No brushes.\n";
288 globalOutputStream() << "UFO:AI: Hiding " << Unsigned(brushes.size()) << " actorclip brushes.\n";
293 void filter_weaponclip(void)
295 if (weaponclip_active) {
296 weaponclip_active = false;
298 weaponclip_active = true;
301 GlobalSceneGraph().traverse(BrushGetLevel(brushes, CONTENTS_WEAPONCLIP, true, false, weaponclip_active));
304 if (brushes.empty()) {
305 globalOutputStream() << "UFO:AI: No brushes.\n";
307 globalOutputStream() << "UFO:AI: Hiding " << Unsigned(brushes.size()) << " weaponclip brushes.\n";