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