1 /**
2 * @file
3 */
4
5 /*
6 Copyright (C) 2002-2013 UFO: Alien Invasion.
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
17 See the GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23 */
24
25 #include "LevelFilter.h"
26
27 #include "ieventmanager.h"
28 #include "iscenegraph.h"
29 #include "shared.h"
30
31 #include "../brush/BrushNode.h"
32
33 #include "generic/callback.h"
34
35 #include <list>
36
hide_node(scene::Node & node,bool hide)37 inline void hide_node (scene::Node& node, bool hide)
38 {
39 hide ? node.enable(scene::Node::eHidden) : node.disable(scene::Node::eHidden);
40 }
41
LevelFilter()42 LevelFilter::LevelFilter () :
43 currentActiveLevel(0)
44 {
45 // TODO: get this info from entities.ufo
46 _classNameList.push_back("func_rotating");
47 _classNameList.push_back("func_door");
48 _classNameList.push_back("func_door_sliding");
49 _classNameList.push_back("func_breakable");
50 _classNameList.push_back("misc_item");
51 _classNameList.push_back("misc_mission");
52 _classNameList.push_back("misc_mission_alien");
53 _classNameList.push_back("misc_model");
54 _classNameList.push_back("misc_sound");
55 _classNameList.push_back("misc_particle");
56 }
57
EntityFindByName(const std::string & name,EntityList & entitylist,int flag,bool hide)58 LevelFilter::EntityFindByName::EntityFindByName (const std::string& name, EntityList& entitylist, int flag, bool hide) :
59 m_name(name), m_entitylist(entitylist), m_flag(flag), m_hide(hide)
60 {
61 }
62
pre(const scene::Path & path,scene::Instance & instance) const63 bool LevelFilter::EntityFindByName::pre (const scene::Path& path, scene::Instance& instance) const
64 {
65 Entity* entity = Node_getEntity(path.top());
66 if (entity != 0) {
67 if (entity->getKeyValue("classname") == m_name) {
68 const std::string spawnflags = entity->getKeyValue("spawnflags");
69 if (!spawnflags.empty()) {
70 const int spawnflagsInt = string::toInt(spawnflags);
71 if (!(spawnflagsInt & m_flag)) {
72 hide_node(path.top(), m_hide); // hide/unhide
73 m_entitylist.push_back(entity);
74 }
75 } else {
76 globalWarningStream() << "Warning: no spawnflags for bmodel entity " << m_name << ".\n";
77 }
78 }
79 }
80 return true;
81 }
82
ForEachFace(Brush & brush)83 LevelFilter::ForEachFace::ForEachFace (Brush& brush)
84 {
85 m_contentFlagsVis = -1;
86 m_surfaceFlagsVis = -1;
87 }
88
visit(Face & face) const89 void LevelFilter::ForEachFace::visit (Face& face) const
90 {
91 m_surfaceFlagsVis = face.getShader().m_flags.getSurfaceFlags();
92 m_contentFlagsVis = face.getShader().m_flags.getContentFlags();
93 }
94
BrushGetLevel(BrushList & brushlist,int flag,bool hide)95 LevelFilter::BrushGetLevel::BrushGetLevel (BrushList& brushlist, int flag, bool hide) :
96 m_brushlist(brushlist), m_flag(flag), m_hide(hide)
97 {
98 }
99
pre(const scene::Path & path,scene::Instance & instance) const100 bool LevelFilter::BrushGetLevel::pre (const scene::Path& path, scene::Instance& instance) const
101 {
102 Brush* brush = Node_getBrush(path.top());
103 if (brush != 0) {
104 ForEachFace faces(*brush);
105 brush->forEachFace(faces);
106 // are any flags set?
107 if (faces.m_contentFlagsVis > 0) {
108 // flag should not be set
109 if (!(faces.m_contentFlagsVis & m_flag)) {
110 hide_node(path.top(), m_hide);
111 m_brushlist.push_back(brush);
112 }
113 }
114 }
115 return true;
116 }
117
118 /**
119 * @brief Activates the level filter for the given level
120 * @param[in] level Which level to show?
121 */
filter_level(int flag)122 void LevelFilter::filter_level (int flag)
123 {
124 int level;
125 BrushList brushes;
126 EntityList entities;
127
128 level = (flag >> 8);
129
130 if (currentActiveLevel) {
131 GlobalSceneGraph().traverse(BrushGetLevel(brushes, (currentActiveLevel << 8), false));
132 for (EntityClassNameList::const_iterator i = _classNameList.begin(); i != _classNameList.end(); ++i) {
133 GlobalSceneGraph().traverse(EntityFindByName(*i, entities, currentActiveLevel, false));
134 }
135 entities.clear();
136 brushes.clear();
137 if (currentActiveLevel == level) {
138 currentActiveLevel = 0;
139 // just disable level filter
140 SceneChangeNotify();
141 return;
142 }
143 }
144 currentActiveLevel = level;
145
146 // first all brushes
147 GlobalSceneGraph().traverse(BrushGetLevel(brushes, flag, true));
148
149 // now all entities
150 for (EntityClassNameList::const_iterator i = _classNameList.begin(); i != _classNameList.end(); ++i) {
151 GlobalSceneGraph().traverse(EntityFindByName(*i, entities, level, true));
152 }
153
154 SceneChangeNotify();
155 }
156
157 /**
158 * @brief gives the current filter level (levels 1 to 8, 0 for no filtering).
159 * @return current filter level
160 */
getCurrentLevel()161 int LevelFilter::getCurrentLevel ()
162 {
163 if (currentActiveLevel > 2)
164 return ilogb(currentActiveLevel) + 1;
165 return currentActiveLevel;
166 }
167
filter_level1()168 void LevelFilter::filter_level1 ()
169 {
170 filter_level(CONTENTS_LEVEL_1);
171 }
filter_level2()172 void LevelFilter::filter_level2 ()
173 {
174 filter_level(CONTENTS_LEVEL_2);
175 }
filter_level3()176 void LevelFilter::filter_level3 ()
177 {
178 filter_level(CONTENTS_LEVEL_3);
179 }
filter_level4()180 void LevelFilter::filter_level4 ()
181 {
182 filter_level(CONTENTS_LEVEL_4);
183 }
filter_level5()184 void LevelFilter::filter_level5 ()
185 {
186 filter_level(CONTENTS_LEVEL_5);
187 }
filter_level6()188 void LevelFilter::filter_level6 ()
189 {
190 filter_level(CONTENTS_LEVEL_6);
191 }
filter_level7()192 void LevelFilter::filter_level7 ()
193 {
194 filter_level(CONTENTS_LEVEL_7);
195 }
filter_level8()196 void LevelFilter::filter_level8 ()
197 {
198 filter_level(CONTENTS_LEVEL_8);
199 }
200
201 /**
202 * @brief register commands for level filtering
203 */
registerCommands()204 void LevelFilter::registerCommands ()
205 {
206 GlobalEventManager().addCommand("FilterLevel1", MemberCaller<LevelFilter, &LevelFilter::filter_level1> (*this));
207 GlobalEventManager().addCommand("FilterLevel2", MemberCaller<LevelFilter, &LevelFilter::filter_level2> (*this));
208 GlobalEventManager().addCommand("FilterLevel3", MemberCaller<LevelFilter, &LevelFilter::filter_level3> (*this));
209 GlobalEventManager().addCommand("FilterLevel4", MemberCaller<LevelFilter, &LevelFilter::filter_level4> (*this));
210 GlobalEventManager().addCommand("FilterLevel5", MemberCaller<LevelFilter, &LevelFilter::filter_level5> (*this));
211 GlobalEventManager().addCommand("FilterLevel6", MemberCaller<LevelFilter, &LevelFilter::filter_level6> (*this));
212 GlobalEventManager().addCommand("FilterLevel7", MemberCaller<LevelFilter, &LevelFilter::filter_level7> (*this));
213 GlobalEventManager().addCommand("FilterLevel8", MemberCaller<LevelFilter, &LevelFilter::filter_level8> (*this));
214 }
215