]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/filters.cpp
Updating Windows compile guide after the major overhaul of Windows
[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 {
66         bfilter_t *pNew = new bfilter_t;
67         pNew->next = pFilter;
68         pNew->attribute = type;
69         if (type == 1 || type == 3) pNew->string = str;
70         if (type == 2 || type == 4 || type == 5 || type == 6 || type == 7) pNew->mask = bmask;
71         if (g_qeglobals.d_savedinfo.exclude & exclude)
72                 pNew->active = true;
73         else
74                 pNew->active = false;
75         if (baseFilter)
76         {
77                 if (numBaseFilters >= MAX_BASE_FILTERS)
78                         Error("Base filters count exceeds MAX_BASE_FILTERS");
79                 baseFilters[numBaseFilters] = pNew;
80                 baseFilterExcludes[numBaseFilters] = exclude;
81                 numBaseFilters++;
82         }
83         return pNew;
84 }
85
86 // type 1 = texture filter (name)
87 // type 3 = entity filter (name)
88 // type 2 = QER_* shader flags
89 // type 4 = entity classes
90 // type 5 = surface flags (q2)
91 // type 6 = content flags (q2)
92 // type 7 = content flags - no match (q2)
93 bfilter_t *FilterAdd(bfilter_t *pFilter, int type, int bmask, const char *str, int exclude)
94 {
95         return FilterAddImpl(pFilter, type, bmask, str, exclude, false);
96 }
97
98 bfilter_t *FilterCreate (int type, int bmask, const char *str, int exclude)
99 {
100         g_qeglobals.d_savedinfo.filters = FilterAdd(g_qeglobals.d_savedinfo.filters, type, bmask, str, exclude);
101         Syn_Printf("Added filter %s (type: %i, bmask: %i, exclude: %i)\n", str, type, bmask, exclude);
102         return g_qeglobals.d_savedinfo.filters;
103 }
104
105 extern void PerformFiltering();
106
107 void FiltersActivate (void)
108 {
109         PerformFiltering();
110         Sys_UpdateWindows(W_XY|W_CAMERA);
111 }
112
113   // removes the filter list at *pFilter, returns NULL pointer
114 // IMPORTANT NOTE: Some plugins add filters, and those will be removed here as well.
115 // Therefore, this function should rarely be used.
116 bfilter_t *FilterListDelete(bfilter_t *pFilter)
117 {
118         if (pFilter != NULL)
119         {
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 {
135         pFilter = FilterAddImpl(pFilter,1,0,"clip",EXCLUDE_CLIP,true);
136         pFilter = FilterAddImpl(pFilter,1,0,"caulk",EXCLUDE_CAULK,true);
137         pFilter = FilterAddImpl(pFilter,1,0,"liquids",EXCLUDE_LIQUIDS,true);
138         pFilter = FilterAddImpl(pFilter,1,0,"hint",EXCLUDE_HINTSSKIPS,true);
139         pFilter = FilterAddImpl(pFilter,1,0,"clusterportal",EXCLUDE_CLUSTERPORTALS,true);
140         pFilter = FilterAddImpl(pFilter,1,0,"areaportal",EXCLUDE_AREAPORTALS,true);
141         pFilter = FilterAddImpl(pFilter,2,QER_TRANS,NULL,EXCLUDE_TRANSLUCENT,true);
142         pFilter = FilterAddImpl(pFilter,3,0,"trigger",EXCLUDE_TRIGGERS,true);
143         pFilter = FilterAddImpl(pFilter,3,0,"misc_model",EXCLUDE_MODELS,true);
144         pFilter = FilterAddImpl(pFilter,3,0,"misc_gamemodel",EXCLUDE_MODELS,true);
145         pFilter = FilterAddImpl(pFilter,4,ECLASS_LIGHT,NULL,EXCLUDE_LIGHTS,true);
146         pFilter = FilterAddImpl(pFilter,4,ECLASS_PATH,NULL,EXCLUDE_PATHS,true);
147         pFilter = FilterAddImpl(pFilter,1,0,"lightgrid",EXCLUDE_LIGHTGRID,true);
148         pFilter = FilterAddImpl(pFilter,1,0,"botclip",EXCLUDE_BOTCLIP,true);
149         pFilter = FilterAddImpl(pFilter,1,0,"clipmonster",EXCLUDE_BOTCLIP,true);
150         return pFilter;
151 }
152
153 void FilterUpdateBase()
154 {
155         int             i;
156         bfilter_t       *filter;
157         int             exclude;
158         for (i = 0; i < numBaseFilters; i++)
159         {
160                 filter = baseFilters[i];
161                 exclude = baseFilterExcludes[i];
162                 if (g_qeglobals.d_savedinfo.exclude & exclude)
163                         filter->active = true;
164                 else
165                         filter->active = false;
166         }
167 }
168
169 /*
170 ==================
171 FilterBrush
172 ==================
173 */
174
175 bool FilterBrush(brush_t *pb)
176 {
177
178         if (!pb->owner)
179                 return FALSE;           // during construction
180
181         if (pb->hiddenBrush)
182                 return TRUE;
183
184         if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_WORLD)
185         {
186                 if (strcmp(pb->owner->eclass->name, "worldspawn") == 0 || !strcmp(pb->owner->eclass->name,"func_group")) // hack, treating func_group as world
187                 {
188                         return TRUE;
189                 }
190         }
191
192         if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_ENT)
193         {
194                 if (strcmp(pb->owner->eclass->name, "worldspawn") != 0 && strcmp(pb->owner->eclass->name,"func_group")) // hack, treating func_group as world
195                 {
196                         return TRUE;
197                 }
198         }
199
200         if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_CURVES )
201         {
202                 if (pb->patchBrush)
203                 {
204                         return TRUE;
205                 }
206         }
207
208
209         if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_DETAILS )
210         {
211                 if (!pb->patchBrush && pb->brush_faces->texdef.contents & CONTENTS_DETAIL )
212                 {
213                         return TRUE;
214                 }
215         }
216         if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_STRUCTURAL )
217         {
218                 if (!pb->patchBrush && !( pb->brush_faces->texdef.contents & CONTENTS_DETAIL ))
219                 {
220                         return TRUE;
221                 }
222         }
223
224         // if brush belongs to world entity or a brushmodel entity and is not a patch
225         if ( ( strcmp(pb->owner->eclass->name, "worldspawn") == 0
226                 || !strncmp( pb->owner->eclass->name, "func", 4)
227                 || !strncmp( pb->owner->eclass->name, "trigger", 7) ) && !pb->patchBrush )
228         {
229                 bool filterbrush = false;
230                 for (face_t *f=pb->brush_faces;f!=NULL;f = f->next)
231                 {
232                         filterbrush=false;
233                         for (bfilter_t *filters = g_qeglobals.d_savedinfo.filters;
234                         filters != NULL;
235                         filters = filters->next)
236                         {
237                                 if (!filters->active)
238                                         continue;
239                                 // exclude by attribute 1 brush->face->pShader->getName()
240                                 if (filters->attribute == 1)
241                                 {
242                                         if (strstr(f->pShader->getName(),filters->string))
243                                         {
244                                                 filterbrush=true;
245                                                 break;
246                                         }
247                                 }
248                                 // exclude by attribute 2 brush->face->pShader->getFlags()
249                                 else if (filters->attribute == 2)
250                                 {
251                                         if (f->pShader->getFlags() & filters->mask)
252                                         {
253                                                 filterbrush=true;
254                                                 break;
255                                         }
256                                 // quake2 - 5 == surface flags, 6 == content flags
257                                 }
258                                 else if (filters->attribute == 5)
259                                 {
260                                         if (f->texdef.flags && f->texdef.flags & filters->mask)
261                                         {
262                                                 filterbrush=true;
263                                                 break;
264                                         }
265                                 }
266                                 else if (filters->attribute == 6)
267                                 {
268                                         if (f->texdef.contents && f->texdef.contents & filters->mask)
269                                         {
270                                                 filterbrush=true;
271                                                 break;
272                                         }
273                                 }
274                                 else if (filters->attribute == 7)
275                                 {
276                                         if (f->texdef.contents && !(f->texdef.contents & filters->mask))
277                                         {
278                                                 filterbrush=true;
279                                                 break;
280                                         }
281                                 }
282                         }
283                         if (!filterbrush)
284                                 break;
285                 }
286                 if (filterbrush)// if no face is found that should not be excluded
287                         return true; // exclude this brush
288         }
289
290         // if brush is a patch
291         if ( pb->patchBrush )
292         {
293                 bool drawpatch=true;
294                 for (bfilter_t *filters = g_qeglobals.d_savedinfo.filters;
295                 filters != NULL;
296                 filters = filters->next)
297                 {
298                         // exclude by attribute 1 (for patch) brush->pPatch->pShader->getName()
299                         if (filters->active
300                                 && filters->attribute == 1)
301                         {
302                                 if (strstr(pb->pPatch->pShader->getName(),filters->string))
303                                 {
304                                         drawpatch=false;
305                                         break;
306                                 }
307                         }
308
309                         // exclude by attribute 2 (for patch) brush->pPatch->pShader->getFlags()
310                         if (filters->active
311                                 && filters->attribute == 2)
312                         {
313                                 if (pb->pPatch->pShader->getFlags() & filters->mask)
314                                 {
315                                         drawpatch=false;
316                                         break;
317                                 }
318                         }
319                 }
320                 if (!drawpatch) // if a shader is found that should be excluded
321                         return TRUE; // exclude this patch
322         }
323
324         if (strcmp(pb->owner->eclass->name, "worldspawn") != 0) // if brush does not belong to world entity
325         {
326                 bool drawentity=true;
327                 for (bfilter_t *filters = g_qeglobals.d_savedinfo.filters;
328                 filters != NULL;
329                 filters = filters->next)
330                 {
331                         // exclude by attribute 3 brush->owner->eclass->name
332                         if (filters->active
333                                 && filters->attribute == 3)
334                         {
335                                 if (strstr(pb->owner->eclass->name,filters->string))
336                                 {
337                                         drawentity=false;
338                                         break;
339                                 }
340                         }
341
342                         // exclude by attribute 4 brush->owner->eclass->nShowFlags
343                         else if (filters->active
344                                 && filters->attribute == 4)
345                         {
346                                 if ( pb->owner->eclass->nShowFlags & filters->mask )
347                                 {
348                                         drawentity=false;
349                                         break;
350                                 }
351                         }
352                 }
353                 if (!drawentity) // if an eclass property is found that should be excluded
354                         return TRUE; // exclude this brush
355         }
356         return FALSE;
357 }