Winding.h (12339B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition 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 BFG Edition 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 #ifndef __WINDING_H__ 30 #define __WINDING_H__ 31 32 /* 33 =============================================================================== 34 35 A winding is an arbitrary convex polygon defined by an array of points. 36 37 =============================================================================== 38 */ 39 40 class idWinding { 41 42 public: 43 idWinding(); 44 explicit idWinding( const int n ); // allocate for n points 45 explicit idWinding( const idVec3 *verts, const int n ); // winding from points 46 explicit idWinding( const idVec3 &normal, const float dist ); // base winding for plane 47 explicit idWinding( const idPlane &plane ); // base winding for plane 48 explicit idWinding( const idWinding &winding ); 49 virtual ~idWinding(); 50 51 idWinding & operator=( const idWinding &winding ); 52 const idVec5 & operator[]( const int index ) const; 53 idVec5 & operator[]( const int index ); 54 55 // add a point to the end of the winding point array 56 idWinding & operator+=( const idVec3 &v ); 57 idWinding & operator+=( const idVec5 &v ); 58 void AddPoint( const idVec3 &v ); 59 void AddPoint( const idVec5 &v ); 60 61 // number of points on winding 62 int GetNumPoints() const; 63 void SetNumPoints( int n ); 64 virtual void Clear(); 65 66 // huge winding for plane, the points go counter clockwise when facing the front of the plane 67 void BaseForPlane( const idVec3 &normal, const float dist ); 68 void BaseForPlane( const idPlane &plane ); 69 70 // splits the winding into a front and back winding, the winding itself stays unchanged 71 // returns a SIDE_? 72 int Split( const idPlane &plane, const float epsilon, idWinding **front, idWinding **back ) const; 73 // returns the winding fragment at the front of the clipping plane, 74 // if there is nothing at the front the winding itself is destroyed and NULL is returned 75 idWinding * Clip( const idPlane &plane, const float epsilon = ON_EPSILON, const bool keepOn = false ); 76 // cuts off the part at the back side of the plane, returns true if some part was at the front 77 // if there is nothing at the front the number of points is set to zero 78 bool ClipInPlace( const idPlane &plane, const float epsilon = ON_EPSILON, const bool keepOn = false ); 79 80 // returns a copy of the winding 81 idWinding * Copy() const; 82 idWinding * Reverse() const; 83 void ReverseSelf(); 84 void RemoveEqualPoints( const float epsilon = ON_EPSILON ); 85 void RemoveColinearPoints( const idVec3 &normal, const float epsilon = ON_EPSILON ); 86 void RemovePoint( int point ); 87 void InsertPoint( const idVec5 &point, int spot ); 88 bool InsertPointIfOnEdge( const idVec5 &point, const idPlane &plane, const float epsilon = ON_EPSILON ); 89 // add a winding to the convex hull 90 void AddToConvexHull( const idWinding *winding, const idVec3 &normal, const float epsilon = ON_EPSILON ); 91 // add a point to the convex hull 92 void AddToConvexHull( const idVec3 &point, const idVec3 &normal, const float epsilon = ON_EPSILON ); 93 // tries to merge 'this' with the given winding, returns NULL if merge fails, both 'this' and 'w' stay intact 94 // 'keep' tells if the contacting points should stay even if they create colinear edges 95 idWinding * TryMerge( const idWinding &w, const idVec3 &normal, int keep = false ) const; 96 // check whether the winding is valid or not 97 bool Check( bool print = true ) const; 98 99 float GetArea() const; 100 idVec3 GetCenter() const; 101 float GetRadius( const idVec3 ¢er ) const; 102 void GetPlane( idVec3 &normal, float &dist ) const; 103 void GetPlane( idPlane &plane ) const; 104 void GetBounds( idBounds &bounds ) const; 105 106 bool IsTiny() const; 107 bool IsHuge() const; // base winding for a plane is typically huge 108 void Print() const; 109 110 float PlaneDistance( const idPlane &plane ) const; 111 int PlaneSide( const idPlane &plane, const float epsilon = ON_EPSILON ) const; 112 113 bool PlanesConcave( const idWinding &w2, const idVec3 &normal1, const idVec3 &normal2, float dist1, float dist2 ) const; 114 115 bool PointInside( const idVec3 &normal, const idVec3 &point, const float epsilon ) const; 116 // returns true if the line or ray intersects the winding 117 bool LineIntersection( const idPlane &windingPlane, const idVec3 &start, const idVec3 &end, bool backFaceCull = false ) const; 118 // intersection point is start + dir * scale 119 bool RayIntersection( const idPlane &windingPlane, const idVec3 &start, const idVec3 &dir, float &scale, bool backFaceCull = false ) const; 120 121 static float TriangleArea( const idVec3 &a, const idVec3 &b, const idVec3 &c ); 122 123 protected: 124 int numPoints; // number of points 125 idVec5 * p; // pointer to point data 126 int allocedSize; 127 128 bool EnsureAlloced( int n, bool keep = false ); 129 virtual bool ReAllocate( int n, bool keep = false ); 130 }; 131 132 ID_INLINE idWinding::idWinding() { 133 numPoints = allocedSize = 0; 134 p = NULL; 135 } 136 137 ID_INLINE idWinding::idWinding( int n ) { 138 numPoints = allocedSize = 0; 139 p = NULL; 140 EnsureAlloced( n ); 141 } 142 143 ID_INLINE idWinding::idWinding( const idVec3 *verts, const int n ) { 144 int i; 145 146 numPoints = allocedSize = 0; 147 p = NULL; 148 if ( !EnsureAlloced( n ) ) { 149 numPoints = 0; 150 return; 151 } 152 for ( i = 0; i < n; i++ ) { 153 p[i].ToVec3() = verts[i]; 154 p[i].s = p[i].t = 0.0f; 155 } 156 numPoints = n; 157 } 158 159 ID_INLINE idWinding::idWinding( const idVec3 &normal, const float dist ) { 160 numPoints = allocedSize = 0; 161 p = NULL; 162 BaseForPlane( normal, dist ); 163 } 164 165 ID_INLINE idWinding::idWinding( const idPlane &plane ) { 166 numPoints = allocedSize = 0; 167 p = NULL; 168 BaseForPlane( plane ); 169 } 170 171 ID_INLINE idWinding::idWinding( const idWinding &winding ) { 172 int i; 173 if ( !EnsureAlloced( winding.GetNumPoints() ) ) { 174 numPoints = 0; 175 return; 176 } 177 for ( i = 0; i < winding.GetNumPoints(); i++ ) { 178 p[i] = winding[i]; 179 } 180 numPoints = winding.GetNumPoints(); 181 } 182 183 ID_INLINE idWinding::~idWinding() { 184 delete[] p; 185 p = NULL; 186 } 187 188 ID_INLINE idWinding &idWinding::operator=( const idWinding &winding ) { 189 int i; 190 191 if ( !EnsureAlloced( winding.numPoints ) ) { 192 numPoints = 0; 193 return *this; 194 } 195 for ( i = 0; i < winding.numPoints; i++ ) { 196 p[i] = winding.p[i]; 197 } 198 numPoints = winding.numPoints; 199 return *this; 200 } 201 202 ID_INLINE const idVec5 &idWinding::operator[]( const int index ) const { 203 //assert( index >= 0 && index < numPoints ); 204 return p[ index ]; 205 } 206 207 ID_INLINE idVec5 &idWinding::operator[]( const int index ) { 208 //assert( index >= 0 && index < numPoints ); 209 return p[ index ]; 210 } 211 212 ID_INLINE idWinding &idWinding::operator+=( const idVec3 &v ) { 213 AddPoint( v ); 214 return *this; 215 } 216 217 ID_INLINE idWinding &idWinding::operator+=( const idVec5 &v ) { 218 AddPoint( v ); 219 return *this; 220 } 221 222 ID_INLINE void idWinding::AddPoint( const idVec3 &v ) { 223 if ( !EnsureAlloced(numPoints+1, true) ) { 224 return; 225 } 226 p[numPoints] = v; 227 numPoints++; 228 } 229 230 ID_INLINE void idWinding::AddPoint( const idVec5 &v ) { 231 if ( !EnsureAlloced(numPoints+1, true) ) { 232 return; 233 } 234 p[numPoints] = v; 235 numPoints++; 236 } 237 238 ID_INLINE int idWinding::GetNumPoints() const { 239 return numPoints; 240 } 241 242 ID_INLINE void idWinding::SetNumPoints( int n ) { 243 if ( !EnsureAlloced( n, true ) ) { 244 return; 245 } 246 numPoints = n; 247 } 248 249 ID_INLINE void idWinding::Clear() { 250 numPoints = 0; 251 delete[] p; 252 p = NULL; 253 } 254 255 ID_INLINE void idWinding::BaseForPlane( const idPlane &plane ) { 256 BaseForPlane( plane.Normal(), plane.Dist() ); 257 } 258 259 ID_INLINE bool idWinding::EnsureAlloced( int n, bool keep ) { 260 if ( n > allocedSize ) { 261 return ReAllocate( n, keep ); 262 } 263 return true; 264 } 265 266 267 /* 268 =============================================================================== 269 270 idFixedWinding is a fixed buffer size winding not using 271 memory allocations. 272 273 When an operation would overflow the fixed buffer a warning 274 is printed and the operation is safely cancelled. 275 276 =============================================================================== 277 */ 278 279 #define MAX_POINTS_ON_WINDING 64 280 281 class idFixedWinding : public idWinding { 282 283 public: 284 idFixedWinding(); 285 explicit idFixedWinding( const int n ); 286 explicit idFixedWinding( const idVec3 *verts, const int n ); 287 explicit idFixedWinding( const idVec3 &normal, const float dist ); 288 explicit idFixedWinding( const idPlane &plane ); 289 explicit idFixedWinding( const idWinding &winding ); 290 explicit idFixedWinding( const idFixedWinding &winding ); 291 virtual ~idFixedWinding(); 292 293 idFixedWinding &operator=( const idWinding &winding ); 294 295 virtual void Clear(); 296 297 // splits the winding in a back and front part, 'this' becomes the front part 298 // returns a SIDE_? 299 int Split( idFixedWinding *back, const idPlane &plane, const float epsilon = ON_EPSILON ); 300 301 protected: 302 idVec5 data[MAX_POINTS_ON_WINDING]; // point data 303 304 virtual bool ReAllocate( int n, bool keep = false ); 305 }; 306 307 ID_INLINE idFixedWinding::idFixedWinding() { 308 numPoints = 0; 309 p = data; 310 allocedSize = MAX_POINTS_ON_WINDING; 311 } 312 313 ID_INLINE idFixedWinding::idFixedWinding( int n ) { 314 numPoints = 0; 315 p = data; 316 allocedSize = MAX_POINTS_ON_WINDING; 317 } 318 319 ID_INLINE idFixedWinding::idFixedWinding( const idVec3 *verts, const int n ) { 320 int i; 321 322 numPoints = 0; 323 p = data; 324 allocedSize = MAX_POINTS_ON_WINDING; 325 if ( !EnsureAlloced( n ) ) { 326 numPoints = 0; 327 return; 328 } 329 for ( i = 0; i < n; i++ ) { 330 p[i].ToVec3() = verts[i]; 331 p[i].s = p[i].t = 0; 332 } 333 numPoints = n; 334 } 335 336 ID_INLINE idFixedWinding::idFixedWinding( const idVec3 &normal, const float dist ) { 337 numPoints = 0; 338 p = data; 339 allocedSize = MAX_POINTS_ON_WINDING; 340 BaseForPlane( normal, dist ); 341 } 342 343 ID_INLINE idFixedWinding::idFixedWinding( const idPlane &plane ) { 344 numPoints = 0; 345 p = data; 346 allocedSize = MAX_POINTS_ON_WINDING; 347 BaseForPlane( plane ); 348 } 349 350 ID_INLINE idFixedWinding::idFixedWinding( const idWinding &winding ) { 351 int i; 352 353 p = data; 354 allocedSize = MAX_POINTS_ON_WINDING; 355 if ( !EnsureAlloced( winding.GetNumPoints() ) ) { 356 numPoints = 0; 357 return; 358 } 359 for ( i = 0; i < winding.GetNumPoints(); i++ ) { 360 p[i] = winding[i]; 361 } 362 numPoints = winding.GetNumPoints(); 363 } 364 365 ID_INLINE idFixedWinding::idFixedWinding( const idFixedWinding &winding ) { 366 int i; 367 368 p = data; 369 allocedSize = MAX_POINTS_ON_WINDING; 370 if ( !EnsureAlloced( winding.GetNumPoints() ) ) { 371 numPoints = 0; 372 return; 373 } 374 for ( i = 0; i < winding.GetNumPoints(); i++ ) { 375 p[i] = winding[i]; 376 } 377 numPoints = winding.GetNumPoints(); 378 } 379 380 ID_INLINE idFixedWinding::~idFixedWinding() { 381 p = NULL; // otherwise it tries to free the fixed buffer 382 } 383 384 ID_INLINE idFixedWinding &idFixedWinding::operator=( const idWinding &winding ) { 385 int i; 386 387 if ( !EnsureAlloced( winding.GetNumPoints() ) ) { 388 numPoints = 0; 389 return *this; 390 } 391 for ( i = 0; i < winding.GetNumPoints(); i++ ) { 392 p[i] = winding[i]; 393 } 394 numPoints = winding.GetNumPoints(); 395 return *this; 396 } 397 398 ID_INLINE void idFixedWinding::Clear() { 399 numPoints = 0; 400 } 401 #endif /* !__WINDING_H__ */