doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
AASBuild_ledge.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 #define LEDGE_EPSILON 0.1f
35 
36 //===============================================================
37 //
38 // idLedge
39 //
40 //===============================================================
41 
42 /*
43 ============
44 idLedge::idLedge
45 ============
46 */
48 }
49 
50 /*
51 ============
52 idLedge::idLedge
53 ============
54 */
55 idLedge::idLedge( const idVec3 &v1, const idVec3 &v2, const idVec3 &gravityDir, idBrushBSPNode *n ) {
56  start = v1;
57  end = v2;
58  node = n;
59  numPlanes = 4;
60  planes[0].SetNormal( (v1 - v2).Cross( gravityDir ) );
61  planes[0].Normalize();
62  planes[0].FitThroughPoint( v1 );
63  planes[1].SetNormal( (v1 - v2).Cross( planes[0].Normal() ) );
64  planes[1].Normalize();
65  planes[1].FitThroughPoint( v1 );
66  planes[2].SetNormal( v1 - v2 );
67  planes[2].Normalize();
68  planes[2].FitThroughPoint( v1 );
69  planes[3].SetNormal( v2 - v1 );
70  planes[3].Normalize();
71  planes[3].FitThroughPoint( v2 );
72 }
73 
74 /*
75 ============
76 idLedge::AddPoint
77 ============
78 */
79 void idLedge::AddPoint( const idVec3 &v ) {
80  if ( planes[2].Distance( v ) > 0.0f ) {
81  start = v;
83  }
84  if ( planes[3].Distance( v ) > 0.0f ) {
85  end = v;
87  }
88 }
89 
90 /*
91 ============
92 idLedge::CreateBevels
93 
94  NOTE: this assumes the gravity is vertical
95 ============
96 */
97 void idLedge::CreateBevels( const idVec3 &gravityDir ) {
98  int i, j;
99  idBounds bounds;
100  idVec3 size, normal;
101 
102  bounds.Clear();
103  bounds.AddPoint( start );
104  bounds.AddPoint( end );
105  size = bounds[1] - bounds[0];
106 
107  // plane through ledge
108  planes[0].SetNormal( (start - end).Cross( gravityDir ) );
109  planes[0].Normalize();
111  // axial bevels at start and end point
112  i = size[1] > size[0];
113  normal = vec3_origin;
114  normal[i] = 1.0f;
115  j = end[i] > start[i];
116  planes[1+j].SetNormal( normal );
117  planes[1+!j].SetNormal( -normal );
118  planes[1].FitThroughPoint( start );
119  planes[2].FitThroughPoint( end );
120  numExpandedPlanes = 3;
121  // if additional bevels are required
122  if ( idMath::Fabs( size[!i] ) > 0.01f ) {
123  normal = vec3_origin;
124  normal[!i] = 1.0f;
125  j = end[!i] > start[!i];
126  planes[3+j].SetNormal( normal );
127  planes[3+!j].SetNormal( -normal );
128  planes[3].FitThroughPoint( start );
129  planes[4].FitThroughPoint( end );
130  numExpandedPlanes = 5;
131  }
132  // opposite of first
134  // number of planes used for splitting
136  // top plane
137  planes[numSplitPlanes+0].SetNormal( (start - end).Cross( planes[0].Normal() ) );
140  // bottom plane
142  // total number of planes
144 }
145 
146 /*
147 ============
148 idLedge::Expand
149 ============
150 */
151 void idLedge::Expand( const idBounds &bounds, float maxStepHeight ) {
152  int i, j;
153  idVec3 v;
154 
155  for ( i = 0; i < numExpandedPlanes; i++ ) {
156 
157  for ( j = 0; j < 3; j++ ) {
158  if ( planes[i].Normal()[j] > 0.0f ) {
159  v[j] = bounds[0][j];
160  }
161  else {
162  v[j] = bounds[1][j];
163  }
164  }
165 
166  planes[i].SetDist( planes[i].Dist() + v * -planes[i].Normal() );
167  }
168 
169  planes[numSplitPlanes+0].SetDist( planes[numSplitPlanes+0].Dist() + maxStepHeight );
170  planes[numSplitPlanes+1].SetDist( planes[numSplitPlanes+1].Dist() + 1.0f );
171 }
172 
173 /*
174 ============
175 idLedge::ChopWinding
176 ============
177 */
178 idWinding *idLedge::ChopWinding( const idWinding *winding ) const {
179  int i;
180  idWinding *w;
181 
182  w = winding->Copy();
183  for ( i = 0; i < numPlanes && w; i++ ) {
184  w = w->Clip( -planes[i], ON_EPSILON, true );
185  }
186  return w;
187 }
188 
189 /*
190 ============
191 idLedge::PointBetweenBounds
192 ============
193 */
194 bool idLedge::PointBetweenBounds( const idVec3 &v ) const {
195  return ( planes[2].Distance( v ) < LEDGE_EPSILON ) && ( planes[3].Distance( v ) < LEDGE_EPSILON );
196 }
197 
198 
199 //===============================================================
200 //
201 // idAASBuild
202 //
203 //===============================================================
204 
205 /*
206 ============
207 idAASBuild::LedgeSubdivFlood_r
208 ============
209 */
211  int s1, i;
212  idBrushBSPPortal *p1;
213  idWinding *w;
214  idList<idBrushBSPNode *> nodeList;
215 
216  if ( node->GetFlags() & NODE_VISITED ) {
217  return;
218  }
219 
220  // if this is not already a ledge area
221  if ( !( node->GetFlags() & AREA_LEDGE ) ) {
222  for ( p1 = node->GetPortals(); p1; p1 = p1->Next(s1) ) {
223  s1 = (p1->GetNode(1) == node);
224 
225  if ( !(p1->GetFlags() & FACE_FLOOR) ) {
226  continue;
227  }
228 
229  // split the area if some part of the floor portal is inside the expanded ledge
230  w = ledge->ChopWinding( p1->GetWinding() );
231  if ( !w ) {
232  continue;
233  }
234  delete w;
235 
236  for ( i = 0; i < ledge->numSplitPlanes; i++ ) {
237  if ( node->PlaneSide( ledge->planes[i], 0.1f ) != SIDE_CROSS ) {
238  continue;
239  }
240  if ( !node->Split( ledge->planes[i], -1 ) ) {
241  continue;
242  }
245  node->GetChild(0)->SetFlag( NODE_VISITED );
246  LedgeSubdivFlood_r( node->GetChild(1), ledge );
247  return;
248  }
249 
250  node->SetFlag( AREA_LEDGE );
251  break;
252  }
253  }
254 
255  node->SetFlag( NODE_VISITED );
256 
257  // get all nodes we might need to flood into
258  for ( p1 = node->GetPortals(); p1; p1 = p1->Next(s1) ) {
259  s1 = (p1->GetNode(1) == node);
260 
261  if ( p1->GetNode( !s1 )->GetContents() & AREACONTENTS_SOLID ) {
262  continue;
263  }
264 
265  // flood through this portal if the portal is partly inside the expanded ledge
266  w = ledge->ChopWinding( p1->GetWinding() );
267  if ( !w ) {
268  continue;
269  }
270  delete w;
271  // add to list, cannot flood directly cause portals might be split on the way
272  nodeList.Append( p1->GetNode( !s1 ) );
273  }
274 
275  // flood into other nodes
276  for ( i = 0; i < nodeList.Num(); i++ ) {
277  LedgeSubdivLeafNodes_r( nodeList[i], ledge );
278  }
279 }
280 
281 /*
282 ============
283 idAASBuild::LedgeSubdivLeafNodes_r
284 
285  The node the ledge was originally part of might be split by other ledges.
286  Here we recurse down the tree from the original node to find all the new leaf nodes the ledge might be part of.
287 ============
288 */
290  if ( !node ) {
291  return;
292  }
293  if ( !node->GetChild(0) && !node->GetChild(1) ) {
294  LedgeSubdivFlood_r( node, ledge );
295  return;
296  }
297  LedgeSubdivLeafNodes_r( node->GetChild(0), ledge );
298  LedgeSubdivLeafNodes_r( node->GetChild(1), ledge );
299 }
300 
301 /*
302 ============
303 idAASBuild::LedgeSubdiv
304 ============
305 */
307  int i, j;
308  idBrush *brush;
309  idList<idBrushSide *> sideList;
310 
311  // create ledge bevels and expand ledges
312  for ( i = 0; i < ledgeList.Num(); i++ ) {
313 
314  ledgeList[i].CreateBevels( aasSettings->gravityDir );
316 
317  // if we should write out a ledge map
318  if ( ledgeMap ) {
319  sideList.SetNum( 0 );
320  for ( j = 0; j < ledgeList[i].numPlanes; j++ ) {
321  sideList.Append( new idBrushSide( ledgeList[i].planes[j], -1 ) );
322  }
323 
324  brush = new idBrush();
325  brush->FromSides( sideList );
326 
327  ledgeMap->WriteBrush( brush );
328 
329  delete brush;
330  }
331 
332  // flood tree from the ledge node and subdivide areas with the ledge
334 
335  // remove the node visited flags
336  ledgeList[i].node->RemoveFlagRecurseFlood( NODE_VISITED );
337  }
338 }
339 
340 /*
341 ============
342 idAASBuild::IsLedgeSide_r
343 ============
344 */
345 bool idAASBuild::IsLedgeSide_r( idBrushBSPNode *node, idFixedWinding *w, const idPlane &plane, const idVec3 &normal, const idVec3 &origin, const float radius ) {
346  int res, i;
347  idFixedWinding back;
348  float dist;
349 
350  if ( !node ) {
351  return false;
352  }
353 
354  while ( node->GetChild(0) && node->GetChild(1) ) {
355  dist = node->GetPlane().Distance( origin );
356  if ( dist > radius ) {
357  res = SIDE_FRONT;
358  }
359  else if ( dist < -radius ) {
360  res = SIDE_BACK;
361  }
362  else {
363  res = w->Split( &back, node->GetPlane(), LEDGE_EPSILON );
364  }
365  if ( res == SIDE_FRONT ) {
366  node = node->GetChild(0);
367  }
368  else if ( res == SIDE_BACK ) {
369  node = node->GetChild(1);
370  }
371  else if ( res == SIDE_ON ) {
372  // continue with the side the winding faces
373  if ( node->GetPlane().Normal() * normal > 0.0f ) {
374  node = node->GetChild(0);
375  }
376  else {
377  node = node->GetChild(1);
378  }
379  }
380  else {
381  if ( IsLedgeSide_r( node->GetChild(1), &back, plane, normal, origin, radius ) ) {
382  return true;
383  }
384  node = node->GetChild(0);
385  }
386  }
387 
388  if ( node->GetContents() & AREACONTENTS_SOLID ) {
389  return false;
390  }
391 
392  for ( i = 0; i < w->GetNumPoints(); i++ ) {
393  if ( plane.Distance( (*w)[i].ToVec3() ) > 0.0f ) {
394  return true;
395  }
396  }
397 
398  return false;
399 }
400 
401 /*
402 ============
403 idAASBuild::AddLedge
404 ============
405 */
406 void idAASBuild::AddLedge( const idVec3 &v1, const idVec3 &v2, idBrushBSPNode *node ) {
407  int i, j, merged;
408 
409  // first try to merge the ledge with existing ledges
410  merged = -1;
411  for ( i = 0; i < ledgeList.Num(); i++ ) {
412 
413  for ( j = 0; j < 2; j++ ) {
414  if ( idMath::Fabs( ledgeList[i].planes[j].Distance( v1 ) ) > LEDGE_EPSILON ) {
415  break;
416  }
417  if ( idMath::Fabs( ledgeList[i].planes[j].Distance( v2 ) ) > LEDGE_EPSILON ) {
418  break;
419  }
420  }
421  if ( j < 2 ) {
422  continue;
423  }
424 
425  if ( !ledgeList[i].PointBetweenBounds( v1 ) &&
426  !ledgeList[i].PointBetweenBounds( v2 ) ) {
427  continue;
428  }
429 
430  if ( merged == -1 ) {
431  ledgeList[i].AddPoint( v1 );
432  ledgeList[i].AddPoint( v2 );
433  merged = i;
434  }
435  else {
436  ledgeList[merged].AddPoint( ledgeList[i].start );
437  ledgeList[merged].AddPoint( ledgeList[i].end );
439  break;
440  }
441  }
442 
443  // if the ledge could not be merged
444  if ( merged == -1 ) {
445  ledgeList.Append( idLedge( v1, v2, aasSettings->gravityDir, node ) );
446  }
447 }
448 
449 /*
450 ============
451 idAASBuild::FindLeafNodeLedges
452 ============
453 */
455  int s1, i;
456  idBrushBSPPortal *p1;
457  idWinding *w;
458  idVec3 v1, v2, normal, origin;
459  idFixedWinding winding;
460  idBounds bounds;
461  idPlane plane;
462  float radius;
463 
464  for ( p1 = node->GetPortals(); p1; p1 = p1->Next(s1) ) {
465  s1 = (p1->GetNode(1) == node);
466 
467  if ( !(p1->GetFlags() & FACE_FLOOR) ) {
468  continue;
469  }
470 
471  if ( s1 ) {
472  plane = p1->GetPlane();
473  w = p1->GetWinding()->Reverse();
474  }
475  else {
476  plane = -p1->GetPlane();
477  w = p1->GetWinding();
478  }
479 
480  for ( i = 0; i < w->GetNumPoints(); i++ ) {
481 
482  v1 = (*w)[i].ToVec3();
483  v2 = (*w)[(i+1)%w->GetNumPoints()].ToVec3();
484  normal = (v2 - v1).Cross( aasSettings->gravityDir );
485  if ( normal.Normalize() < 0.5f ) {
486  continue;
487  }
488 
489  winding.Clear();
490  winding += v1 + normal * LEDGE_EPSILON * 0.5f;
491  winding += v2 + normal * LEDGE_EPSILON * 0.5f;
492  winding += winding[1].ToVec3() + ( aasSettings->maxStepHeight + 1.0f ) * aasSettings->gravityDir;
493  winding += winding[0].ToVec3() + ( aasSettings->maxStepHeight + 1.0f ) * aasSettings->gravityDir;
494 
495  winding.GetBounds( bounds );
496  origin = (bounds[1] - bounds[0]) * 0.5f;
497  radius = origin.Length() + LEDGE_EPSILON;
498  origin = bounds[0] + origin;
499 
501 
502  if ( !IsLedgeSide_r( root, &winding, plane, normal, origin, radius ) ) {
503  continue;
504  }
505 
506  AddLedge( v1, v2, node );
507  }
508 
509  if ( w != p1->GetWinding() ) {
510  delete w;
511  }
512  }
513 }
514 
515 /*
516 ============
517 idAASBuild::FindLedges_r
518 ============
519 */
521  if ( !node ) {
522  return;
523  }
524 
525  if ( node->GetContents() & AREACONTENTS_SOLID ) {
526  return;
527  }
528 
529  if ( !node->GetChild(0) && !node->GetChild(1) ) {
530  if ( node->GetFlags() & NODE_VISITED ) {
531  return;
532  }
533  FindLeafNodeLedges( root, node );
534  node->SetFlag( NODE_VISITED );
535  return;
536  }
537 
538  FindLedges_r( root, node->GetChild(0) );
539  FindLedges_r( root, node->GetChild(1) );
540 }
541 
542 /*
543 ============
544 idAASBuild::WriteLedgeMap
545 ============
546 */
547 void idAASBuild::WriteLedgeMap( const idStr &fileName, const idStr &ext ) {
548  ledgeMap = new idBrushMap( fileName, ext );
549  ledgeMap->SetTexture( "textures/base_trim/bluetex4q_ed" );
550 }
551 
552 /*
553 ============
554 idAASBuild::LedgeSubdivision
555 
556  NOTE: this assumes the bounding box is higher than the maximum step height
557  only ledges with vertical sides are considered
558 ============
559 */
562  ledgeList.Clear();
563 
564  common->Printf( "[Ledge Subdivision]\n" );
565 
567  FindLedges_r( bsp.GetRootNode(), bsp.GetRootNode() );
569 
570  common->Printf( "\r%6d ledges\n", ledgeList.Num() );
571 
572  LedgeSubdiv( bsp.GetRootNode() );
573 
574  common->Printf( "\r%6d subdivisions\n", numLedgeSubdivisions );
575 }
idPlane planes[8]
void GetBounds(idBounds &bounds) const
Definition: Winding.cpp:700
void CreateBevels(const idVec3 &gravityDir)
float Normalize(void)
Definition: Vector.h:646
const idVec3 & Normal(void) const
Definition: Plane.h:239
idLedge(void)
#define SIDE_CROSS
Definition: Plane.h:50
idWinding * ChopWinding(const idWinding *winding) const
int GetContents(void) const
Definition: BrushBSP.h:106
void AddLedge(const idVec3 &v1, const idVec3 &v2, idBrushBSPNode *node)
const GLdouble * v
Definition: glext.h:2936
float maxStepHeight
Definition: AASFile.h:228
void SetNum(int newnum, bool resize=true)
Definition: List.h:289
#define SIDE_BACK
Definition: Plane.h:48
float Distance(const idVec3 &v) const
Definition: Plane.h:324
#define LEDGE_EPSILON
GLenum GLsizei n
Definition: glext.h:3705
const idPlane & GetPlane(void) const
Definition: BrushBSP.h:64
const idPlane & GetPlane(void) const
Definition: BrushBSP.h:107
Definition: Vector.h:316
#define AREACONTENTS_SOLID
Definition: AASFile.h:78
int numPlanes
int PlaneSide(const idPlane &plane, float epsilon=ON_EPSILON) const
Definition: BrushBSP.cpp:399
void Clear(void)
Definition: Bounds.h:201
idWinding * Reverse(void) const
Definition: Winding.cpp:478
void LedgeSubdivision(idBrushBSP &bsp)
void SetNormal(const idVec3 &normal)
Definition: Plane.h:233
idWinding * Clip(const idPlane &plane, const float epsilon=ON_EPSILON, const bool keepOn=false)
Definition: Winding.cpp:234
void FindLeafNodeLedges(idBrushBSPNode *root, idBrushBSPNode *node)
idBounds boundingBoxes[MAX_AAS_BOUNDING_BOXES]
Definition: AASFile.h:215
int i
Definition: process.py:33
int GetFlags(void) const
Definition: BrushBSP.h:111
idVec3 gravityDir
Definition: AASFile.h:225
int Split(idFixedWinding *back, const idPlane &plane, const float epsilon=ON_EPSILON)
Definition: Winding.cpp:1484
idBrushBSPNode * GetRootNode(void) const
Definition: BrushBSP.h:176
void RemoveFlagRecurse(int flag)
Definition: BrushBSP.cpp:459
void LedgeSubdiv(idBrushBSPNode *root)
void WriteLedgeMap(const idStr &fileName, const idStr &ext)
int numSplitPlanes
idList< idLedge > ledgeList
bool AddPoint(const idVec3 &v)
Definition: Bounds.h:226
GLfloat GLfloat GLfloat v2
Definition: glext.h:3608
int GetNumPoints(void) const
Definition: Winding.h:238
int Distance(CPoint pt1, CPoint pt2)
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:3454
float Length(void) const
Definition: Vector.h:631
void AddPoint(const idVec3 &v)
void SetDist(const float dist)
Definition: Plane.h:275
idBrushBSPNode * GetNode(int side) const
Definition: BrushBSP.h:71
idVec3 vec3_origin(0.0f, 0.0f, 0.0f)
GLuint GLuint end
Definition: glext.h:2845
static float Fabs(float f)
Definition: Math.h:779
idCommon * common
Definition: Common.cpp:206
virtual void Clear(void)
Definition: Winding.h:398
Definition: Plane.h:71
#define AREA_LEDGE
Definition: AASFile.h:70
int numLedgeSubdivisions
const idAASSettings * aasSettings
void LedgeSubdivFlood_r(idBrushBSPNode *node, const idLedge *ledge)
virtual void Printf(const char *fmt,...) id_attribute((format(printf
float Normalize(bool fixDegenerate=true)
Definition: Plane.h:247
GLfloat GLfloat v1
Definition: glext.h:3607
void SetTexture(const idStr &textureName)
Definition: Brush.h:221
int Append(const type &obj)
Definition: List.h:646
#define SIDE_ON
Definition: Plane.h:49
#define NODE_VISITED
Definition: BrushBSP.h:90
tuple f
Definition: idal.py:89
#define ON_EPSILON
Definition: Plane.h:44
idBrushBSPNode * GetChild(int index) const
Definition: BrushBSP.h:103
idBrushBSPNode * node
int Num(void) const
Definition: List.h:265
bool RemoveIndex(int index)
Definition: List.h:849
GLsizeiptr size
Definition: glext.h:3112
int numExpandedPlanes
idWinding * Copy(void) const
Definition: Winding.cpp:464
idBrushMap * ledgeMap
Definition: Str.h:116
idBrushBSPPortal * GetPortals(void) const
Definition: BrushBSP.h:108
bool PointBetweenBounds(const idVec3 &v) const
#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
GLuint res
Definition: glext.h:5385
idBrushBSPPortal * Next(int side) const
Definition: BrushBSP.h:70
void DisplayRealTimeString(char *string,...)
Definition: Brush.cpp:47
GLint j
Definition: qgl.h:264
void FindLedges_r(idBrushBSPNode *root, idBrushBSPNode *node)
void LedgeSubdivLeafNodes_r(idBrushBSPNode *node, const idLedge *ledge)
Definition: List.h:84
#define SIDE_FRONT
Definition: Plane.h:47
void WriteBrush(const idBrush *brush)
Definition: Brush.cpp:1548
void Expand(const idBounds &bounds, float maxStepHeight)
Definition: Brush.h:98
bool IsLedgeSide_r(idBrushBSPNode *node, idFixedWinding *w, const idPlane &plane, const idVec3 &normal, const idVec3 &origin, const float radius)
bool FromSides(idList< idBrushSide * > &sideList)
Definition: Brush.cpp:313
GLuint start
Definition: glext.h:2845
void FitThroughPoint(const idVec3 &p)
Definition: Plane.h:297
bool Split(const idPlane &splitPlane, int splitPlaneNum)
Definition: BrushBSP.cpp:330
void Clear(void)
Definition: List.h:184