]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/filters.cpp
Merge pull request #19 from merlin1991/scons-update
[xonotic/netradiant.git] / radiant / filters.cpp
1 /*
2    Copyright (c) 2001, Loki software, inc.
3    All rights reserved.
4
5    Redistribution and use in source and binary forms, with or without modification,
6    are permitted provided that the following conditions are met:
7
8    Redistributions of source code must retain the above copyright notice, this list
9    of conditions and the following disclaimer.
10
11    Redistributions in binary form must reproduce the above copyright notice, this
12    list of conditions and the following disclaimer in the documentation and/or
13    other materials provided with the distribution.
14
15    Neither the name of Loki software nor the names of its contributors may be used
16    to endorse or promote products derived from this software without specific prior
17    written permission.
18
19    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
20    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22    DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
23    DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26    ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "stdafx.h"
32
33 /*
34     Rambetter on Sun Jan 23, 2011:
35
36     What follows is a discussion of the introduction to some new members and functions
37     such as baseFilters, baseFilterExcludes, FilterAddImpl(), and so on.
38
39     There was a problem that "base" filters were not taking effect as a result of
40     user action such as clicking a filter checkbox.  The reason why the base filters
41     were not being updated is because the previous logic of updating the filters had
42     been commented out.  It was commented out because the previous logic deleted ALL
43     filters (including plugin filters) and re-created only the base filters.  So in
44     effect, all plugin filters would be deleted whenever a filter checkbox was altered.
45
46     So, we need some way of knowing which are the base filters so that we can take
47     action when a filter checkbox is marked [or unmarked].  Then we can update
48     the base filters by either deleting and recreating them, or by changing their
49     active state in an intelligent manner.  I am choosing to do the latter.
50
51     My goal here is to preserve the structure bfilter_t completely as it has been
52     historically.  I feel that modifying bfilter_t is dangerous with respect to breaking
53     plugins.  So what I'm doing instead is tracking which are the base filters via
54     external array, baseFilters.  The array baseFilterExcludes keeps track of the "exclude"
55     parameter for the corresponding filter.
56  */
57
58 #define MAX_BASE_FILTERS 32
59 static bfilter_t   *baseFilters[MAX_BASE_FILTERS];
60 static int baseFilterExcludes[MAX_BASE_FILTERS];
61 static int numBaseFilters = 0;
62
63 // This shall not be called from outside filters.cpp.
64 bfilter_t *FilterAddImpl( bfilter_t *pFilter, int type, int bmask, const char *str, int exclude, bool baseFilter ){
65         bfilter_t *pNew = new bfilter_t;
66         pNew->next = pFilter;
67         pNew->attribute = type;
68         if ( type == 1 || type == 3 ) {
69                 pNew->string = str;
70         }
71         if ( type == 2 || type == 4 || type == 5 || type == 6 || type == 7 ) {
72                 pNew->mask = bmask;
73         }
74         if ( g_qeglobals.d_savedinfo.exclude & exclude ) {
75                 pNew->active = true;
76         }
77         else{
78                 pNew->active = false;
79         }
80         if ( baseFilter ) {
81                 if ( numBaseFilters >= MAX_BASE_FILTERS ) {
82                         Error( "Base filters count exceeds MAX_BASE_FILTERS" );
83                 }
84                 baseFilters[numBaseFilters] = pNew;
85                 baseFilterExcludes[numBaseFilters] = exclude;
86                 numBaseFilters++;
87         }
88         return pNew;
89 }
90
91 // type 1 = texture filter (name)
92 // type 3 = entity filter (name)
93 // type 2 = QER_* shader flags
94 // type 4 = entity classes
95 // type 5 = surface flags (q2)
96 // type 6 = content flags (q2)
97 // type 7 = content flags - no match (q2)
98 bfilter_t *FilterAdd( bfilter_t *pFilter, int type, int bmask, const char *str, int exclude ){
99         return FilterAddImpl( pFilter, type, bmask, str, exclude, false );
100 }
101
102 bfilter_t *FilterCreate( int type, int bmask, const char *str, int exclude ){
103         g_qeglobals.d_savedinfo.filters = FilterAdd( g_qeglobals.d_savedinfo.filters, type, bmask, str, exclude );
104         Syn_Printf( "Added filter %s (type: %i, bmask: %i, exclude: %i)\n", str, type, bmask, exclude );
105         return g_qeglobals.d_savedinfo.filters;
106 }
107
108 extern void PerformFiltering();
109
110 void FiltersActivate( void ){
111         PerformFiltering();
112         Sys_UpdateWindows( W_XY | W_CAMERA );
113 }
114
115 // removes the filter list at *pFilter, returns NULL pointer
116 // IMPORTANT NOTE: Some plugins add filters, and those will be removed here as well.
117 // Therefore, this function should rarely be used.
118 bfilter_t *FilterListDelete( bfilter_t *pFilter ){
119         if ( pFilter != NULL ) {
120                 FilterListDelete( pFilter->next );
121                 delete pFilter;
122         }
123         else
124         {
125                 memset( baseFilters, 0, sizeof( baseFilters ) ); // Strictly speaking we don't really need this.
126                 memset( baseFilterExcludes, 0, sizeof( baseFilterExcludes ) ); // Strictly speaking we don't really need this.
127                 numBaseFilters = 0; // We do need this.
128         }
129         return NULL;
130 }
131
132
133 bfilter_t *FilterAddBase( bfilter_t *pFilter ){
134         pFilter = FilterAddImpl( pFilter,1,0,"clip",EXCLUDE_CLIP,true );
135         pFilter = FilterAddImpl( pFilter,1,0,"caulk",EXCLUDE_CAULK,true );
136         pFilter = FilterAddImpl( pFilter,1,0,"liquids",EXCLUDE_LIQUIDS,true );
137         pFilter = FilterAddImpl( pFilter,1,0,"hint",EXCLUDE_HINTSSKIPS,true );
138         pFilter = FilterAddImpl( pFilter,1,0,"clusterportal",EXCLUDE_CLUSTERPORTALS,true );
139         pFilter = FilterAddImpl( pFilter,1,0,"areaportal",EXCLUDE_AREAPORTALS,true );
140         pFilter = FilterAddImpl( pFilter,2,QER_TRANS,NULL,EXCLUDE_TRANSLUCENT,true );
141         pFilter = FilterAddImpl( pFilter,3,0,"trigger",EXCLUDE_TRIGGERS,true );
142         pFilter = FilterAddImpl( pFilter,3,0,"misc_model",EXCLUDE_MODELS,true );
143         pFilter = FilterAddImpl( pFilter,3,0,"misc_gamemodel",EXCLUDE_MODELS,true );
144         pFilter = FilterAddImpl( pFilter,4,ECLASS_LIGHT,NULL,EXCLUDE_LIGHTS,true );
145         pFilter = FilterAddImpl( pFilter,4,ECLASS_PATH,NULL,EXCLUDE_PATHS,true );
146         pFilter = FilterAddImpl( pFilter,1,0,"lightgrid",EXCLUDE_LIGHTGRID,true );
147         pFilter = FilterAddImpl( pFilter,1,0,"botclip",EXCLUDE_BOTCLIP,true );
148         pFilter = FilterAddImpl( pFilter,1,0,"clipmonster",EXCLUDE_BOTCLIP,true );
149         return pFilter;
150 }
151
152 void FilterUpdateBase(){
153         int i;
154         bfilter_t   *filter;
155         int exclude;
156         for ( i = 0; i < numBaseFilters; i++ )
157         {
158                 filter = baseFilters[i];
159                 exclude = baseFilterExcludes[i];
160                 if ( g_qeglobals.d_savedinfo.exclude & exclude ) {
161                         filter->active = true;
162                 }
163                 else{
164                         filter->active = false;
165                 }
166         }
167 }
168
169 /*
170    ==================
171    FilterBrush
172    ==================
173  */
174
175 bool FilterBrush( brush_t *pb ){
176
177         if ( !pb->owner ) {
178                 return FALSE;       // during construction
179
180         }
181         if ( pb->hiddenBrush ) {
182                 return TRUE;
183         }
184
185         if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_WORLD ) {
186                 if ( strcmp( pb->owner->eclass->name, "worldspawn" ) == 0 || !strcmp( pb->owner->eclass->name,"func_group" ) ) { // hack, treating func_group as world
187                         return TRUE;
188                 }
189         }
190
191         if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_ENT ) {
192                 if ( strcmp( pb->owner->eclass->name, "worldspawn" ) != 0 && strcmp( pb->owner->eclass->name,"func_group" ) ) { // hack, treating func_group as world
193                         return TRUE;
194                 }
195         }
196
197         if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_CURVES ) {
198                 if ( pb->patchBrush ) {
199                         return TRUE;
200                 }
201         }
202
203
204         if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_DETAILS ) {
205                 if ( !pb->patchBrush && pb->brush_faces->texdef.contents & CONTENTS_DETAIL ) {
206                         return TRUE;
207                 }
208         }
209         if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_STRUCTURAL ) {
210                 if ( !pb->patchBrush && !( pb->brush_faces->texdef.contents & CONTENTS_DETAIL ) ) {
211                         return TRUE;
212                 }
213         }
214
215         // if brush belongs to world entity or a brushmodel entity and is not a patch
216         if ( ( strcmp( pb->owner->eclass->name, "worldspawn" ) == 0
217                    || !strncmp( pb->owner->eclass->name, "func", 4 )
218                    || !strncmp( pb->owner->eclass->name, "trigger", 7 ) ) && !pb->patchBrush ) {
219                 bool filterbrush = false;
220                 for ( face_t *f = pb->brush_faces; f != NULL; f = f->next )
221                 {
222                         filterbrush = false;
223                         for ( bfilter_t *filters = g_qeglobals.d_savedinfo.filters;
224                                   filters != NULL;
225                                   filters = filters->next )
226                         {
227                                 if ( !filters->active ) {
228                                         continue;
229                                 }
230                                 // exclude by attribute 1 brush->face->pShader->getName()
231                                 if ( filters->attribute == 1 ) {
232                                         if ( strstr( f->pShader->getName(),filters->string ) ) {
233                                                 filterbrush = true;
234                                                 break;
235                                         }
236                                 }
237                                 // exclude by attribute 2 brush->face->pShader->getFlags()
238                                 else if ( filters->attribute == 2 ) {
239                                         if ( f->pShader->getFlags() & filters->mask ) {
240                                                 filterbrush = true;
241                                                 break;
242                                         }
243                                         // quake2 - 5 == surface flags, 6 == content flags
244                                 }
245                                 else if ( filters->attribute == 5 ) {
246                                         if ( f->texdef.flags && f->texdef.flags & filters->mask ) {
247                                                 filterbrush = true;
248                                                 break;
249                                         }
250                                 }
251                                 else if ( filters->attribute == 6 ) {
252                                         if ( f->texdef.contents && f->texdef.contents & filters->mask ) {
253                                                 filterbrush = true;
254                                                 break;
255                                         }
256                                 }
257                                 else if ( filters->attribute == 7 ) {
258                                         if ( f->texdef.contents && !( f->texdef.contents & filters->mask ) ) {
259                                                 filterbrush = true;
260                                                 break;
261                                         }
262                                 }
263                         }
264                         if ( !filterbrush ) {
265                                 break;
266                         }
267                 }
268                 if ( filterbrush ) { // if no face is found that should not be excluded
269                         return true; // exclude this brush
270                 }
271         }
272
273         // if brush is a patch
274         if ( pb->patchBrush ) {
275                 bool drawpatch = true;
276                 for ( bfilter_t *filters = g_qeglobals.d_savedinfo.filters;
277                           filters != NULL;
278                           filters = filters->next )
279                 {
280                         // exclude by attribute 1 (for patch) brush->pPatch->pShader->getName()
281                         if ( filters->active
282                                  && filters->attribute == 1 ) {
283                                 if ( strstr( pb->pPatch->pShader->getName(),filters->string ) ) {
284                                         drawpatch = false;
285                                         break;
286                                 }
287                         }
288
289                         // exclude by attribute 2 (for patch) brush->pPatch->pShader->getFlags()
290                         if ( filters->active
291                                  && filters->attribute == 2 ) {
292                                 if ( pb->pPatch->pShader->getFlags() & filters->mask ) {
293                                         drawpatch = false;
294                                         break;
295                                 }
296                         }
297                 }
298                 if ( !drawpatch ) { // if a shader is found that should be excluded
299                         return TRUE; // exclude this patch
300                 }
301         }
302
303         if ( strcmp( pb->owner->eclass->name, "worldspawn" ) != 0 ) { // if brush does not belong to world entity
304                 bool drawentity = true;
305                 for ( bfilter_t *filters = g_qeglobals.d_savedinfo.filters;
306                           filters != NULL;
307                           filters = filters->next )
308                 {
309                         // exclude by attribute 3 brush->owner->eclass->name
310                         if ( filters->active
311                                  && filters->attribute == 3 ) {
312                                 if ( strstr( pb->owner->eclass->name,filters->string ) ) {
313                                         drawentity = false;
314                                         break;
315                                 }
316                         }
317
318                         // exclude by attribute 4 brush->owner->eclass->nShowFlags
319                         else if ( filters->active
320                                           && filters->attribute == 4 ) {
321                                 if ( pb->owner->eclass->nShowFlags & filters->mask ) {
322                                         drawentity = false;
323                                         break;
324                                 }
325                         }
326                 }
327                 if ( !drawentity ) { // if an eclass property is found that should be excluded
328                         return TRUE; // exclude this brush
329                 }
330         }
331         return FALSE;
332 }