apply misc fixes from Markus Fischer and Rambetter
[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 // type 1 = texture filter (name)
34 // type 3 = entity filter (name)
35 // type 2 = QER_* shader flags
36 // type 4 = entity classes
37 // type 5 = surface flags (q2)
38 // type 6 = content flags (q2)
39 // type 7 = content flags - no match (q2)
40 bfilter_t *FilterAdd(bfilter_t *pFilter, int type, int bmask, const char *str, int exclude)
41 {
42         bfilter_t *pNew = new bfilter_t;
43         pNew->next = pFilter;
44         pNew->attribute = type;
45         if (type == 1 || type == 3) pNew->string = str;
46         if (type == 2 || type == 4 || type == 5 || type == 6 || type == 7) pNew->mask = bmask;
47         if (g_qeglobals.d_savedinfo.exclude & exclude)
48                 pNew->active = true;
49         else
50                 pNew->active = false;
51         return pNew;
52 }
53
54 bfilter_t *FilterCreate (int type, int bmask, const char *str, int exclude)
55 {
56         g_qeglobals.d_savedinfo.filters = FilterAdd(g_qeglobals.d_savedinfo.filters, type, bmask, str, exclude);
57         Syn_Printf("Added filter %s (type: %i, bmask: %i, exclude: %i)\n", str, type, bmask, exclude);
58         return g_qeglobals.d_savedinfo.filters;
59 }
60
61 extern void PerformFiltering();
62
63 void FiltersActivate (void)
64 {
65         PerformFiltering();
66         Sys_UpdateWindows(W_XY|W_CAMERA);
67 }
68
69   // removes the filter list at *pFilter, returns NULL pointer
70 bfilter_t *FilterListDelete(bfilter_t *pFilter)
71 {
72         if (pFilter != NULL)
73         {
74                 FilterListDelete(pFilter->next);
75                 delete pFilter;
76         }
77         return NULL;
78 }
79
80
81  //spog - FilterUpdate is called each time the filters are changed by menu or shortcuts
82 bfilter_t *FilterUpdate(bfilter_t *pFilter)
83 {
84         pFilter = FilterAdd(pFilter,1,0,"clip",EXCLUDE_CLIP);
85         pFilter = FilterAdd(pFilter,1,0,"caulk",EXCLUDE_CAULK);
86         pFilter = FilterAdd(pFilter,1,0,"liquids",EXCLUDE_LIQUIDS);
87         pFilter = FilterAdd(pFilter,1,0,"hint",EXCLUDE_HINTSSKIPS);
88         pFilter = FilterAdd(pFilter,1,0,"clusterportal",EXCLUDE_CLUSTERPORTALS);
89         pFilter = FilterAdd(pFilter,1,0,"areaportal",EXCLUDE_AREAPORTALS);
90         pFilter = FilterAdd(pFilter,2,QER_TRANS,NULL,EXCLUDE_TRANSLUCENT);
91         pFilter = FilterAdd(pFilter,3,0,"trigger",EXCLUDE_TRIGGERS);
92         pFilter = FilterAdd(pFilter,3,0,"misc_model",EXCLUDE_MODELS);
93         pFilter = FilterAdd(pFilter,3,0,"misc_gamemodel",EXCLUDE_MODELS);
94         pFilter = FilterAdd(pFilter,4,ECLASS_LIGHT,NULL,EXCLUDE_LIGHTS);
95         pFilter = FilterAdd(pFilter,4,ECLASS_PATH,NULL,EXCLUDE_PATHS);
96         pFilter = FilterAdd(pFilter,1,0,"lightgrid",EXCLUDE_LIGHTGRID);
97         pFilter = FilterAdd(pFilter,1,0,"botclip",EXCLUDE_BOTCLIP);
98   pFilter = FilterAdd(pFilter,1,0,"clipmonster",EXCLUDE_BOTCLIP);
99         return pFilter;
100 }
101
102 /*
103 ==================
104 FilterBrush
105 ==================
106 */
107
108 bool FilterBrush(brush_t *pb)
109 {
110
111         if (!pb->owner)
112                 return FALSE;           // during construction
113
114         if (pb->hiddenBrush)
115                 return TRUE;
116
117         if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_WORLD)
118         {
119                 if (strcmp(pb->owner->eclass->name, "worldspawn") == 0 || !strcmp(pb->owner->eclass->name,"func_group")) // hack, treating func_group as world
120                 {
121                         return TRUE;
122                 }
123         }
124
125         if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_ENT)
126         {
127                 if (strcmp(pb->owner->eclass->name, "worldspawn") != 0 && strcmp(pb->owner->eclass->name,"func_group")) // hack, treating func_group as world
128                 {
129                         return TRUE;
130                 }
131         }
132
133         if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_CURVES )
134         {
135                 if (pb->patchBrush)
136                 {
137                         return TRUE;
138                 }
139         }
140
141
142         if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_DETAILS )
143         {
144                 if (!pb->patchBrush && pb->brush_faces->texdef.contents & CONTENTS_DETAIL )
145                 {
146                         return TRUE;
147                 }
148         }
149         if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_STRUCTURAL )
150         {
151                 if (!pb->patchBrush && !( pb->brush_faces->texdef.contents & CONTENTS_DETAIL ))
152                 {
153                         return TRUE;
154                 }
155         }
156
157         // if brush belongs to world entity or a brushmodel entity and is not a patch
158         if ( ( strcmp(pb->owner->eclass->name, "worldspawn") == 0
159                 || !strncmp( pb->owner->eclass->name, "func", 4)
160                 || !strncmp( pb->owner->eclass->name, "trigger", 7) ) && !pb->patchBrush )
161         {
162                 bool filterbrush = false;
163                 for (face_t *f=pb->brush_faces;f!=NULL;f = f->next)
164                 {
165                         filterbrush=false;
166                         for (bfilter_t *filters = g_qeglobals.d_savedinfo.filters;
167                         filters != NULL;
168                         filters = filters->next)
169                         {
170                                 if (!filters->active)
171                                         continue;
172                                 // exclude by attribute 1 brush->face->pShader->getName()
173                                 if (filters->attribute == 1)
174                                 {
175                                         if (strstr(f->pShader->getName(),filters->string))
176                                         {
177                                                 filterbrush=true;
178                                                 break;
179                                         }
180                                 }
181                                 // exclude by attribute 2 brush->face->pShader->getFlags()
182                                 else if (filters->attribute == 2)
183                                 {
184                                         if (f->pShader->getFlags() & filters->mask)
185                                         {
186                                                 filterbrush=true;
187                                                 break;
188                                         }
189                                 // quake2 - 5 == surface flags, 6 == content flags
190                                 }
191                                 else if (filters->attribute == 5)
192                                 {
193                                         if (f->texdef.flags && f->texdef.flags & filters->mask)
194                                         {
195                                                 filterbrush=true;
196                                                 break;
197                                         }
198                                 }
199                                 else if (filters->attribute == 6)
200                                 {
201                                         if (f->texdef.contents && f->texdef.contents & filters->mask)
202                                         {
203                                                 filterbrush=true;
204                                                 break;
205                                         }
206                                 }
207                                 else if (filters->attribute == 7)
208                                 {
209                                         if (f->texdef.contents && !(f->texdef.contents & filters->mask))
210                                         {
211                                                 filterbrush=true;
212                                                 break;
213                                         }
214                                 }
215                         }
216                         if (!filterbrush)
217                                 break;
218                 }
219                 if (filterbrush)// if no face is found that should not be excluded
220                         return true; // exclude this brush
221         }
222
223         // if brush is a patch
224         if ( pb->patchBrush )
225         {
226                 bool drawpatch=true;
227                 for (bfilter_t *filters = g_qeglobals.d_savedinfo.filters;
228                 filters != NULL;
229                 filters = filters->next)
230                 {
231                         // exclude by attribute 1 (for patch) brush->pPatch->pShader->getName()
232                         if (filters->active
233                                 && filters->attribute == 1)
234                         {
235                                 if (strstr(pb->pPatch->pShader->getName(),filters->string))
236                                 {
237                                         drawpatch=false;
238                                         break;
239                                 }
240                         }
241
242                         // exclude by attribute 2 (for patch) brush->pPatch->pShader->getFlags()
243                         if (filters->active
244                                 && filters->attribute == 2)
245                         {
246                                 if (pb->pPatch->pShader->getFlags() & filters->mask)
247                                 {
248                                         drawpatch=false;
249                                         break;
250                                 }
251                         }
252                 }
253                 if (!drawpatch) // if a shader is found that should be excluded
254                         return TRUE; // exclude this patch
255         }
256
257         if (strcmp(pb->owner->eclass->name, "worldspawn") != 0) // if brush does not belong to world entity
258         {
259                 bool drawentity=true;
260                 for (bfilter_t *filters = g_qeglobals.d_savedinfo.filters;
261                 filters != NULL;
262                 filters = filters->next)
263                 {
264                         // exclude by attribute 3 brush->owner->eclass->name
265                         if (filters->active
266                                 && filters->attribute == 3)
267                         {
268                                 if (strstr(pb->owner->eclass->name,filters->string))
269                                 {
270                                         drawentity=false;
271                                         break;
272                                 }
273                         }
274
275                         // exclude by attribute 4 brush->owner->eclass->nShowFlags
276                         else if (filters->active
277                                 && filters->attribute == 4)
278                         {
279                                 if ( pb->owner->eclass->nShowFlags & filters->mask )
280                                 {
281                                         drawentity=false;
282                                         break;
283                                 }
284                         }
285                 }
286                 if (!drawentity) // if an eclass property is found that should be excluded
287                         return TRUE; // exclude this brush
288         }
289         return FALSE;
290 }