]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - contrib/ufoaiplug/ufoai_filters.cpp
Merge remote-tracking branch 'ttimo/master'
[xonotic/netradiant.git] / contrib / ufoaiplug / 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 bool nodraw_active = false;
35 bool weaponclip_active = false;
36 int level_active = 0;
37
38 // TODO: This should be added to ibrush.h
39 // like already done for Node_getEntity in ientity.h
40 // FIXME: Doesn't belong here
41 inline Brush* Node_getBrush( scene::Node& node ){
42         return NodeTypeCast<Brush>::cast( node );
43 }
44
45 void hide_node( scene::Node& node, bool hide ){
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 bool pre( const scene::Path& path, scene::Instance& instance ) const {
65         int spawnflagsInt;
66         Entity* entity = Node_getEntity( path.top() );
67         if ( entity != 0 ) {
68                 if ( string_equal( m_name, entity->getKeyValue( "classname" ) ) ) {
69                         const char *spawnflags = entity->getKeyValue( "spawnflags" );
70                         globalOutputStream() << "spawnflags for " << m_name << ": " << spawnflags << ".\n";
71
72                         if ( !string_empty( spawnflags ) ) {
73                                 spawnflagsInt = atoi( spawnflags );
74                                 if ( !( spawnflagsInt & m_flag ) ) {
75                                         hide_node( path.top(), m_hide );   // hide/unhide
76                                         m_entitylist.push_back( entity );
77                                 }
78                         }
79                         else
80                         {
81                                 globalOutputStream() << "UFO:AI: Warning: no spawnflags for " << m_name << ".\n";
82                         }
83                 }
84         }
85         return true;
86 }
87 };
88
89 class ForEachFace : public BrushVisitor
90 {
91 Brush &m_brush;
92 public:
93 mutable int m_contentFlagsVis;
94 mutable int m_surfaceFlagsVis;
95
96 ForEachFace( Brush& brush )
97         : m_brush( brush ){
98         m_contentFlagsVis = -1;
99         m_surfaceFlagsVis = -1;
100 }
101
102 void visit( Face& face ) const {
103 #if _DEBUG
104         if ( m_surfaceFlagsVis < 0 ) {
105                 m_surfaceFlagsVis = face.getShader().m_flags.m_surfaceFlags;
106         }
107         else if ( m_surfaceFlagsVis >= 0 && m_surfaceFlagsVis != face.getShader().m_flags.m_surfaceFlags ) {
108                 globalOutputStream() << "Faces with different surfaceflags at brush\n";
109         }
110         if ( m_contentFlagsVis < 0 ) {
111                 m_contentFlagsVis = face.getShader().m_flags.m_contentFlags;
112         }
113         else if ( m_contentFlagsVis >= 0 && m_contentFlagsVis != face.getShader().m_flags.m_contentFlags ) {
114                 globalOutputStream() << "Faces with different contentflags at brush\n";
115         }
116 #else
117         m_surfaceFlagsVis = face.getShader().m_flags.m_surfaceFlags;
118         m_contentFlagsVis = face.getShader().m_flags.m_contentFlags;
119 #endif
120 }
121 };
122
123 typedef std::list<Brush*> brushlist_t;
124
125 class BrushGetLevel : public scene::Graph::Walker
126 {
127 brushlist_t& m_brushlist;
128 int m_flag;
129 bool m_content;     // if true - use m_contentFlags - otherwise m_surfaceFlags
130 mutable bool m_notset;
131 mutable bool m_hide;
132 public:
133 BrushGetLevel( brushlist_t& brushlist, int flag, bool content, bool notset, bool hide )
134         : m_brushlist( brushlist ), m_flag( flag ), m_content( content ), m_notset( notset ), m_hide( hide ){
135 }
136 bool pre( const scene::Path& path, scene::Instance& instance ) const {
137         Brush* brush = Node_getBrush( path.top() );
138         if ( brush != 0 ) {
139                 ForEachFace faces( *brush );
140                 brush->forEachFace( faces );
141                 // contentflags?
142                 if ( m_content ) {
143                         // are any flags set?
144                         if ( faces.m_contentFlagsVis > 0 ) {
145                                 // flag should not be set
146                                 if ( m_notset && ( !( faces.m_contentFlagsVis & m_flag ) ) ) {
147                                         hide_node( path.top(), m_hide );
148                                         m_brushlist.push_back( brush );
149                                 }
150                                 // check whether flag is set
151                                 else if ( !m_notset && ( ( faces.m_contentFlagsVis & m_flag ) ) ) {
152                                         hide_node( path.top(), m_hide );
153                                         m_brushlist.push_back( brush );
154                                 }
155                         }
156                 }
157                 // surfaceflags?
158                 else
159                 {
160                         // are any flags set?
161                         if ( faces.m_surfaceFlagsVis > 0 ) {
162                                 // flag should not be set
163                                 if ( m_notset && ( !( faces.m_surfaceFlagsVis & m_flag ) ) ) {
164                                         hide_node( path.top(), m_hide );
165                                         m_brushlist.push_back( brush );
166                                 }
167                                 // check whether flag is set
168                                 else if ( !m_notset && ( ( faces.m_surfaceFlagsVis & m_flag ) ) ) {
169                                         hide_node( path.top(), m_hide );
170                                         m_brushlist.push_back( brush );
171                                 }
172                         }
173                 }
174
175         }
176         return true;
177 }
178 };
179
180 /**
181  * @brief Activates the level filter for the given level
182  * @param[in] level Which level to show?
183  * @todo Entities
184  */
185 void filter_level( int flag ){
186         int level;
187         brushlist_t brushes;
188         entitylist_t entities;
189
190         level = ( flag >> 8 );
191
192         if ( level_active ) {
193                 GlobalSceneGraph().traverse( BrushGetLevel( brushes, ( level_active << 8 ), true, true, false ) );
194                 GlobalSceneGraph().traverse( EntityFindByName( "func_door", entities, level_active, false ) );
195                 GlobalSceneGraph().traverse( EntityFindByName( "func_breakable", entities, level_active, false ) );
196                 GlobalSceneGraph().traverse( EntityFindByName( "misc_model", entities, level_active, false ) );
197                 GlobalSceneGraph().traverse( EntityFindByName( "misc_particle", entities, level_active, false ) );
198                 entities.erase( entities.begin(), entities.end() );
199                 brushes.erase( brushes.begin(), brushes.end() );
200                 if ( level_active == level ) {
201                         level_active = 0;
202                         // just disabĺe level filter
203                         return;
204                 }
205         }
206         level_active = level;
207         globalOutputStream() << "UFO:AI: level_active: " << level_active << ", flag: " << flag << ".\n";
208
209         // first all brushes
210         GlobalSceneGraph().traverse( BrushGetLevel( brushes, flag, true, true, true ) );
211
212         // now all entities
213         GlobalSceneGraph().traverse( EntityFindByName( "func_door", entities, level, true ) );
214         GlobalSceneGraph().traverse( EntityFindByName( "func_breakable", entities, level, true ) );
215         GlobalSceneGraph().traverse( EntityFindByName( "misc_model", entities, level, true ) );
216         GlobalSceneGraph().traverse( EntityFindByName( "misc_particle", entities, level, true ) );
217
218 #ifdef _DEBUG
219         if ( brushes.empty() ) {
220                 globalOutputStream() << "UFO:AI: No brushes.\n";
221         }
222         else
223         {
224                 globalOutputStream() << "UFO:AI: Found " << Unsigned( brushes.size() ) << " brushes.\n";
225         }
226
227         // now let's filter all entities like misc_model, func_breakable and func_door that have the spawnflags set
228         if ( entities.empty() ) {
229                 globalOutputStream() << "UFO:AI: No entities.\n";
230         }
231         else
232         {
233                 globalOutputStream() << "UFO:AI: Found " << Unsigned( entities.size() ) << " entities.\n";
234         }
235 #endif
236 }
237
238 void filter_stepon( void ){
239         if ( stepon_active ) {
240                 stepon_active = false;
241         }
242         else {
243                 stepon_active = true;
244         }
245         brushlist_t brushes;
246         GlobalSceneGraph().traverse( BrushGetLevel( brushes, CONTENTS_STEPON, true, false, stepon_active ) );
247
248         if ( brushes.empty() ) {
249                 globalOutputStream() << "UFO:AI: No brushes.\n";
250         }
251         else
252         {
253                 globalOutputStream() << "UFO:AI: Hiding " << Unsigned( brushes.size() ) << " stepon brushes.\n";
254         }
255 }
256
257 void filter_nodraw( void ){
258         if ( nodraw_active ) {
259                 nodraw_active = false;
260         }
261         else {
262                 nodraw_active = true;
263         }
264         brushlist_t brushes;
265         GlobalSceneGraph().traverse( BrushGetLevel( brushes, SURF_NODRAW, false, false, nodraw_active ) );
266
267 #ifdef _DEBUG
268         if ( brushes.empty() ) {
269                 globalOutputStream() << "UFO:AI: No brushes.\n";
270         }
271         else
272         {
273                 globalOutputStream() << "UFO:AI: Hiding " << Unsigned( brushes.size() ) << " nodraw brushes.\n";
274         }
275 #endif
276 }
277
278 void filter_actorclip( void ){
279         if ( actorclip_active ) {
280                 actorclip_active = false;
281         }
282         else {
283                 actorclip_active = true;
284         }
285         brushlist_t brushes;
286         GlobalSceneGraph().traverse( BrushGetLevel( brushes, CONTENTS_ACTORCLIP, true, false, actorclip_active ) );
287
288 #ifdef _DEBUG
289         if ( brushes.empty() ) {
290                 globalOutputStream() << "UFO:AI: No brushes.\n";
291         }
292         else
293         {
294                 globalOutputStream() << "UFO:AI: Hiding " << Unsigned( brushes.size() ) << " actorclip brushes.\n";
295         }
296 #endif
297 }
298
299 void filter_weaponclip( void ){
300         if ( weaponclip_active ) {
301                 weaponclip_active = false;
302         }
303         else {
304                 weaponclip_active = true;
305         }
306         brushlist_t brushes;
307         GlobalSceneGraph().traverse( BrushGetLevel( brushes, CONTENTS_WEAPONCLIP, true, false, weaponclip_active ) );
308
309 #ifdef _DEBUG
310         if ( brushes.empty() ) {
311                 globalOutputStream() << "UFO:AI: No brushes.\n";
312         }
313         else
314         {
315                 globalOutputStream() << "UFO:AI: Hiding " << Unsigned( brushes.size() ) << " weaponclip brushes.\n";
316         }
317 #endif
318 }