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 ){
43 return NodeTypeCast<Brush>::cast( node );
46 void hide_node( scene::Node& node, bool hide ){
48 ? node.enable( scene::Node::eHidden )
49 : node.disable( scene::Node::eHidden );
52 typedef std::list<Entity*> entitylist_t;
54 class EntityFindByName : public scene::Graph::Walker
57 entitylist_t& m_entitylist;
58 /* this starts at 1 << level */
62 EntityFindByName( const char* name, entitylist_t& entitylist, int flag, bool hide )
63 : m_name( name ), m_entitylist( entitylist ), m_flag( flag ), m_hide( hide ){
65 bool pre( const scene::Path& path, scene::Instance& instance ) const {
67 Entity* entity = Node_getEntity( path.top() );
69 if ( string_equal( m_name, entity->getKeyValue( "classname" ) ) ) {
70 const char *spawnflags = entity->getKeyValue( "spawnflags" );
71 globalOutputStream() << "spawnflags for " << m_name << ": " << spawnflags << ".\n";
73 if ( !string_empty( spawnflags ) ) {
74 spawnflagsInt = atoi( spawnflags );
75 if ( !( spawnflagsInt & m_flag ) ) {
76 hide_node( path.top(), m_hide ); // hide/unhide
77 m_entitylist.push_back( entity );
82 globalOutputStream() << "UFO:AI: Warning: no spawnflags for " << m_name << ".\n";
90 class ForEachFace : public BrushVisitor
94 mutable int m_contentFlagsVis;
95 mutable int m_surfaceFlagsVis;
97 ForEachFace( Brush& brush )
99 m_contentFlagsVis = -1;
100 m_surfaceFlagsVis = -1;
103 void visit( Face& face ) const {
105 if ( m_surfaceFlagsVis < 0 ) {
106 m_surfaceFlagsVis = face.getShader().m_flags.m_surfaceFlags;
108 else if ( m_surfaceFlagsVis >= 0 && m_surfaceFlagsVis != face.getShader().m_flags.m_surfaceFlags ) {
109 globalOutputStream() << "Faces with different surfaceflags at brush\n";
111 if ( m_contentFlagsVis < 0 ) {
112 m_contentFlagsVis = face.getShader().m_flags.m_contentFlags;
114 else if ( m_contentFlagsVis >= 0 && m_contentFlagsVis != face.getShader().m_flags.m_contentFlags ) {
115 globalOutputStream() << "Faces with different contentflags at brush\n";
118 m_surfaceFlagsVis = face.getShader().m_flags.m_surfaceFlags;
119 m_contentFlagsVis = face.getShader().m_flags.m_contentFlags;
124 typedef std::list<Brush*> brushlist_t;
126 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 ){
137 bool pre( const scene::Path& path, scene::Instance& instance ) const {
138 Brush* brush = Node_getBrush( path.top() );
140 ForEachFace faces( *brush );
141 brush->forEachFace( faces );
144 // are any flags set?
145 if ( faces.m_contentFlagsVis > 0 ) {
146 // flag should not be set
147 if ( m_notset && ( !( faces.m_contentFlagsVis & m_flag ) ) ) {
148 hide_node( path.top(), m_hide );
149 m_brushlist.push_back( brush );
151 // check whether flag is set
152 else if ( !m_notset && ( ( faces.m_contentFlagsVis & m_flag ) ) ) {
153 hide_node( path.top(), m_hide );
154 m_brushlist.push_back( brush );
161 // are any flags set?
162 if ( faces.m_surfaceFlagsVis > 0 ) {
163 // flag should not be set
164 if ( m_notset && ( !( faces.m_surfaceFlagsVis & m_flag ) ) ) {
165 hide_node( path.top(), m_hide );
166 m_brushlist.push_back( brush );
168 // check whether flag is set
169 else if ( !m_notset && ( ( faces.m_surfaceFlagsVis & m_flag ) ) ) {
170 hide_node( path.top(), m_hide );
171 m_brushlist.push_back( brush );
182 * @brief Activates the level filter for the given level
183 * @param[in] level Which level to show?
186 void filter_level( int flag ){
189 entitylist_t entities;
191 level = ( flag >> 8 );
193 if ( level_active ) {
194 GlobalSceneGraph().traverse( BrushGetLevel( brushes, ( level_active << 8 ), true, true, false ) );
195 GlobalSceneGraph().traverse( EntityFindByName( "func_door", entities, level_active, false ) );
196 GlobalSceneGraph().traverse( EntityFindByName( "func_breakable", entities, level_active, false ) );
197 GlobalSceneGraph().traverse( EntityFindByName( "misc_model", entities, level_active, false ) );
198 GlobalSceneGraph().traverse( EntityFindByName( "misc_particle", entities, level_active, false ) );
199 entities.erase( entities.begin(), entities.end() );
200 brushes.erase( brushes.begin(), brushes.end() );
201 if ( level_active == level ) {
203 // just disabĺe level filter
207 level_active = level;
208 globalOutputStream() << "UFO:AI: level_active: " << level_active << ", flag: " << flag << ".\n";
211 GlobalSceneGraph().traverse( BrushGetLevel( brushes, flag, true, true, true ) );
214 GlobalSceneGraph().traverse( EntityFindByName( "func_door", entities, level, true ) );
215 GlobalSceneGraph().traverse( EntityFindByName( "func_breakable", entities, level, true ) );
216 GlobalSceneGraph().traverse( EntityFindByName( "misc_model", entities, level, true ) );
217 GlobalSceneGraph().traverse( EntityFindByName( "misc_particle", entities, level, true ) );
220 if ( brushes.empty() ) {
221 globalOutputStream() << "UFO:AI: No brushes.\n";
225 globalOutputStream() << "UFO:AI: Found " << Unsigned( brushes.size() ) << " brushes.\n";
228 // now let's filter all entities like misc_model, func_breakable and func_door that have the spawnflags set
229 if ( entities.empty() ) {
230 globalOutputStream() << "UFO:AI: No entities.\n";
234 globalOutputStream() << "UFO:AI: Found " << Unsigned( entities.size() ) << " entities.\n";
239 void filter_stepon( void ){
240 if ( stepon_active ) {
241 stepon_active = false;
244 stepon_active = true;
247 GlobalSceneGraph().traverse( BrushGetLevel( brushes, CONTENTS_STEPON, true, false, stepon_active ) );
249 if ( brushes.empty() ) {
250 globalOutputStream() << "UFO:AI: No brushes.\n";
254 globalOutputStream() << "UFO:AI: Hiding " << Unsigned( brushes.size() ) << " stepon brushes.\n";
258 void filter_nodraw( void ){
259 if ( nodraw_active ) {
260 nodraw_active = false;
263 nodraw_active = true;
266 GlobalSceneGraph().traverse( BrushGetLevel( brushes, SURF_NODRAW, false, false, nodraw_active ) );
269 if ( brushes.empty() ) {
270 globalOutputStream() << "UFO:AI: No brushes.\n";
274 globalOutputStream() << "UFO:AI: Hiding " << Unsigned( brushes.size() ) << " nodraw brushes.\n";
279 void filter_actorclip( void ){
280 if ( actorclip_active ) {
281 actorclip_active = false;
284 actorclip_active = true;
287 GlobalSceneGraph().traverse( BrushGetLevel( brushes, CONTENTS_ACTORCLIP, true, false, actorclip_active ) );
290 if ( brushes.empty() ) {
291 globalOutputStream() << "UFO:AI: No brushes.\n";
295 globalOutputStream() << "UFO:AI: Hiding " << Unsigned( brushes.size() ) << " actorclip brushes.\n";
300 void filter_weaponclip( void ){
301 if ( weaponclip_active ) {
302 weaponclip_active = false;
305 weaponclip_active = true;
308 GlobalSceneGraph().traverse( BrushGetLevel( brushes, CONTENTS_WEAPONCLIP, true, false, weaponclip_active ) );
311 if ( brushes.empty() ) {
312 globalOutputStream() << "UFO:AI: No brushes.\n";
316 globalOutputStream() << "UFO:AI: Hiding " << Unsigned( brushes.size() ) << " weaponclip brushes.\n";