NearestPolygon.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /* Copyright (c) 2002-2012 Croteam Ltd.
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of version 2 of the GNU General Public License as published by
  4. the Free Software Foundation
  5. This program is distributed in the hope that it will be useful,
  6. but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License along
  10. with this program; if not, write to the Free Software Foundation, Inc.,
  11. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
  12. #include "stdh.h"
  13. #include <Engine/Entities/Entity.h>
  14. #include <Engine/Brushes/Brush.h>
  15. #include <Engine/Templates/DynamicArray.cpp>
  16. #include <Engine/Templates/StaticArray.cpp>
  17. #include <Engine/Templates/StaticStackArray.cpp>
  18. #include <Engine/Math/Geometry.inl>
  19. #include <Engine/Math/Clipping.inl>
  20. static CEntity *_pen;
  21. static FLOAT3D _vHandle;
  22. static CBrushPolygon *_pbpoNear;
  23. static FLOAT _fNearDistance;
  24. static FLOAT3D _vNearPoint;
  25. static FLOATplane3D _plPlane;
  26. class CActiveSector {
  27. public:
  28. CBrushSector *as_pbsc;
  29. void Clear(void) {};
  30. };
  31. static CStaticStackArray<CActiveSector> _aas;
  32. /* Add a sector if needed. */
  33. static void AddSector(CBrushSector *pbsc)
  34. {
  35. // if not already active and in first mip of its brush
  36. if ( pbsc->bsc_pbmBrushMip->IsFirstMip()
  37. &&!(pbsc->bsc_ulFlags&BSCF_NEARTESTED)) {
  38. // add it to active sectors
  39. _aas.Push().as_pbsc = pbsc;
  40. pbsc->bsc_ulFlags|=BSCF_NEARTESTED;
  41. }
  42. }
  43. /* Add all sectors of a brush. */
  44. static void AddAllSectorsOfBrush(CBrush3D *pbr)
  45. {
  46. // get first mip
  47. CBrushMip *pbmMip = pbr->GetFirstMip();
  48. // if it has no brush mip for that mip factor
  49. if (pbmMip==NULL) {
  50. // skip it
  51. return;
  52. }
  53. // for each sector in the brush mip
  54. FOREACHINDYNAMICARRAY(pbmMip->bm_abscSectors, CBrushSector, itbsc) {
  55. // add the sector
  56. AddSector(itbsc);
  57. }
  58. }
  59. void SearchThroughSectors(void)
  60. {
  61. // for each active sector (sectors are added during iteration!)
  62. for(INDEX ias=0; ias<_aas.Count(); ias++) {
  63. CBrushSector *pbsc = _aas[ias].as_pbsc;
  64. // for each polygon in the sector
  65. {FOREACHINSTATICARRAY(pbsc->bsc_abpoPolygons, CBrushPolygon, itbpo) {
  66. CBrushPolygon &bpo = *itbpo;
  67. // if it is not a wall
  68. if (bpo.bpo_ulFlags&BPOF_PORTAL) {
  69. // skip it
  70. continue;
  71. }
  72. const FLOATplane3D &plPolygon = bpo.bpo_pbplPlane->bpl_plAbsolute;
  73. // find distance of the polygon plane from the handle
  74. FLOAT fDistance = plPolygon.PointDistance(_vHandle);
  75. // if it is behind the plane or further than nearest found
  76. if (fDistance<0.0f || fDistance>_fNearDistance) {
  77. // skip it
  78. continue;
  79. }
  80. // find projection of handle to the polygon plane
  81. FLOAT3D vOnPlane = plPolygon.ProjectPoint(_vHandle);
  82. // if it is not in the bounding box of polygon
  83. const FLOATaabbox3D &boxPolygon = bpo.bpo_boxBoundingBox;
  84. const FLOAT EPSILON = 0.01f;
  85. if (
  86. (boxPolygon.Min()(1)-EPSILON>vOnPlane(1)) ||
  87. (boxPolygon.Max()(1)+EPSILON<vOnPlane(1)) ||
  88. (boxPolygon.Min()(2)-EPSILON>vOnPlane(2)) ||
  89. (boxPolygon.Max()(2)+EPSILON<vOnPlane(2)) ||
  90. (boxPolygon.Min()(3)-EPSILON>vOnPlane(3)) ||
  91. (boxPolygon.Max()(3)+EPSILON<vOnPlane(3))) {
  92. // skip it
  93. continue;
  94. }
  95. // find major axes of the polygon plane
  96. INDEX iMajorAxis1, iMajorAxis2;
  97. GetMajorAxesForPlane(plPolygon, iMajorAxis1, iMajorAxis2);
  98. // create an intersector
  99. CIntersector isIntersector(_vHandle(iMajorAxis1), _vHandle(iMajorAxis2));
  100. // for all edges in the polygon
  101. FOREACHINSTATICARRAY(bpo.bpo_abpePolygonEdges, CBrushPolygonEdge, itbpePolygonEdge) {
  102. // get edge vertices (edge direction is irrelevant here!)
  103. const FLOAT3D &vVertex0 = itbpePolygonEdge->bpe_pbedEdge->bed_pbvxVertex0->bvx_vAbsolute;
  104. const FLOAT3D &vVertex1 = itbpePolygonEdge->bpe_pbedEdge->bed_pbvxVertex1->bvx_vAbsolute;
  105. // pass the edge to the intersector
  106. isIntersector.AddEdge(
  107. vVertex0(iMajorAxis1), vVertex0(iMajorAxis2),
  108. vVertex1(iMajorAxis1), vVertex1(iMajorAxis2));
  109. }
  110. // if the point is not inside polygon
  111. if (!isIntersector.IsIntersecting()) {
  112. // skip it
  113. continue;
  114. }
  115. // remember the polygon
  116. _pbpoNear = &bpo;
  117. _fNearDistance = fDistance;
  118. _vNearPoint = vOnPlane;
  119. }}
  120. // for each entity in the sector
  121. {FOREACHDSTOFSRC(pbsc->bsc_rsEntities, CEntity, en_rdSectors, pen)
  122. // if it is a brush
  123. if (pen->en_RenderType == CEntity::RT_BRUSH) {
  124. // get its brush
  125. CBrush3D &brBrush = *pen->en_pbrBrush;
  126. // add all sectors in the brush
  127. AddAllSectorsOfBrush(&brBrush);
  128. }
  129. ENDFOR}
  130. }
  131. }
  132. /* Get nearest position of nearest brush polygon to this entity if available. */
  133. // use:
  134. // ->bpo_pbscSector->bsc_pbmBrushMip->bm_pbrBrush->br_penEntity
  135. // to get the entity
  136. CBrushPolygon *CEntity::GetNearestPolygon(
  137. FLOAT3D &vPoint, FLOATplane3D &plPlane, FLOAT &fDistanceToEdge)
  138. {
  139. _pen = this;
  140. // take reference point at handle of the model entity
  141. _vHandle = en_plPlacement.pl_PositionVector;
  142. // start infinitely far away
  143. _pbpoNear = NULL;
  144. _fNearDistance = UpperLimit(1.0f);
  145. // for each zoning sector that this entity is in
  146. {FOREACHSRCOFDST(en_rdSectors, CBrushSector, bsc_rsEntities, pbsc)
  147. // add the sector
  148. AddSector(pbsc);
  149. ENDFOR}
  150. // start the search
  151. SearchThroughSectors();
  152. // for each active sector
  153. for(INDEX ias=0; ias<_aas.Count(); ias++) {
  154. // mark it as inactive
  155. _aas[ias].as_pbsc->bsc_ulFlags&=~BSCF_NEARTESTED;
  156. }
  157. _aas.PopAll();
  158. // if there is some polygon found
  159. if( _pbpoNear!=NULL) {
  160. // return info
  161. plPlane = _pbpoNear->bpo_pbplPlane->bpl_plAbsolute;
  162. vPoint = _vNearPoint;
  163. fDistanceToEdge = _pbpoNear->GetDistanceFromEdges(_vNearPoint);
  164. return _pbpoNear;
  165. // if none is found
  166. } else {
  167. // return failure
  168. return NULL;
  169. }
  170. }