doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
AASBuild_gravity.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 #include "../../../idlib/precompiled.h"
30 #pragma hdrstop
31 
32 #include "AASBuild_local.h"
33 
34 
35 /*
36 ============
37 idAASBuild::SetPortalFlags_r
38 ============
39 */
41  int s;
43  idVec3 normal;
44 
45  if ( !node ) {
46  return;
47  }
48 
49  if ( node->GetContents() & AREACONTENTS_SOLID ) {
50  return;
51  }
52 
53  if ( !node->GetChild(0) && !node->GetChild(1) ) {
54  for ( p = node->GetPortals(); p; p = p->Next(s) ) {
55  s = (p->GetNode(1) == node);
56 
57  // if solid at the other side of the portal
58  if ( p->GetNode(!s)->GetContents() & AREACONTENTS_SOLID ) {
59  if ( s ) {
60  normal = -p->GetPlane().Normal();
61  }
62  else {
63  normal = p->GetPlane().Normal();
64  }
65  if ( normal * aasSettings->invGravityDir > aasSettings->minFloorCos ) {
66  p->SetFlag( FACE_FLOOR );
67  }
68  else {
69  p->SetFlag( FACE_SOLID );
70  }
71  }
72  }
73  return;
74  }
75 
76  SetPortalFlags_r( node->GetChild(0) );
77  SetPortalFlags_r( node->GetChild(1) );
78 }
79 
80 /*
81 ============
82 idAASBuild::PortalIsGap
83 ============
84 */
85 bool idAASBuild::PortalIsGap( idBrushBSPPortal *portal, int side ) {
86  idVec3 normal;
87 
88  // if solid at the other side of the portal
89  if ( portal->GetNode(!side)->GetContents() & AREACONTENTS_SOLID ) {
90  return false;
91  }
92 
93  if ( side ) {
94  normal = -(portal->GetPlane().Normal());
95  }
96  else {
97  normal = portal->GetPlane().Normal();
98  }
99  if ( normal * aasSettings->invGravityDir > aasSettings->minFloorCos ) {
100  return true;
101  }
102  return false;
103 }
104 
105 /*
106 ============
107 idAASBuild::GravSubdivLeafNode
108 ============
109 */
110 #define FACE_CHECKED BIT(31)
111 #define GRAVSUBDIV_EPSILON 0.1f
112 
114  int s1, s2, i, j, k, side1;
115  int numSplits, numSplitters;
116  idBrushBSPPortal *p1, *p2;
117  idWinding *w1, *w2;
118  idVec3 normal;
119  idPlane plane;
120  idPlaneSet planeList;
121  float d, min, max;
122  int *splitterOrder;
123  int *bestNumSplits;
124  int floor, gap, numFloorChecked;
125 
126  // if this leaf node is already classified it cannot have a combination of floor and gap portals
127  if ( node->GetFlags() & (AREA_FLOOR|AREA_GAP) ) {
128  return;
129  }
130 
131  floor = gap = 0;
132 
133  // check if the area has a floor
134  for ( p1 = node->GetPortals(); p1; p1 = p1->Next(s1) ) {
135  s1 = (p1->GetNode(1) == node);
136 
137  if ( p1->GetFlags() & FACE_FLOOR ) {
138  floor++;
139  }
140  }
141 
142  // find seperating planes between gap and floor portals
143  for ( p1 = node->GetPortals(); p1; p1 = p1->Next(s1) ) {
144  s1 = (p1->GetNode(1) == node);
145 
146  // if the portal is a gap seen from this side
147  if ( PortalIsGap( p1, s1 ) ) {
148  gap++;
149  // if the area doesn't have a floor
150  if ( !floor ) {
151  break;
152  }
153  }
154  else {
155  continue;
156  }
157 
158  numFloorChecked = 0;
159 
160  w1 = p1->GetWinding();
161 
162  // test all edges of the gap
163  for ( i = 0; i < w1->GetNumPoints(); i++ ) {
164 
165  // create a plane through the edge of the gap parallel to the direction of gravity
166  normal = (*w1)[(i+1)%w1->GetNumPoints()].ToVec3() - (*w1)[i].ToVec3();
167  normal = normal.Cross( aasSettings->invGravityDir );
168  if ( normal.Normalize() < 0.2f ) {
169  continue;
170  }
171  plane.SetNormal( normal );
172  plane.FitThroughPoint( (*w1)[i].ToVec3() );
173 
174  // get the side of the plane the gap is on
175  side1 = w1->PlaneSide( plane, GRAVSUBDIV_EPSILON );
176  if ( side1 == SIDE_ON ) {
177  break;
178  }
179 
180  // test if the plane through the edge of the gap seperates the gap from a floor portal
181  for ( p2 = node->GetPortals(); p2; p2 = p2->Next(s2) ) {
182  s2 = (p2->GetNode(1) == node);
183 
184  if ( !( p2->GetFlags() & FACE_FLOOR ) ) {
185  continue;
186  }
187 
188  if ( p2->GetFlags() & FACE_CHECKED ) {
189  continue;
190  }
191 
192  w2 = p2->GetWinding();
193 
194  min = 2.0f * GRAVSUBDIV_EPSILON;
195  max = GRAVSUBDIV_EPSILON;
196  if ( side1 == SIDE_FRONT ) {
197  for ( j = 0; j < w2->GetNumPoints(); j++ ) {
198  d = plane.Distance( (*w2)[j].ToVec3() );
199  if ( d >= GRAVSUBDIV_EPSILON ) {
200  break; // point at the same side of the plane as the gap
201  }
202  d = idMath::Fabs( d );
203  if ( d < min ) {
204  min = d;
205  }
206  if ( d > max ) {
207  max = d;
208  }
209  }
210  }
211  else {
212  for ( j = 0; j < w2->GetNumPoints(); j++ ) {
213  d = plane.Distance( (*w2)[j].ToVec3() );
214  if ( d <= -GRAVSUBDIV_EPSILON ) {
215  break; // point at the same side of the plane as the gap
216  }
217  d = idMath::Fabs( d );
218  if ( d < min ) {
219  min = d;
220  }
221  if ( d > max ) {
222  max = d;
223  }
224  }
225  }
226 
227  // a point of the floor portal was found to be at the same side of the plane as the gap
228  if ( j < w2->GetNumPoints() ) {
229  continue;
230  }
231 
232  // if the floor portal touches the plane
233  if ( min < GRAVSUBDIV_EPSILON && max > GRAVSUBDIV_EPSILON ) {
234  planeList.FindPlane( plane, 0.00001f, 0.1f );
235  }
236 
237  p2->SetFlag( FACE_CHECKED );
238  numFloorChecked++;
239 
240  }
241  if ( numFloorChecked == floor ) {
242  break;
243  }
244  }
245 
246  for ( p2 = node->GetPortals(); p2; p2 = p2->Next(s2) ) {
247  s2 = (p2->GetNode(1) == node);
248  p2->RemoveFlag( FACE_CHECKED );
249  }
250  }
251 
252  // if the leaf node does not have both floor and gap portals
253  if ( !( gap && floor) ) {
254  if ( floor ) {
255  node->SetFlag( AREA_FLOOR );
256  }
257  else if ( gap ) {
258  node->SetFlag( AREA_GAP );
259  }
260  return;
261  }
262 
263  // if no valid seperators found
264  if ( planeList.Num() == 0 ) {
265  // NOTE: this should never happend, if it does the leaf node has degenerate portals
266  return;
267  }
268 
269  splitterOrder = (int *) _alloca( planeList.Num() * sizeof( int ) );
270  bestNumSplits = (int *) _alloca( planeList.Num() * sizeof( int ) );
271  numSplitters = 0;
272 
273  // test all possible seperators and sort them from best to worst
274  for ( i = 0; i < planeList.Num(); i += 2 ) {
275  numSplits = 0;
276 
277  for ( p1 = node->GetPortals(); p1; p1 = p1->Next(s1) ) {
278  s1 = (p1->GetNode(1) == node);
279  if ( p1->GetWinding()->PlaneSide( planeList[i], 0.1f ) == SIDE_CROSS ) {
280  numSplits++;
281  }
282  }
283 
284  for ( j = 0; j < numSplitters; j++ ) {
285  if ( numSplits < bestNumSplits[j] ) {
286  for ( k = numSplitters; k > j; k-- ) {
287  bestNumSplits[k] = bestNumSplits[k-1];
288  splitterOrder[k] = splitterOrder[k-1];
289  }
290  bestNumSplits[j] = numSplits;
291  splitterOrder[j] = i;
292  numSplitters++;
293  break;
294  }
295  }
296  if ( j >= numSplitters ) {
297  bestNumSplits[j] = numSplits;
298  splitterOrder[j] = i;
299  numSplitters++;
300  }
301  }
302 
303  // try all seperators in order from best to worst
304  for ( i = 0; i < numSplitters; i++ ) {
305  if ( node->Split( planeList[splitterOrder[i]], -1 ) ) {
306  // we found a seperator that works
307  break;
308  }
309  }
310  if ( i >= numSplitters) {
311  return;
312  }
313 
315 
316  // test children for further splits
317  GravSubdivLeafNode( node->GetChild(0) );
318  GravSubdivLeafNode( node->GetChild(1) );
319 }
320 
321 /*
322 ============
323 idAASBuild::GravSubdiv_r
324 ============
325 */
327 
328  if ( !node ) {
329  return;
330  }
331 
332  if ( node->GetContents() & AREACONTENTS_SOLID ) {
333  return;
334  }
335 
336  if ( !node->GetChild(0) && !node->GetChild(1) ) {
337  GravSubdivLeafNode( node );
338  return;
339  }
340 
341  GravSubdiv_r( node->GetChild(0) );
342  GravSubdiv_r( node->GetChild(1) );
343 }
344 
345 /*
346 ============
347 idAASBuild::GravitationalSubdivision
348 ============
349 */
352 
353  common->Printf( "[Gravitational Subdivision]\n" );
354 
355  SetPortalFlags_r( bsp.GetRootNode() );
356  GravSubdiv_r( bsp.GetRootNode() );
357 
358  common->Printf( "\r%6d subdivisions\n", numGravitationalSubdivisions );
359 }
#define min(a, b)
float Normalize(void)
Definition: Vector.h:646
void GravSubdiv_r(idBrushBSPNode *node)
const idVec3 & Normal(void) const
Definition: Plane.h:239
#define SIDE_CROSS
Definition: Plane.h:50
int GetContents(void) const
Definition: BrushBSP.h:106
void RemoveFlag(int flag)
Definition: BrushBSP.h:69
float Distance(const idVec3 &v) const
Definition: Plane.h:324
#define FACE_SOLID
Definition: AASFile.h:61
bool PortalIsGap(idBrushBSPPortal *portal, int side)
case const int
Definition: Callbacks.cpp:52
const idPlane & GetPlane(void) const
Definition: BrushBSP.h:64
void GravSubdivLeafNode(idBrushBSPNode *node)
Definition: Vector.h:316
#define AREACONTENTS_SOLID
Definition: AASFile.h:78
GLdouble s
Definition: glext.h:2935
void SetNormal(const idVec3 &normal)
Definition: Plane.h:233
idVec3 Cross(const idVec3 &a) const
Definition: Vector.h:619
float minFloorCos
Definition: AASFile.h:232
int i
Definition: process.py:33
int GetFlags(void) const
Definition: BrushBSP.h:111
idBrushBSPNode * GetRootNode(void) const
Definition: BrushBSP.h:176
int FindPlane(const idPlane &plane, const float normalEps, const float distEps)
Definition: PlaneSet.h:51
int PlaneSide(const idPlane &plane, const float epsilon=ON_EPSILON) const
Definition: Winding.cpp:1292
int numGravitationalSubdivisions
void SetFlag(int flag)
Definition: BrushBSP.h:68
int GetNumPoints(void) const
Definition: Winding.h:238
idBrushBSPNode * GetNode(int side) const
Definition: BrushBSP.h:71
static float Fabs(float f)
Definition: Math.h:779
idCommon * common
Definition: Common.cpp:206
#define GRAVSUBDIV_EPSILON
#define AREA_GAP
Definition: AASFile.h:69
Definition: Plane.h:71
const idAASSettings * aasSettings
virtual void Printf(const char *fmt,...) id_attribute((format(printf
GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint GLdouble GLdouble w2
Definition: glext.h:4080
void GravitationalSubdivision(idBrushBSP &bsp)
idVec3 invGravityDir
Definition: AASFile.h:226
#define SIDE_ON
Definition: Plane.h:49
#define AREA_FLOOR
Definition: AASFile.h:68
tuple f
Definition: idal.py:89
idBrushBSPNode * GetChild(int index) const
Definition: BrushBSP.h:103
int Num(void) const
Definition: List.h:265
idBrushBSPPortal * GetPortals(void) const
Definition: BrushBSP.h:108
#define FACE_FLOOR
Definition: AASFile.h:63
void SetFlag(int flag)
Definition: BrushBSP.h:112
int GetFlags(void) const
Definition: BrushBSP.h:67
idWinding * GetWinding(void) const
Definition: BrushBSP.h:63
#define FACE_CHECKED
idBrushBSPPortal * Next(int side) const
Definition: BrushBSP.h:70
void DisplayRealTimeString(char *string,...)
Definition: Brush.cpp:47
GLint j
Definition: qgl.h:264
void SetPortalFlags_r(idBrushBSPNode *node)
#define max(x, y)
Definition: os.h:70
GLfloat GLfloat p
Definition: glext.h:4674
#define SIDE_FRONT
Definition: Plane.h:47
void FitThroughPoint(const idVec3 &p)
Definition: Plane.h:297
bool Split(const idPlane &splitPlane, int splitPlaneNum)
Definition: BrushBSP.cpp:330
GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint GLdouble w1
Definition: glext.h:4080