Winding.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. 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.
  17. 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.
  18. ===========================================================================
  19. */
  20. #ifndef __WINDING_H__
  21. #define __WINDING_H__
  22. /*
  23. ===============================================================================
  24. A winding is an arbitrary convex polygon defined by an array of points.
  25. ===============================================================================
  26. */
  27. class idWinding {
  28. public:
  29. idWinding();
  30. explicit idWinding( const int n ); // allocate for n points
  31. explicit idWinding( const idVec3 *verts, const int n ); // winding from points
  32. explicit idWinding( const idVec3 &normal, const float dist ); // base winding for plane
  33. explicit idWinding( const idPlane &plane ); // base winding for plane
  34. explicit idWinding( const idWinding &winding );
  35. virtual ~idWinding();
  36. idWinding & operator=( const idWinding &winding );
  37. const idVec5 & operator[]( const int index ) const;
  38. idVec5 & operator[]( const int index );
  39. // add a point to the end of the winding point array
  40. idWinding & operator+=( const idVec3 &v );
  41. idWinding & operator+=( const idVec5 &v );
  42. void AddPoint( const idVec3 &v );
  43. void AddPoint( const idVec5 &v );
  44. // number of points on winding
  45. int GetNumPoints() const;
  46. void SetNumPoints( int n );
  47. virtual void Clear();
  48. // huge winding for plane, the points go counter clockwise when facing the front of the plane
  49. void BaseForPlane( const idVec3 &normal, const float dist );
  50. void BaseForPlane( const idPlane &plane );
  51. // splits the winding into a front and back winding, the winding itself stays unchanged
  52. // returns a SIDE_?
  53. int Split( const idPlane &plane, const float epsilon, idWinding **front, idWinding **back ) const;
  54. // returns the winding fragment at the front of the clipping plane,
  55. // if there is nothing at the front the winding itself is destroyed and NULL is returned
  56. idWinding * Clip( const idPlane &plane, const float epsilon = ON_EPSILON, const bool keepOn = false );
  57. // cuts off the part at the back side of the plane, returns true if some part was at the front
  58. // if there is nothing at the front the number of points is set to zero
  59. bool ClipInPlace( const idPlane &plane, const float epsilon = ON_EPSILON, const bool keepOn = false );
  60. // returns a copy of the winding
  61. idWinding * Copy() const;
  62. idWinding * Reverse() const;
  63. void ReverseSelf();
  64. void RemoveEqualPoints( const float epsilon = ON_EPSILON );
  65. void RemoveColinearPoints( const idVec3 &normal, const float epsilon = ON_EPSILON );
  66. void RemovePoint( int point );
  67. void InsertPoint( const idVec5 &point, int spot );
  68. bool InsertPointIfOnEdge( const idVec5 &point, const idPlane &plane, const float epsilon = ON_EPSILON );
  69. // add a winding to the convex hull
  70. void AddToConvexHull( const idWinding *winding, const idVec3 &normal, const float epsilon = ON_EPSILON );
  71. // add a point to the convex hull
  72. void AddToConvexHull( const idVec3 &point, const idVec3 &normal, const float epsilon = ON_EPSILON );
  73. // tries to merge 'this' with the given winding, returns NULL if merge fails, both 'this' and 'w' stay intact
  74. // 'keep' tells if the contacting points should stay even if they create colinear edges
  75. idWinding * TryMerge( const idWinding &w, const idVec3 &normal, int keep = false ) const;
  76. // check whether the winding is valid or not
  77. bool Check( bool print = true ) const;
  78. float GetArea() const;
  79. idVec3 GetCenter() const;
  80. float GetRadius( const idVec3 &center ) const;
  81. void GetPlane( idVec3 &normal, float &dist ) const;
  82. void GetPlane( idPlane &plane ) const;
  83. void GetBounds( idBounds &bounds ) const;
  84. bool IsTiny() const;
  85. bool IsHuge() const; // base winding for a plane is typically huge
  86. void Print() const;
  87. float PlaneDistance( const idPlane &plane ) const;
  88. int PlaneSide( const idPlane &plane, const float epsilon = ON_EPSILON ) const;
  89. bool PlanesConcave( const idWinding &w2, const idVec3 &normal1, const idVec3 &normal2, float dist1, float dist2 ) const;
  90. bool PointInside( const idVec3 &normal, const idVec3 &point, const float epsilon ) const;
  91. // returns true if the line or ray intersects the winding
  92. bool LineIntersection( const idPlane &windingPlane, const idVec3 &start, const idVec3 &end, bool backFaceCull = false ) const;
  93. // intersection point is start + dir * scale
  94. bool RayIntersection( const idPlane &windingPlane, const idVec3 &start, const idVec3 &dir, float &scale, bool backFaceCull = false ) const;
  95. static float TriangleArea( const idVec3 &a, const idVec3 &b, const idVec3 &c );
  96. protected:
  97. int numPoints; // number of points
  98. idVec5 * p; // pointer to point data
  99. int allocedSize;
  100. bool EnsureAlloced( int n, bool keep = false );
  101. virtual bool ReAllocate( int n, bool keep = false );
  102. };
  103. ID_INLINE idWinding::idWinding() {
  104. numPoints = allocedSize = 0;
  105. p = NULL;
  106. }
  107. ID_INLINE idWinding::idWinding( int n ) {
  108. numPoints = allocedSize = 0;
  109. p = NULL;
  110. EnsureAlloced( n );
  111. }
  112. ID_INLINE idWinding::idWinding( const idVec3 *verts, const int n ) {
  113. int i;
  114. numPoints = allocedSize = 0;
  115. p = NULL;
  116. if ( !EnsureAlloced( n ) ) {
  117. numPoints = 0;
  118. return;
  119. }
  120. for ( i = 0; i < n; i++ ) {
  121. p[i].ToVec3() = verts[i];
  122. p[i].s = p[i].t = 0.0f;
  123. }
  124. numPoints = n;
  125. }
  126. ID_INLINE idWinding::idWinding( const idVec3 &normal, const float dist ) {
  127. numPoints = allocedSize = 0;
  128. p = NULL;
  129. BaseForPlane( normal, dist );
  130. }
  131. ID_INLINE idWinding::idWinding( const idPlane &plane ) {
  132. numPoints = allocedSize = 0;
  133. p = NULL;
  134. BaseForPlane( plane );
  135. }
  136. ID_INLINE idWinding::idWinding( const idWinding &winding ) {
  137. int i;
  138. if ( !EnsureAlloced( winding.GetNumPoints() ) ) {
  139. numPoints = 0;
  140. return;
  141. }
  142. for ( i = 0; i < winding.GetNumPoints(); i++ ) {
  143. p[i] = winding[i];
  144. }
  145. numPoints = winding.GetNumPoints();
  146. }
  147. ID_INLINE idWinding::~idWinding() {
  148. delete[] p;
  149. p = NULL;
  150. }
  151. ID_INLINE idWinding &idWinding::operator=( const idWinding &winding ) {
  152. int i;
  153. if ( !EnsureAlloced( winding.numPoints ) ) {
  154. numPoints = 0;
  155. return *this;
  156. }
  157. for ( i = 0; i < winding.numPoints; i++ ) {
  158. p[i] = winding.p[i];
  159. }
  160. numPoints = winding.numPoints;
  161. return *this;
  162. }
  163. ID_INLINE const idVec5 &idWinding::operator[]( const int index ) const {
  164. //assert( index >= 0 && index < numPoints );
  165. return p[ index ];
  166. }
  167. ID_INLINE idVec5 &idWinding::operator[]( const int index ) {
  168. //assert( index >= 0 && index < numPoints );
  169. return p[ index ];
  170. }
  171. ID_INLINE idWinding &idWinding::operator+=( const idVec3 &v ) {
  172. AddPoint( v );
  173. return *this;
  174. }
  175. ID_INLINE idWinding &idWinding::operator+=( const idVec5 &v ) {
  176. AddPoint( v );
  177. return *this;
  178. }
  179. ID_INLINE void idWinding::AddPoint( const idVec3 &v ) {
  180. if ( !EnsureAlloced(numPoints+1, true) ) {
  181. return;
  182. }
  183. p[numPoints] = v;
  184. numPoints++;
  185. }
  186. ID_INLINE void idWinding::AddPoint( const idVec5 &v ) {
  187. if ( !EnsureAlloced(numPoints+1, true) ) {
  188. return;
  189. }
  190. p[numPoints] = v;
  191. numPoints++;
  192. }
  193. ID_INLINE int idWinding::GetNumPoints() const {
  194. return numPoints;
  195. }
  196. ID_INLINE void idWinding::SetNumPoints( int n ) {
  197. if ( !EnsureAlloced( n, true ) ) {
  198. return;
  199. }
  200. numPoints = n;
  201. }
  202. ID_INLINE void idWinding::Clear() {
  203. numPoints = 0;
  204. delete[] p;
  205. p = NULL;
  206. }
  207. ID_INLINE void idWinding::BaseForPlane( const idPlane &plane ) {
  208. BaseForPlane( plane.Normal(), plane.Dist() );
  209. }
  210. ID_INLINE bool idWinding::EnsureAlloced( int n, bool keep ) {
  211. if ( n > allocedSize ) {
  212. return ReAllocate( n, keep );
  213. }
  214. return true;
  215. }
  216. /*
  217. ===============================================================================
  218. idFixedWinding is a fixed buffer size winding not using
  219. memory allocations.
  220. When an operation would overflow the fixed buffer a warning
  221. is printed and the operation is safely cancelled.
  222. ===============================================================================
  223. */
  224. #define MAX_POINTS_ON_WINDING 64
  225. class idFixedWinding : public idWinding {
  226. public:
  227. idFixedWinding();
  228. explicit idFixedWinding( const int n );
  229. explicit idFixedWinding( const idVec3 *verts, const int n );
  230. explicit idFixedWinding( const idVec3 &normal, const float dist );
  231. explicit idFixedWinding( const idPlane &plane );
  232. explicit idFixedWinding( const idWinding &winding );
  233. explicit idFixedWinding( const idFixedWinding &winding );
  234. virtual ~idFixedWinding();
  235. idFixedWinding &operator=( const idWinding &winding );
  236. virtual void Clear();
  237. // splits the winding in a back and front part, 'this' becomes the front part
  238. // returns a SIDE_?
  239. int Split( idFixedWinding *back, const idPlane &plane, const float epsilon = ON_EPSILON );
  240. protected:
  241. idVec5 data[MAX_POINTS_ON_WINDING]; // point data
  242. virtual bool ReAllocate( int n, bool keep = false );
  243. };
  244. ID_INLINE idFixedWinding::idFixedWinding() {
  245. numPoints = 0;
  246. p = data;
  247. allocedSize = MAX_POINTS_ON_WINDING;
  248. }
  249. ID_INLINE idFixedWinding::idFixedWinding( int n ) {
  250. numPoints = 0;
  251. p = data;
  252. allocedSize = MAX_POINTS_ON_WINDING;
  253. }
  254. ID_INLINE idFixedWinding::idFixedWinding( const idVec3 *verts, const int n ) {
  255. int i;
  256. numPoints = 0;
  257. p = data;
  258. allocedSize = MAX_POINTS_ON_WINDING;
  259. if ( !EnsureAlloced( n ) ) {
  260. numPoints = 0;
  261. return;
  262. }
  263. for ( i = 0; i < n; i++ ) {
  264. p[i].ToVec3() = verts[i];
  265. p[i].s = p[i].t = 0;
  266. }
  267. numPoints = n;
  268. }
  269. ID_INLINE idFixedWinding::idFixedWinding( const idVec3 &normal, const float dist ) {
  270. numPoints = 0;
  271. p = data;
  272. allocedSize = MAX_POINTS_ON_WINDING;
  273. BaseForPlane( normal, dist );
  274. }
  275. ID_INLINE idFixedWinding::idFixedWinding( const idPlane &plane ) {
  276. numPoints = 0;
  277. p = data;
  278. allocedSize = MAX_POINTS_ON_WINDING;
  279. BaseForPlane( plane );
  280. }
  281. ID_INLINE idFixedWinding::idFixedWinding( const idWinding &winding ) {
  282. int i;
  283. p = data;
  284. allocedSize = MAX_POINTS_ON_WINDING;
  285. if ( !EnsureAlloced( winding.GetNumPoints() ) ) {
  286. numPoints = 0;
  287. return;
  288. }
  289. for ( i = 0; i < winding.GetNumPoints(); i++ ) {
  290. p[i] = winding[i];
  291. }
  292. numPoints = winding.GetNumPoints();
  293. }
  294. ID_INLINE idFixedWinding::idFixedWinding( const idFixedWinding &winding ) {
  295. int i;
  296. p = data;
  297. allocedSize = MAX_POINTS_ON_WINDING;
  298. if ( !EnsureAlloced( winding.GetNumPoints() ) ) {
  299. numPoints = 0;
  300. return;
  301. }
  302. for ( i = 0; i < winding.GetNumPoints(); i++ ) {
  303. p[i] = winding[i];
  304. }
  305. numPoints = winding.GetNumPoints();
  306. }
  307. ID_INLINE idFixedWinding::~idFixedWinding() {
  308. p = NULL; // otherwise it tries to free the fixed buffer
  309. }
  310. ID_INLINE idFixedWinding &idFixedWinding::operator=( const idWinding &winding ) {
  311. int i;
  312. if ( !EnsureAlloced( winding.GetNumPoints() ) ) {
  313. numPoints = 0;
  314. return *this;
  315. }
  316. for ( i = 0; i < winding.GetNumPoints(); i++ ) {
  317. p[i] = winding[i];
  318. }
  319. numPoints = winding.GetNumPoints();
  320. return *this;
  321. }
  322. ID_INLINE void idFixedWinding::Clear() {
  323. numPoints = 0;
  324. }
  325. #endif /* !__WINDING_H__ */