Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

462 lines
12 KiB

  1. #include "fow.h"
  2. #include "fow_radiusoccluder.h"
  3. #include "fow_viewer.h"
  4. #include "fow_2dplane.h"
  5. #include "engine/IVDebugOverlay.h"
  6. // memdbgon must be the last include file in a .cpp file!!!
  7. #include <tier0/memdbgon.h>
  8. extern IVDebugOverlay *debugoverlay;
  9. //-----------------------------------------------------------------------------
  10. // Purpose: constructor to init this occluder with the id
  11. // Input : nID - the id of this occluder
  12. //-----------------------------------------------------------------------------
  13. CFoW_RadiusOccluder::CFoW_RadiusOccluder( int nID )
  14. {
  15. m_nID = nID;
  16. m_flRadius = 0.0f;
  17. m_vLocation.Zero();
  18. m_nHeightGroup = 0;
  19. m_bEnabled = true;
  20. }
  21. //-----------------------------------------------------------------------------
  22. // Purpose: update the radius of this occluder
  23. // Input : flRadius - the new radius size
  24. //-----------------------------------------------------------------------------
  25. void CFoW_RadiusOccluder::UpdateSize( float flRadius )
  26. {
  27. m_flRadius = flRadius;
  28. }
  29. //-----------------------------------------------------------------------------
  30. // Purpose: update the location of this occluder
  31. // Input : vLocation - the new location
  32. //-----------------------------------------------------------------------------
  33. void CFoW_RadiusOccluder::UpdateLocation( Vector &vLocation )
  34. {
  35. m_vLocation = vLocation;
  36. }
  37. //-----------------------------------------------------------------------------
  38. // Purpose: update the height group of this occluder
  39. // Input : nHeightGroup - the new height group
  40. //-----------------------------------------------------------------------------
  41. void CFoW_RadiusOccluder::UpdateHeightGroup( uint8 nHeightGroup )
  42. {
  43. m_nHeightGroup = nHeightGroup;
  44. }
  45. //-----------------------------------------------------------------------------
  46. // Purpose: is the occluder within range of the viewer?
  47. // Input : pViewer - the viewer to check against
  48. // Output : returns true if the two circles intersect
  49. //-----------------------------------------------------------------------------
  50. bool CFoW_RadiusOccluder::IsInRange( CFoW_Viewer *pViewer )
  51. {
  52. if ( m_bEnabled == false )
  53. {
  54. return false;
  55. }
  56. Vector vDiff = pViewer->GetLocation() - m_vLocation;
  57. float flLen = sqrt( ( vDiff.x * vDiff.x ) + ( vDiff.y * vDiff.y ) );
  58. return ( flLen <= m_flRadius + pViewer->GetSize() );
  59. }
  60. //-----------------------------------------------------------------------------
  61. // Purpose: obstruct the viewer by updating the local viewer grid
  62. // Input : pFoW - the main FoW object
  63. // pViewer - the viewer to obstruct
  64. //-----------------------------------------------------------------------------
  65. void CFoW_RadiusOccluder::ObstructViewerGrid( CFoW *pFoW, CFoW_Viewer *pViewer )
  66. {
  67. if ( m_bEnabled == false )
  68. {
  69. return;
  70. }
  71. Vector vViewerLoc = pViewer->GetLocation();
  72. float flViewerRadius = pViewer->GetSize();
  73. Vector vDelta = ( vViewerLoc - m_vLocation );
  74. vDelta.z = 0.0f;
  75. float flLength = vDelta.Length();
  76. if ( flLength > ( flViewerRadius + m_flRadius ) )
  77. {
  78. return;
  79. }
  80. // if ( length <= m_flRadius || length > ViewerRadius )
  81. if ( flLength <= m_flRadius )
  82. {
  83. return;
  84. }
  85. float flAngle = ( float )atan2( vDelta.y, vDelta.x );
  86. float flTangentLen = sqrt( flLength * flLength - m_flRadius * m_flRadius );
  87. float flTangentAngle = ( float )asin( m_flRadius / flLength );
  88. // compute the two tangent angles
  89. float flPos = flAngle + flTangentAngle;
  90. float flNeg = flAngle - flTangentAngle;
  91. float x[ 6 ], y[ 6 ];
  92. // compute the two tangent points
  93. x[ 0 ] = -( float )cos( flPos ) * flTangentLen + vViewerLoc.x;
  94. y[ 0 ] = -( float )sin( flPos ) * flTangentLen + vViewerLoc.y;
  95. x[ 5 ] = -( float )cos( flNeg ) * flTangentLen + vViewerLoc.x;
  96. y[ 5 ] = -( float )sin( flNeg ) * flTangentLen + vViewerLoc.y;
  97. // extend the tangent points to the viewer's edge
  98. x[ 1 ] = -( float )cos( flPos ) * flViewerRadius + vViewerLoc.x;
  99. y[ 1 ] = -( float )sin( flPos ) * flViewerRadius + vViewerLoc.y;
  100. x[ 4 ] = -( float )cos( flNeg ) * flViewerRadius + vViewerLoc.x;
  101. y[ 4 ] = -( float )sin( flNeg ) * flViewerRadius + vViewerLoc.y;
  102. // compute the forward direction of the viewer's intersection through this blocker
  103. float fx = -vDelta.x / flLength;
  104. float fy = -vDelta.y / flLength;
  105. // compute half the length between the viewer's tangent edges
  106. float dx2 = x[ 4 ] - x[ 1 ];
  107. float dy2 = y[ 4 ] - y[ 1 ];
  108. float flHalflen = ( dx2 * dx2 + dy2 * dy2 ) / 4;
  109. // compute the side of the triangle that forms from viewer's radius to half way across the viewer's tangent edges
  110. float flLen2 = ( float )sqrt( flViewerRadius * flViewerRadius - flHalflen );
  111. flLen2 = flViewerRadius - flLen2;
  112. // compute the box extents to encompass the circle's bounds
  113. x[ 2 ] = x[ 1 ] + ( fx * flLen2 );
  114. y[ 2 ] = y[ 1 ] + ( fy * flLen2 );
  115. x[ 3 ] = x[ 4 ] + ( fx * flLen2 );
  116. y[ 3 ] = y[ 4 ] + ( fy * flLen2 );
  117. CFOW_2DPlane Planes[ 6 ];
  118. for (int i = 0; i < 6; i++)
  119. {
  120. Planes[ i ].Init( x[ i ], y[ i ], x[ ( i + 1 ) % 6 ], y[ ( i + 1 ) % 6 ] );
  121. }
  122. float flMinX = x[ 0 ], flMinY = y[ 0 ], flMaxX = x[ 0 ], flMaxY = y[ 0 ];
  123. for ( int i = 1; i < 6; i++ )
  124. {
  125. if ( x[ i ] < flMinX )
  126. {
  127. flMinX = x[ i ];
  128. }
  129. if ( x[ i ] > flMaxX )
  130. {
  131. flMaxX = x[ i ];
  132. }
  133. if ( y[ i ] < flMinY )
  134. {
  135. flMinY = y[ i ];
  136. }
  137. if ( y[i] > flMaxY )
  138. {
  139. flMaxY = y[ i ];
  140. }
  141. }
  142. float px, py, flStart_py, ex, ey;
  143. int nGridX, nGridY, nStartGridY;
  144. Vector2D vViewerStart, vViewerEnd;
  145. int nGridSize = pFoW->GetHorizontalGridSize();
  146. pViewer->GetStartPosition( vViewerStart );
  147. pViewer->GetEndPosition( vViewerEnd );
  148. if ( flMinX > vViewerStart.x )
  149. {
  150. nGridX = ( int )( flMinX - vViewerStart.x ) / nGridSize;
  151. px = vViewerStart.x + ( int )( nGridSize * nGridX );
  152. }
  153. else
  154. {
  155. px = vViewerStart.x;
  156. nGridX = 0;
  157. }
  158. if ( flMaxX < vViewerEnd.x )
  159. {
  160. ex = flMaxX;
  161. }
  162. else
  163. {
  164. ex = vViewerEnd.x;
  165. }
  166. if ( flMinY > vViewerStart.y )
  167. {
  168. nStartGridY = ( int )( flMinY - vViewerStart.y ) / nGridSize;
  169. flStart_py = vViewerStart.y + ( int )( nGridSize * nStartGridY );
  170. }
  171. else
  172. {
  173. nStartGridY = 0;
  174. flStart_py = vViewerStart.y;
  175. }
  176. if ( flMaxY < vViewerEnd.y )
  177. {
  178. ey = flMaxY;
  179. }
  180. else
  181. {
  182. ey = vViewerEnd.y;
  183. }
  184. byte *pLocalVisibility = pViewer->GetVisibility();
  185. int nLocalGridUnits = pViewer->GetGridUnits();
  186. // offset to center of grid
  187. px += nGridSize / 2;
  188. flStart_py += nGridSize / 2;
  189. for ( ; px < ex; px += nGridSize, nGridX++)
  190. {
  191. for ( nGridY = nStartGridY, py = flStart_py; py < ey; py += nGridSize, nGridY++ )
  192. {
  193. byte *pPos = pLocalVisibility + ( nGridX * nLocalGridUnits ) + nGridY;
  194. if ( ( ( *pPos ) & FOW_VG_IS_VISIBLE ) == 0 )
  195. {
  196. continue;
  197. }
  198. int i;
  199. for ( i = 0; i < 6; i++ )
  200. {
  201. #if 0
  202. // we don't need to check the bounding planes - these would be used to construct a stencil buffer though
  203. if ( i == 1 || i == 2 || i == 3 )
  204. {
  205. continue;
  206. }
  207. #endif
  208. if ( !Planes[ i ].PointInFront( px, py ) )
  209. {
  210. break;
  211. }
  212. }
  213. if ( i == 6 )
  214. {
  215. ( *pPos ) &= ~FOW_VG_IS_VISIBLE;
  216. }
  217. }
  218. }
  219. }
  220. // #define SLOW_PATH 1
  221. //-----------------------------------------------------------------------------
  222. // Purpose: obstruct the viewer by updating the depth circle
  223. // Input : pFoW - the main FoW object
  224. // pViewer - the viewer to obstruct
  225. //-----------------------------------------------------------------------------
  226. void CFoW_RadiusOccluder::ObstructViewerRadius( CFoW *pFoW, CFoW_Viewer *pViewer )
  227. {
  228. if ( m_bEnabled == false )
  229. {
  230. return;
  231. }
  232. if ( m_flRadius <= 1.0f )
  233. {
  234. Warning( "FoW: Occluder %d has invalid radius\n", m_nID );
  235. return;
  236. }
  237. int nViewerHeightGroup = pViewer->GetHeightGroup();
  238. if ( nViewerHeightGroup >= 1 && m_nHeightGroup >= 1 && m_nHeightGroup < nViewerHeightGroup )
  239. { // both the viewer and the occluder have height groups and this occluder is under the viewer, then don't obstruct
  240. return;
  241. }
  242. Vector vViewerLoc = pViewer->GetLocation();
  243. float flViewerRadius = pViewer->GetSize();
  244. Vector vDelta = ( vViewerLoc - m_vLocation );
  245. vDelta.z = 0.0f;
  246. float flLength = vDelta.Length();
  247. if ( flLength > ( flViewerRadius + m_flRadius ) )
  248. {
  249. return;
  250. }
  251. // if ( length <= m_flRadius || length > ViewerRadius )
  252. if ( flLength <= m_flRadius )
  253. {
  254. return;
  255. }
  256. float flAngle = ( float )atan2( vDelta.x, vDelta.y ) + DEG2RAD( 180.0f );
  257. float flTangentLen = sqrt( flLength * flLength - m_flRadius * m_flRadius );
  258. float flTangentAngle = ( float )asin( m_flRadius / flLength );
  259. // compute the two tangent angles
  260. float flPos = flAngle + flTangentAngle;
  261. float flNeg = flAngle - flTangentAngle;
  262. float x[ 6 ], y[ 6 ];
  263. // compute the two tangent points
  264. #ifdef SLOW_PATH
  265. x[ 0 ] = ( float )sin( flPos ) * flTangentLen + vViewerLoc.x;
  266. y[ 0 ] = ( float )cos( flPos ) * flTangentLen + vViewerLoc.y;
  267. x[ 5 ] = ( float )sin( flNeg ) * flTangentLen + vViewerLoc.x;
  268. y[ 5 ] = ( float )cos( flNeg ) * flTangentLen + vViewerLoc.y;
  269. #else
  270. x[ 0 ] = ( float )TableSin( flPos ) * flTangentLen + vViewerLoc.x;
  271. y[ 0 ] = ( float )TableCos( flPos ) * flTangentLen + vViewerLoc.y;
  272. x[ 5 ] = ( float )TableSin( flNeg ) * flTangentLen + vViewerLoc.x;
  273. y[ 5 ] = ( float )TableCos( flNeg ) * flTangentLen + vViewerLoc.y;
  274. #endif
  275. // Msg( "%g, %g\n", RAD2DEG( flPos ), RAD2DEG( flNeg ) );
  276. CFOW_2DPlane Plane;
  277. Plane.Init( x[ 5 ], y[ 5 ], x[ 0 ], y[ 0 ] );
  278. int nUnits = pViewer->GetRadiusUnits();
  279. int *pVisibility = pViewer->GetVisibilityRadius();
  280. Vector vCenterLocation = vViewerLoc;
  281. float flDistance = Plane.DistanceFrom( vCenterLocation.x, vCenterLocation.y );
  282. if ( flDistance < 0.0f )
  283. {
  284. return;
  285. }
  286. #ifdef SLOW_PATH
  287. CFOW_2DPlane Edge1, Edge2;
  288. Edge1.Init( vCenterLocation.x, vCenterLocation.y, x[ 0 ], y[ 0 ] );
  289. Edge2.Init( x[ 5 ], y[ 5 ], vCenterLocation.x, vCenterLocation.y );
  290. float flDegreeAmount = 360.0f / nUnits;
  291. float flCurrentDegree = 0.0f;
  292. for ( int i = 0; i < nUnits; i++, flCurrentDegree += flDegreeAmount )
  293. {
  294. Vector vLocation = vViewerLoc;
  295. Vector vDelta;
  296. vDelta.x = sin( DEG2RAD( flCurrentDegree ) );
  297. vDelta.y = cos( DEG2RAD( flCurrentDegree ) );
  298. vLocation += vDelta * flViewerRadius;
  299. float flDistance = Plane.DistanceFromRay( vCenterLocation.x, vCenterLocation.y, vDelta.x, vDelta.y );
  300. if ( flDistance >= 0.0f )
  301. {
  302. flDistance *= flDistance;
  303. if ( flDistance >= 0.0f && flDistance < pVisibility[ i ] )
  304. {
  305. if ( Edge1.PointInFront( vLocation.x, vLocation.y ) && Edge2.PointInFront( vLocation.x, vLocation.y ) )
  306. {
  307. pVisibility[ i ] = flDistance;
  308. }
  309. }
  310. }
  311. }
  312. #else
  313. float flCurrentDegree, flFinishDegree;
  314. int nStartIndex;
  315. if ( flPos < flNeg )
  316. {
  317. flCurrentDegree = flPos;
  318. flFinishDegree = flNeg;
  319. }
  320. else
  321. {
  322. flCurrentDegree = flNeg;
  323. flFinishDegree = flPos;
  324. }
  325. float flDegreeAmount = 2.0f * M_PI_F / nUnits;
  326. nStartIndex = ( int )( flCurrentDegree / flDegreeAmount ) % nUnits;
  327. if ( nStartIndex < 0 )
  328. {
  329. nStartIndex += nUnits;
  330. }
  331. float flHorizontalGridSize = pFoW->GetHorizontalGridSize();
  332. for ( int i = nStartIndex; flCurrentDegree < flFinishDegree; i++, flCurrentDegree += flDegreeAmount )
  333. {
  334. Vector vDelta;
  335. if ( i >= nUnits )
  336. {
  337. i = 0;
  338. }
  339. vDelta.x = TableSin( flCurrentDegree );
  340. vDelta.y = TableCos( flCurrentDegree );
  341. float flDistance = Plane.DistanceFromRay( vCenterLocation.x, vCenterLocation.y, vDelta.x, vDelta.y );
  342. if ( flDistance >= 0.0f )
  343. {
  344. flDistance += flHorizontalGridSize * 1.1f; // back off a bit
  345. flDistance *= flDistance;
  346. if ( flDistance < pVisibility[ i ] )
  347. {
  348. pVisibility[ i ] = flDistance;
  349. }
  350. }
  351. }
  352. #endif
  353. }
  354. //-----------------------------------------------------------------------------
  355. // Purpose:
  356. // Input :
  357. //-----------------------------------------------------------------------------
  358. void CFoW_RadiusOccluder::DrawDebugInfo( Vector &vLocation, float flViewRadius, unsigned nFlags )
  359. {
  360. if ( ( nFlags & FOW_DEBUG_SHOW_OCCLUDERS ) == 0 )
  361. {
  362. return;
  363. }
  364. Vector vDiff = vLocation - m_vLocation;
  365. if ( vDiff.Length2D() > flViewRadius + m_flRadius )
  366. {
  367. return;
  368. }
  369. if ( ( nFlags & FOW_DEBUG_SHOW_OCCLUDERS ) != 0 )
  370. {
  371. debugoverlay->AddSphereOverlay( m_vLocation, m_flRadius, 10, 10, 255, 0, 0, 127, FOW_DEBUG_VIEW_TIME );
  372. debugoverlay->AddBoxOverlay( m_vLocation, Vector( -16.0f, -16.0f, -16.0f ), Vector( 16.0f, 16.0f, 16.0f ), QAngle( 0, 0, 0 ), 255, 0, 0, 127, FOW_DEBUG_VIEW_TIME );
  373. }
  374. }
  375. #include <tier0/memdbgoff.h>