Team Fortress 2 Source Code as on 22/4/2020
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.

1308 lines
34 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Debugging overlay functions
  4. //
  5. // $Workfile: $
  6. // $Date: $
  7. // $NoKeywords: $
  8. //===========================================================================//
  9. #include "render_pch.h"
  10. #include "edict.h"
  11. #include "client.h"
  12. #include "debugoverlay.h"
  13. #include "cdll_int.h"
  14. #include "ivideomode.h"
  15. #include "materialsystem/imesh.h"
  16. #include "gl_matsysiface.h"
  17. #include "server.h"
  18. #include "client_class.h"
  19. #include "icliententitylist.h"
  20. #include "mathlib/vmatrix.h"
  21. #include "icliententity.h"
  22. #include "overlaytext.h"
  23. #include "engine/ivdebugoverlay.h"
  24. #include "cmodel_engine.h"
  25. #include "vphysics_interface.h"
  26. #include "materialsystem/imaterial.h"
  27. #include "tier2/renderutils.h"
  28. // memdbgon must be the last include file in a .cpp file!!!
  29. #include "tier0/memdbgon.h"
  30. extern edict_t *EDICT_NUM(int n);
  31. ConVar enable_debug_overlays( "enable_debug_overlays", "1", FCVAR_GAMEDLL | FCVAR_CHEAT, "Enable rendering of debug overlays" );
  32. int GetOverlayTick()
  33. {
  34. if ( sv.IsActive() )
  35. return sv.m_nTickCount;
  36. return cl.GetClientTickCount();
  37. }
  38. bool OverlayText_t::IsDead()
  39. {
  40. if ( IsXbox() && cl.IsPaused() )
  41. return false;
  42. if ( m_nServerCount != cl.m_nServerCount )
  43. return true;
  44. if ( m_nCreationTick != -1 )
  45. {
  46. if ( GetOverlayTick() > m_nCreationTick )
  47. return true;
  48. return false;
  49. }
  50. if ( m_flEndTime == NDEBUG_PERSIST_TILL_NEXT_SERVER )
  51. return false;
  52. return (cl.GetTime() >= m_flEndTime);
  53. }
  54. void OverlayText_t::SetEndTime( float duration )
  55. {
  56. m_nServerCount = cl.m_nServerCount;
  57. if ( duration <= 0.0f )
  58. {
  59. m_flEndTime = 0.0f;
  60. m_nCreationTick = GetOverlayTick();
  61. return;
  62. }
  63. if ( duration == NDEBUG_PERSIST_TILL_NEXT_SERVER )
  64. {
  65. m_flEndTime = NDEBUG_PERSIST_TILL_NEXT_SERVER;
  66. }
  67. else
  68. {
  69. m_flEndTime = cl.GetTime() + duration;
  70. }
  71. }
  72. namespace CDebugOverlay
  73. {
  74. enum OverlayType_t
  75. {
  76. OVERLAY_BOX = 0,
  77. OVERLAY_SPHERE,
  78. OVERLAY_LINE,
  79. OVERLAY_TRIANGLE,
  80. OVERLAY_SWEPT_BOX,
  81. OVERLAY_BOX2
  82. };
  83. struct OverlayBase_t
  84. {
  85. OverlayBase_t()
  86. {
  87. m_Type = OVERLAY_BOX;
  88. m_nServerCount = -1;
  89. m_nCreationTick = -1;
  90. m_flEndTime = 0.0f;
  91. m_pNextOverlay = NULL;
  92. }
  93. bool IsDead()
  94. {
  95. if ( IsXbox() && cl.IsPaused() )
  96. return false;
  97. if ( m_nServerCount != cl.m_nServerCount )
  98. return true;
  99. if ( m_nCreationTick != -1 )
  100. {
  101. if ( GetOverlayTick() > m_nCreationTick )
  102. return true;
  103. return false;
  104. }
  105. if ( m_flEndTime == NDEBUG_PERSIST_TILL_NEXT_SERVER )
  106. return false;
  107. return (cl.GetTime() >= m_flEndTime) ;
  108. }
  109. void SetEndTime( float duration )
  110. {
  111. m_nServerCount = cl.m_nServerCount;
  112. if ( duration <= 0.0f )
  113. {
  114. m_nCreationTick = GetOverlayTick(); // stay alive for only one frame
  115. return;
  116. }
  117. if ( duration == NDEBUG_PERSIST_TILL_NEXT_SERVER )
  118. {
  119. m_flEndTime = NDEBUG_PERSIST_TILL_NEXT_SERVER;
  120. }
  121. else
  122. {
  123. m_flEndTime = cl.GetTime() + duration;
  124. }
  125. }
  126. OverlayType_t m_Type; // What type of overlay is it?
  127. int m_nCreationTick; // Duration -1 means go away after this frame #
  128. int m_nServerCount; // Latch server count, too
  129. float m_flEndTime; // When does this box go away
  130. OverlayBase_t *m_pNextOverlay;
  131. };
  132. struct OverlayBox_t : public OverlayBase_t
  133. {
  134. OverlayBox_t() { m_Type = OVERLAY_BOX; }
  135. Vector origin;
  136. Vector mins;
  137. Vector maxs;
  138. QAngle angles;
  139. int r;
  140. int g;
  141. int b;
  142. int a;
  143. };
  144. struct OverlayBox2_t : public OverlayBase_t
  145. {
  146. OverlayBox2_t() { m_Type = OVERLAY_BOX2; }
  147. Vector origin;
  148. Vector mins;
  149. Vector maxs;
  150. QAngle angles;
  151. Color edgeColor;
  152. Color faceColor;
  153. };
  154. struct OverlaySphere_t : public OverlayBase_t
  155. {
  156. OverlaySphere_t() { m_Type = OVERLAY_SPHERE; }
  157. Vector vOrigin;
  158. float flRadius;
  159. int nTheta;
  160. int nPhi;
  161. int r;
  162. int g;
  163. int b;
  164. int a;
  165. };
  166. struct OverlayLine_t : public OverlayBase_t
  167. {
  168. OverlayLine_t() { m_Type = OVERLAY_LINE; }
  169. Vector origin;
  170. Vector dest;
  171. int r;
  172. int g;
  173. int b;
  174. int a;
  175. bool noDepthTest;
  176. };
  177. struct OverlayTriangle_t : public OverlayBase_t
  178. {
  179. OverlayTriangle_t() { m_Type = OVERLAY_TRIANGLE; }
  180. Vector p1;
  181. Vector p2;
  182. Vector p3;
  183. int r;
  184. int g;
  185. int b;
  186. int a;
  187. bool noDepthTest;
  188. };
  189. struct OverlaySweptBox_t : public OverlayBase_t
  190. {
  191. OverlaySweptBox_t() { m_Type = OVERLAY_SWEPT_BOX; }
  192. Vector start;
  193. Vector end;
  194. Vector mins;
  195. Vector maxs;
  196. QAngle angles;
  197. int r;
  198. int g;
  199. int b;
  200. int a;
  201. };
  202. //-----------------------------------------------------------------------------
  203. // Forward declarations
  204. //-----------------------------------------------------------------------------
  205. void DrawOverlays();
  206. void DrawGridOverlay();
  207. void ClearAllOverlays();
  208. void ClearDeadOverlays();
  209. //-----------------------------------------------------------------------------
  210. // Init static member variables
  211. //-----------------------------------------------------------------------------
  212. OverlayText_t* s_pOverlayText = NULL; // text is handled differently; for backward compatibility reasons
  213. OverlayBase_t* s_pOverlays = NULL;
  214. Vector s_vGridPosition(0,0,0);
  215. bool s_bDrawGrid = false;
  216. CThreadFastMutex s_OverlayMutex;
  217. //-----------------------------------------------------------------------------
  218. // Purpose: Hack to allow this code to run on a client that's not connected to a server
  219. // (i.e., demo playback, or multiplayer game )
  220. // Input : ent_num -
  221. // origin -
  222. // mins -
  223. // maxs -
  224. // Output : static void
  225. //-----------------------------------------------------------------------------
  226. static bool GetEntityOriginClientOrServer( int ent_num, Vector& origin )
  227. {
  228. AUTO_LOCK( s_OverlayMutex );
  229. // Assume failure
  230. origin.Init();
  231. if ( sv.IsActive() )
  232. {
  233. edict_t *e = EDICT_NUM( ent_num );
  234. if ( e )
  235. {
  236. IServerEntity *serverEntity = e->GetIServerEntity();
  237. if ( serverEntity )
  238. {
  239. CM_WorldSpaceCenter( serverEntity->GetCollideable(), &origin );
  240. }
  241. return true;
  242. }
  243. }
  244. else
  245. {
  246. IClientEntity *clent = entitylist->GetClientEntity( ent_num );
  247. if ( clent )
  248. {
  249. CM_WorldSpaceCenter( clent->GetCollideable(), &origin );
  250. return true;
  251. }
  252. }
  253. return false;
  254. }
  255. //-----------------------------------------------------------------------------
  256. // Purpose: Given a point, return the screen position
  257. // Input :
  258. // Output :
  259. //-----------------------------------------------------------------------------
  260. int ScreenPosition(const Vector& point, Vector& screen)
  261. {
  262. AUTO_LOCK( s_OverlayMutex );
  263. CMatRenderContextPtr pRenderContext( materials );
  264. int retval = g_EngineRenderer->ClipTransform(point,&screen);
  265. int x, y, w, h;
  266. pRenderContext->GetViewport( x, y, w, h );
  267. screen[0] = 0.5 * screen[0] * w;
  268. screen[1] = -0.5 * screen[1] * h;
  269. screen[0] += 0.5 * w;
  270. screen[1] += 0.5 * h;
  271. return retval;
  272. }
  273. //-----------------------------------------------------------------------------
  274. // Purpose: Given an xy screen pos (0-1), return the screen position
  275. // Input :
  276. // Output :
  277. //-----------------------------------------------------------------------------
  278. int ScreenPosition(float flXPos, float flYPos, Vector& screen)
  279. {
  280. if (flXPos > 1.0 || flYPos > 1.0 || flXPos < 0.0 || flYPos < 0.0 )
  281. return 1; // Fail
  282. AUTO_LOCK( s_OverlayMutex );
  283. CMatRenderContextPtr pRenderContext( materials );
  284. int x, y, w, h;
  285. pRenderContext->GetViewport( x, y, w, h );
  286. screen[0] = flXPos * w;
  287. screen[1] = flYPos * h;
  288. return 0;
  289. }
  290. //-----------------------------------------------------------------------------
  291. // Purpose: Add new entity positioned overlay text
  292. // Input : Entity to attach text to
  293. // How many lines to offset text from entity origin
  294. // The text to print
  295. // Output :
  296. //-----------------------------------------------------------------------------
  297. void AddEntityTextOverlay(int ent_index, int line_offset, float duration, int r, int g, int b, int a, const char *text)
  298. {
  299. if ( cl.IsPaused() )
  300. return;
  301. AUTO_LOCK( s_OverlayMutex );
  302. OverlayText_t *new_overlay = new OverlayText_t;
  303. Vector myPos, myMins, myMaxs;
  304. GetEntityOriginClientOrServer( ent_index, myPos );
  305. VectorCopy(myPos,new_overlay->origin);
  306. Q_strncpy(new_overlay->text,text, sizeof( new_overlay->text ) );
  307. new_overlay->bUseOrigin = true;
  308. new_overlay->lineOffset = line_offset;
  309. new_overlay->SetEndTime( duration );
  310. new_overlay->r = r;
  311. new_overlay->g = g;
  312. new_overlay->b = b;
  313. new_overlay->a = a;
  314. new_overlay->nextOverlayText = s_pOverlayText;
  315. s_pOverlayText = new_overlay;
  316. }
  317. //-----------------------------------------------------------------------------
  318. // Purpose: Add new overlay text
  319. // Input : Position of text & text
  320. // Output :
  321. //-----------------------------------------------------------------------------
  322. void AddGridOverlay(const Vector& vPos)
  323. {
  324. if ( cl.IsPaused() )
  325. return;
  326. AUTO_LOCK( s_OverlayMutex );
  327. s_vGridPosition[0] = vPos[0];
  328. s_vGridPosition[1] = vPos[1];
  329. s_vGridPosition[2] = vPos[2];
  330. s_bDrawGrid = true;
  331. }
  332. void AddCoordFrameOverlay(const matrix3x4_t& frame, float flScale, int vColorTable[3][3]/*=NULL*/)
  333. {
  334. static int s_defaultColorTable[3][3] =
  335. {
  336. { 255, 0, 0 },
  337. { 0 , 255, 0 },
  338. { 0 , 0, 255 }
  339. };
  340. AUTO_LOCK( s_OverlayMutex );
  341. if ( vColorTable == NULL )
  342. vColorTable = s_defaultColorTable;
  343. Vector startPt, endPt;
  344. MatrixGetColumn( frame, 3, startPt );
  345. for (int k = 0; k < 3; k++)
  346. {
  347. endPt.x = frame[0][3] + frame[0][k] * flScale;
  348. endPt.y = frame[1][3] + frame[1][k] * flScale;
  349. endPt.z = frame[2][3] + frame[2][k] * flScale;
  350. AddLineOverlay(
  351. startPt,
  352. endPt,
  353. vColorTable[k][0], vColorTable[k][1], vColorTable[k][2], 255,
  354. true,
  355. NDEBUG_PERSIST_TILL_NEXT_SERVER
  356. );
  357. }
  358. }
  359. //-----------------------------------------------------------------------------
  360. // Purpose: Add new overlay text
  361. // Input : Position of text & text
  362. // Output :
  363. //-----------------------------------------------------------------------------
  364. void AddTextOverlay(const Vector& textPos, float duration, const char *text)
  365. {
  366. if ( cl.IsPaused() )
  367. return;
  368. AUTO_LOCK( s_OverlayMutex );
  369. OverlayText_t *new_overlay = new OverlayText_t;
  370. VectorCopy(textPos,new_overlay->origin);
  371. Q_strncpy(new_overlay->text,text, sizeof( new_overlay->text ) );
  372. new_overlay->bUseOrigin = true;
  373. new_overlay->lineOffset = 0;
  374. new_overlay->SetEndTime( duration );
  375. new_overlay->r = 255;
  376. new_overlay->g = 255;
  377. new_overlay->b = 255;
  378. new_overlay->a = 255;
  379. new_overlay->nextOverlayText = s_pOverlayText;
  380. s_pOverlayText = new_overlay;
  381. }
  382. //-----------------------------------------------------------------------------
  383. // Purpose: Add new overlay text
  384. // Input : Position of text & text
  385. // Output :
  386. //-----------------------------------------------------------------------------
  387. void AddTextOverlay(const Vector& textPos, float duration, float alpha, const char *text)
  388. {
  389. if ( cl.IsPaused() )
  390. return;
  391. AUTO_LOCK( s_OverlayMutex );
  392. OverlayText_t *new_overlay = new OverlayText_t;
  393. VectorCopy(textPos,new_overlay->origin);
  394. Q_strncpy(new_overlay->text,text, sizeof( new_overlay->text ) );
  395. new_overlay->bUseOrigin = true;
  396. new_overlay->lineOffset = 0;
  397. new_overlay->SetEndTime( duration );
  398. new_overlay->r = 255;
  399. new_overlay->g = 255;
  400. new_overlay->b = 255;
  401. new_overlay->a = (int)clamp(alpha * 255.f,0.f,255.f);
  402. new_overlay->nextOverlayText = s_pOverlayText;
  403. s_pOverlayText = new_overlay;
  404. }
  405. //------------------------------------------------------------------------------
  406. // Purpose :
  407. // Input :
  408. // Output :
  409. //------------------------------------------------------------------------------
  410. void AddScreenTextOverlay(float flXPos, float flYPos, int line_offset, float duration, int r, int g, int b, int a, const char *text)
  411. {
  412. if ( cl.IsPaused() )
  413. return;
  414. AUTO_LOCK( s_OverlayMutex );
  415. OverlayText_t *new_overlay = new OverlayText_t;
  416. Q_strncpy(new_overlay->text,text, sizeof( new_overlay->text ) );
  417. new_overlay->flXPos = flXPos;
  418. new_overlay->flYPos = flYPos;
  419. new_overlay->bUseOrigin = false;
  420. new_overlay->lineOffset = line_offset;
  421. new_overlay->SetEndTime( duration );
  422. new_overlay->r = r;
  423. new_overlay->g = g;
  424. new_overlay->b = b;
  425. new_overlay->a = a;
  426. new_overlay->nextOverlayText = s_pOverlayText;
  427. s_pOverlayText = new_overlay;
  428. }
  429. void AddScreenTextOverlay( float flXPos, float flYPos, float duration, int r, int g, int b, int a, const char *text )
  430. {
  431. AddScreenTextOverlay( flXPos, flYPos, 0, duration, r, g, b, a, text );
  432. }
  433. //-----------------------------------------------------------------------------
  434. // Purpose: Add new overlay text
  435. // Input : Position of text
  436. // How many lines to offset text from position
  437. // ext
  438. // Output :
  439. //-----------------------------------------------------------------------------
  440. void AddTextOverlay(const Vector& textPos, int line_offset, float duration, const char *text)
  441. {
  442. if ( cl.IsPaused() )
  443. return;
  444. AUTO_LOCK( s_OverlayMutex );
  445. OverlayText_t *new_overlay = new OverlayText_t;
  446. VectorCopy(textPos,new_overlay->origin);
  447. Q_strncpy(new_overlay->text,text, sizeof( new_overlay->text ) );
  448. new_overlay->bUseOrigin = true;
  449. new_overlay->lineOffset = line_offset;
  450. new_overlay->SetEndTime( duration );
  451. new_overlay->r = 255;
  452. new_overlay->g = 255;
  453. new_overlay->b = 255;
  454. new_overlay->a = 255;
  455. new_overlay->bUseOrigin = true;
  456. new_overlay->nextOverlayText = s_pOverlayText;
  457. s_pOverlayText = new_overlay;
  458. }
  459. void AddTextOverlay(const Vector& textPos, int line_offset, float duration, float alpha, const char *text)
  460. {
  461. if ( cl.IsPaused() )
  462. return;
  463. AUTO_LOCK( s_OverlayMutex );
  464. OverlayText_t *new_overlay = new OverlayText_t;
  465. VectorCopy(textPos,new_overlay->origin);
  466. Q_strncpy(new_overlay->text,text, sizeof( new_overlay->text ) );
  467. new_overlay->bUseOrigin = true;
  468. new_overlay->lineOffset = line_offset;
  469. new_overlay->SetEndTime( duration );
  470. new_overlay->r = 255;
  471. new_overlay->g = 255;
  472. new_overlay->b = 255;
  473. new_overlay->a = (int)clamp(alpha * 255.f,0.f,255.f);
  474. new_overlay->bUseOrigin = true;
  475. new_overlay->nextOverlayText = s_pOverlayText;
  476. s_pOverlayText = new_overlay;
  477. }
  478. void AddTextOverlay(const Vector& textPos, int line_offset, float duration, float r, float g, float b, float alpha, const char *text)
  479. {
  480. if ( cl.IsPaused() )
  481. return;
  482. AUTO_LOCK( s_OverlayMutex );
  483. OverlayText_t *new_overlay = new OverlayText_t;
  484. VectorCopy(textPos,new_overlay->origin);
  485. Q_strncpy(new_overlay->text,text, sizeof( new_overlay->text ) );
  486. new_overlay->bUseOrigin = true;
  487. new_overlay->lineOffset = line_offset;
  488. new_overlay->SetEndTime( duration );
  489. new_overlay->r = (int)clamp(r * 255.f,0.f,255.f);
  490. new_overlay->g = (int)clamp(g * 255.f,0.f,255.f);
  491. new_overlay->b = (int)clamp(b * 255.f,0.f,255.f);
  492. new_overlay->a = (int)clamp(alpha * 255.f,0.f,255.f);
  493. new_overlay->bUseOrigin = true;
  494. new_overlay->nextOverlayText = s_pOverlayText;
  495. s_pOverlayText = new_overlay;
  496. }
  497. //-----------------------------------------------------------------------------
  498. // Purpose: Add new overlay box
  499. // Input : Position of box
  500. // size of box
  501. // angles of box
  502. // color & alpha
  503. // duration
  504. // Output :
  505. //-----------------------------------------------------------------------------
  506. void AddBoxOverlay(const Vector& origin, const Vector& mins, const Vector& maxs, QAngle const& angles, int r, int g, int b, int a, float flDuration)
  507. {
  508. if ( cl.IsPaused() )
  509. return;
  510. AUTO_LOCK( s_OverlayMutex );
  511. OverlayBox_t *new_overlay = new OverlayBox_t;
  512. new_overlay->origin = origin;
  513. new_overlay->mins[0] = mins[0];
  514. new_overlay->mins[1] = mins[1];
  515. new_overlay->mins[2] = mins[2];
  516. new_overlay->maxs[0] = maxs[0];
  517. new_overlay->maxs[1] = maxs[1];
  518. new_overlay->maxs[2] = maxs[2];
  519. new_overlay->angles = angles;
  520. new_overlay->r = r;
  521. new_overlay->g = g;
  522. new_overlay->b = b;
  523. new_overlay->a = a;
  524. new_overlay->SetEndTime( flDuration );
  525. new_overlay->m_pNextOverlay = s_pOverlays;
  526. s_pOverlays = new_overlay;
  527. }
  528. void AddBoxOverlay2( const Vector& origin, const Vector& mins, const Vector& maxs, QAngle const& orientation, const Color& faceColor, const Color& edgeColor, float duration )
  529. {
  530. if ( cl.IsPaused() )
  531. return;
  532. AUTO_LOCK( s_OverlayMutex );
  533. OverlayBox2_t *new_overlay = new OverlayBox2_t;
  534. new_overlay->origin = origin;
  535. new_overlay->mins[0] = mins[0];
  536. new_overlay->mins[1] = mins[1];
  537. new_overlay->mins[2] = mins[2];
  538. new_overlay->maxs[0] = maxs[0];
  539. new_overlay->maxs[1] = maxs[1];
  540. new_overlay->maxs[2] = maxs[2];
  541. new_overlay->angles = orientation;
  542. new_overlay->faceColor = faceColor;
  543. new_overlay->edgeColor = edgeColor;
  544. new_overlay->SetEndTime( duration );
  545. new_overlay->m_pNextOverlay = s_pOverlays;
  546. s_pOverlays = new_overlay;
  547. }
  548. //-----------------------------------------------------------------------------
  549. // Purpose: Add new overlay sphere
  550. // Input : Position of sphere
  551. // radius of sphere
  552. // color & alpha
  553. // duration
  554. // Output :
  555. //-----------------------------------------------------------------------------
  556. void AddSphereOverlay(const Vector& vOrigin, float flRadius, int nTheta, int nPhi, int r, int g, int b, int a, float flDuration)
  557. {
  558. if ( cl.IsPaused() )
  559. return;
  560. AUTO_LOCK( s_OverlayMutex );
  561. OverlaySphere_t *new_overlay = new OverlaySphere_t;
  562. new_overlay->vOrigin = vOrigin;
  563. new_overlay->flRadius = flRadius;
  564. new_overlay->nTheta = nTheta;
  565. new_overlay->nPhi = nPhi;
  566. new_overlay->r = r;
  567. new_overlay->g = g;
  568. new_overlay->b = b;
  569. new_overlay->a = a;
  570. new_overlay->SetEndTime( flDuration );
  571. new_overlay->m_pNextOverlay = s_pOverlays;
  572. s_pOverlays = new_overlay;
  573. }
  574. void AddSweptBoxOverlay(const Vector& start, const Vector& end,
  575. const Vector& mins, const Vector& maxs, QAngle const& angles, int r, int g, int b, int a, float flDuration)
  576. {
  577. if ( cl.IsPaused() )
  578. return;
  579. AUTO_LOCK( s_OverlayMutex );
  580. OverlaySweptBox_t *new_overlay = new OverlaySweptBox_t;
  581. new_overlay->start = start;
  582. new_overlay->end = end;
  583. new_overlay->mins[0] = mins[0];
  584. new_overlay->mins[1] = mins[1];
  585. new_overlay->mins[2] = mins[2];
  586. new_overlay->maxs[0] = maxs[0];
  587. new_overlay->maxs[1] = maxs[1];
  588. new_overlay->maxs[2] = maxs[2];
  589. new_overlay->angles = angles;
  590. new_overlay->r = r;
  591. new_overlay->g = g;
  592. new_overlay->b = b;
  593. new_overlay->a = a;
  594. new_overlay->SetEndTime( flDuration );
  595. new_overlay->m_pNextOverlay = s_pOverlays;
  596. s_pOverlays = new_overlay;
  597. }
  598. //-----------------------------------------------------------------------------
  599. // Purpose: Add new overlay text
  600. // Input : Entity to attach text to
  601. // How many lines to offset text from entity origin
  602. // The text to print
  603. // Output :
  604. //-----------------------------------------------------------------------------
  605. void AddLineOverlay(const Vector& origin, const Vector& dest, int r, int g, int b, int a, bool noDepthTest, float flDuration)
  606. {
  607. if ( cl.IsPaused() )
  608. return;
  609. AUTO_LOCK( s_OverlayMutex );
  610. OverlayLine_t *new_loverlay = new OverlayLine_t;
  611. new_loverlay->origin[0] = origin[0];
  612. new_loverlay->origin[1] = origin[1];
  613. new_loverlay->origin[2] = origin[2];
  614. new_loverlay->dest[0] = dest[0];
  615. new_loverlay->dest[1] = dest[1];
  616. new_loverlay->dest[2] = dest[2];
  617. new_loverlay->r = r;
  618. new_loverlay->g = g;
  619. new_loverlay->b = b;
  620. new_loverlay->a = a;
  621. new_loverlay->noDepthTest = noDepthTest;
  622. new_loverlay->SetEndTime( flDuration );
  623. new_loverlay->m_pNextOverlay = s_pOverlays;
  624. s_pOverlays = new_loverlay;
  625. }
  626. //-----------------------------------------------------------------------------
  627. // Purpose: Add new triangle overlay
  628. //-----------------------------------------------------------------------------
  629. void AddTriangleOverlay(const Vector& p1, const Vector& p2, const Vector &p3,
  630. int r, int g, int b, int a, bool noDepthTest, float flDuration)
  631. {
  632. if ( cl.IsPaused() )
  633. return;
  634. AUTO_LOCK( s_OverlayMutex );
  635. OverlayTriangle_t *pTriangle = new OverlayTriangle_t;
  636. pTriangle->p1 = p1;
  637. pTriangle->p2 = p2;
  638. pTriangle->p3 = p3;
  639. pTriangle->r = r;
  640. pTriangle->g = g;
  641. pTriangle->b = b;
  642. pTriangle->a = a;
  643. pTriangle->noDepthTest = noDepthTest;
  644. pTriangle->SetEndTime( flDuration );
  645. pTriangle->m_pNextOverlay = s_pOverlays;
  646. s_pOverlays = pTriangle;
  647. }
  648. //------------------------------------------------------------------------------
  649. // Purpose : Draw a grid around the s_vGridPosition
  650. // Input :
  651. // Output :
  652. //------------------------------------------------------------------------------
  653. void DrawGridOverlay(void)
  654. {
  655. AUTO_LOCK( s_OverlayMutex );
  656. static int gridSpacing = 100;
  657. static int numHorzSpaces = 16;
  658. static int numVertSpaces = 3;
  659. Vector startGrid;
  660. startGrid[0] = gridSpacing*((int)s_vGridPosition[0]/gridSpacing);
  661. startGrid[1] = gridSpacing*((int)s_vGridPosition[1]/gridSpacing);
  662. startGrid[2] = s_vGridPosition[2];
  663. // Shift to the left
  664. startGrid[0] -= (numHorzSpaces/2)*gridSpacing;
  665. startGrid[1] -= (numHorzSpaces/2)*gridSpacing;
  666. Vector color( 20, 180, 190 );
  667. for (int i=1;i<numVertSpaces+1;i++)
  668. {
  669. // Draw x axis lines
  670. Vector startLine;
  671. VectorCopy(startGrid,startLine);
  672. for (int j=0;j<numHorzSpaces+1;j++)
  673. {
  674. Vector endLine;
  675. VectorCopy(startLine,endLine);
  676. endLine[0] += gridSpacing*numHorzSpaces;
  677. RenderLine( startLine, endLine, Color( color.x, color.y, color.z, 255 ), true );
  678. Vector bottomStartLine;
  679. VectorCopy(startLine,bottomStartLine);
  680. for ( int k=0; k<numHorzSpaces+1; k++ )
  681. {
  682. Vector bottomEndLine;
  683. VectorCopy(bottomStartLine,bottomEndLine);
  684. bottomEndLine[2] -= gridSpacing;
  685. RenderLine( bottomStartLine, bottomEndLine, Color( color.x, color.y, color.z, 255 ), true );
  686. bottomStartLine[0] += gridSpacing;
  687. }
  688. startLine[1] += gridSpacing;
  689. }
  690. // Draw y axis lines
  691. VectorCopy(startGrid,startLine);
  692. for ( int j=0; j<numHorzSpaces+1; j++ )
  693. {
  694. Vector endLine;
  695. VectorCopy(startLine,endLine);
  696. endLine[1] += gridSpacing*numHorzSpaces;
  697. RenderLine( startLine, endLine, Color( color.x, color.y, color.z, 255 ), true );
  698. startLine[0] += gridSpacing;
  699. }
  700. VectorScale( color, 0.7, color );
  701. startGrid[2] -= gridSpacing;
  702. }
  703. s_bDrawGrid = false;
  704. }
  705. //------------------------------------------------------------------------------
  706. // Draws a generic overlay
  707. //------------------------------------------------------------------------------
  708. void DrawOverlay( OverlayBase_t *pOverlay )
  709. {
  710. AUTO_LOCK( s_OverlayMutex );
  711. switch( pOverlay->m_Type)
  712. {
  713. case OVERLAY_LINE:
  714. {
  715. // Draw the line
  716. OverlayLine_t *pLine = static_cast<OverlayLine_t*>(pOverlay);
  717. RenderLine( pLine->origin, pLine->dest, Color( pLine->r, pLine->g, pLine->b, pLine->a ), !pLine->noDepthTest);
  718. }
  719. break;
  720. case OVERLAY_BOX:
  721. {
  722. // Draw the box
  723. OverlayBox_t *pCurrBox = static_cast<OverlayBox_t*>(pOverlay);
  724. if ( pCurrBox->a > 0 )
  725. {
  726. RenderBox( pCurrBox->origin, pCurrBox->angles, pCurrBox->mins, pCurrBox->maxs, Color( pCurrBox->r, pCurrBox->g, pCurrBox->b, pCurrBox->a ), false );
  727. }
  728. RenderWireframeBox( pCurrBox->origin, pCurrBox->angles, pCurrBox->mins, pCurrBox->maxs, Color( pCurrBox->r, pCurrBox->g, pCurrBox->b, 255 ), true );
  729. }
  730. break;
  731. case OVERLAY_BOX2:
  732. {
  733. // Draw the box
  734. OverlayBox2_t *pCurrBox = static_cast<OverlayBox2_t*>(pOverlay);
  735. if ( pCurrBox->faceColor.a() > 0 )
  736. {
  737. RenderBox( pCurrBox->origin, pCurrBox->angles, pCurrBox->mins, pCurrBox->maxs, pCurrBox->faceColor, false );
  738. }
  739. if ( pCurrBox->edgeColor.a() > 0 )
  740. {
  741. RenderWireframeBox( pCurrBox->origin, pCurrBox->angles, pCurrBox->mins, pCurrBox->maxs, pCurrBox->edgeColor, false );
  742. }
  743. }
  744. break;
  745. case OVERLAY_SPHERE:
  746. {
  747. // Draw the sphere
  748. OverlaySphere_t *pSphere = static_cast<OverlaySphere_t*>(pOverlay);
  749. RenderSphere( pSphere->vOrigin, pSphere->flRadius, pSphere->nTheta, pSphere->nPhi, Color( pSphere->r, pSphere->g, pSphere->b, pSphere->a ), g_pMaterialAmbientCube );
  750. }
  751. break;
  752. case OVERLAY_SWEPT_BOX:
  753. {
  754. OverlaySweptBox_t *pBox = static_cast<OverlaySweptBox_t*>(pOverlay);
  755. RenderWireframeSweptBox( pBox->start, pBox->end, pBox->angles, pBox->mins, pBox->maxs, Color( pBox->r, pBox->g, pBox->b, pBox->a ), true );
  756. }
  757. break;
  758. case OVERLAY_TRIANGLE:
  759. {
  760. OverlayTriangle_t *pTriangle = static_cast<OverlayTriangle_t*>(pOverlay);
  761. RenderTriangle( pTriangle->p1, pTriangle->p2, pTriangle->p3,
  762. Color( pTriangle->r, pTriangle->g, pTriangle->b, pTriangle->a ), !pTriangle->noDepthTest );
  763. }
  764. break;
  765. default:
  766. Assert(0);
  767. }
  768. }
  769. void DestroyOverlay( OverlayBase_t *pOverlay )
  770. {
  771. AUTO_LOCK( s_OverlayMutex );
  772. switch( pOverlay->m_Type)
  773. {
  774. case OVERLAY_LINE:
  775. {
  776. OverlayLine_t *pCurrLine = static_cast<OverlayLine_t*>(pOverlay);
  777. delete pCurrLine;
  778. }
  779. break;
  780. case OVERLAY_BOX:
  781. {
  782. OverlayBox_t *pCurrBox = static_cast<OverlayBox_t*>(pOverlay);
  783. delete pCurrBox;
  784. }
  785. break;
  786. case OVERLAY_BOX2:
  787. {
  788. OverlayBox2_t *pCurrBox = static_cast<OverlayBox2_t*>(pOverlay);
  789. delete pCurrBox;
  790. }
  791. break;
  792. case OVERLAY_SPHERE:
  793. {
  794. OverlaySphere_t *pCurrSphere = static_cast<OverlaySphere_t*>(pOverlay);
  795. delete pCurrSphere;
  796. }
  797. break;
  798. case OVERLAY_SWEPT_BOX:
  799. {
  800. OverlaySweptBox_t *pCurrBox = static_cast<OverlaySweptBox_t*>(pOverlay);
  801. delete pCurrBox;
  802. }
  803. break;
  804. case OVERLAY_TRIANGLE:
  805. {
  806. OverlayTriangle_t *pTriangle = static_cast<OverlayTriangle_t*>(pOverlay);
  807. delete pTriangle;
  808. }
  809. break;
  810. default:
  811. Assert(0);
  812. }
  813. }
  814. //------------------------------------------------------------------------------
  815. // Purpose :
  816. // Input :
  817. // Output :
  818. //------------------------------------------------------------------------------
  819. void DrawAllOverlays(void)
  820. {
  821. if ( !enable_debug_overlays.GetBool() )
  822. return;
  823. AUTO_LOCK( s_OverlayMutex );
  824. OverlayBase_t* pCurrOverlay = s_pOverlays;
  825. OverlayBase_t* pPrevOverlay = NULL;
  826. OverlayBase_t* pNextOverlay;
  827. while (pCurrOverlay)
  828. {
  829. // Is it time to kill this overlay?
  830. if ( pCurrOverlay->IsDead() )
  831. {
  832. if (pPrevOverlay)
  833. {
  834. // If I had a last overlay reset it's next pointer
  835. pPrevOverlay->m_pNextOverlay = pCurrOverlay->m_pNextOverlay;
  836. }
  837. else
  838. {
  839. // If the first line, reset the s_pOverlays pointer
  840. s_pOverlays = pCurrOverlay->m_pNextOverlay;
  841. }
  842. pNextOverlay = pCurrOverlay->m_pNextOverlay;
  843. DestroyOverlay( pCurrOverlay );
  844. pCurrOverlay = pNextOverlay;
  845. }
  846. else
  847. {
  848. DrawOverlay( pCurrOverlay );
  849. pPrevOverlay = pCurrOverlay;
  850. pCurrOverlay = pCurrOverlay->m_pNextOverlay;
  851. }
  852. }
  853. }
  854. //------------------------------------------------------------------------------
  855. // Purpose : Remove from the linkedlist overlays that have the special "until next
  856. // server tick" frametime
  857. // Input :
  858. // Output :
  859. //------------------------------------------------------------------------------
  860. //0.01234f
  861. void PurgeServerOverlays( void )
  862. {
  863. AUTO_LOCK( s_OverlayMutex );
  864. OverlayBase_t* pCurrOverlay = s_pOverlays;
  865. while (pCurrOverlay)
  866. {
  867. if ( pCurrOverlay->m_flEndTime == NDEBUG_PERSIST_TILL_NEXT_SERVER )
  868. {
  869. pCurrOverlay->m_flEndTime = cl.GetTime() + host_state.interval_per_tick;
  870. }
  871. pCurrOverlay = pCurrOverlay->m_pNextOverlay;
  872. }
  873. OverlayText_t* pCurrText = s_pOverlayText;
  874. while (pCurrText)
  875. {
  876. if ( pCurrText->m_flEndTime == NDEBUG_PERSIST_TILL_NEXT_SERVER )
  877. {
  878. pCurrText->m_flEndTime = cl.GetTime() + host_state.interval_per_tick;
  879. }
  880. pCurrText = pCurrText->nextOverlayText;
  881. }
  882. }
  883. void PurgeTextOverlays( void )
  884. {
  885. AUTO_LOCK( s_OverlayMutex );
  886. OverlayText_t* pCurrOverlay = s_pOverlayText;
  887. while ( pCurrOverlay )
  888. {
  889. if ( pCurrOverlay->m_flEndTime == 0.0f &&
  890. pCurrOverlay->m_nCreationTick != -1 )
  891. {
  892. pCurrOverlay->m_nCreationTick = 0;
  893. }
  894. pCurrOverlay = pCurrOverlay->nextOverlayText;
  895. }
  896. }
  897. //-----------------------------------------------------------------------------
  898. // Purpose:
  899. // Input :
  900. // Output :
  901. //-----------------------------------------------------------------------------
  902. void Draw3DOverlays(void)
  903. {
  904. // Clear overlays every frame
  905. AUTO_LOCK( s_OverlayMutex );
  906. static int previous_servercount = 0;
  907. if ( previous_servercount != cl.m_nServerCount )
  908. {
  909. ClearAllOverlays();
  910. previous_servercount = cl.m_nServerCount;
  911. }
  912. DrawAllOverlays();
  913. if (s_bDrawGrid)
  914. {
  915. DrawGridOverlay();
  916. }
  917. }
  918. //------------------------------------------------------------------------------
  919. // Purpose : Deletes all overlays
  920. // Input :
  921. // Output :
  922. //------------------------------------------------------------------------------
  923. void ClearAllOverlays(void)
  924. {
  925. AUTO_LOCK( s_OverlayMutex );
  926. while (s_pOverlays)
  927. {
  928. OverlayBase_t *pOldOverlay = s_pOverlays;
  929. s_pOverlays = s_pOverlays->m_pNextOverlay;
  930. DestroyOverlay( pOldOverlay );
  931. }
  932. while (s_pOverlayText)
  933. {
  934. OverlayText_t *cur_ol = s_pOverlayText;
  935. s_pOverlayText = s_pOverlayText->nextOverlayText;
  936. delete cur_ol;
  937. }
  938. s_bDrawGrid = false;
  939. }
  940. void ClearDeadOverlays( void )
  941. {
  942. AUTO_LOCK( s_OverlayMutex );
  943. OverlayText_t* pCurrText = s_pOverlayText;
  944. OverlayText_t* pLastText = NULL;
  945. OverlayText_t* pNextText = NULL;
  946. while (pCurrText)
  947. {
  948. // Is it time to kill this Text?
  949. if ( pCurrText->IsDead() )
  950. {
  951. // If I had a last Text reset it's next pointer
  952. if (pLastText)
  953. {
  954. pLastText->nextOverlayText = pCurrText->nextOverlayText;
  955. }
  956. // If the first Text, reset the s_pOverlayText pointer
  957. else
  958. {
  959. s_pOverlayText = pCurrText->nextOverlayText;
  960. }
  961. pNextText = pCurrText->nextOverlayText;
  962. delete pCurrText;
  963. pCurrText = pNextText;
  964. }
  965. else
  966. {
  967. pLastText = pCurrText;
  968. pCurrText = pCurrText->nextOverlayText;
  969. }
  970. }
  971. }
  972. } // end namespace CDebugOverlay
  973. //-----------------------------------------------------------------------------
  974. // Purpose: export debug overlay to client DLL
  975. // Input :
  976. // Output :
  977. //-----------------------------------------------------------------------------
  978. class CIVDebugOverlay : public IVDebugOverlay, public IVPhysicsDebugOverlay
  979. {
  980. private:
  981. char m_text[1024];
  982. va_list m_argptr;
  983. public:
  984. void AddEntityTextOverlay(int ent_index, int line_offset, float duration, int r, int g, int b, int a, const char *format, ...)
  985. {
  986. va_start( m_argptr, format );
  987. Q_vsnprintf( m_text, sizeof( m_text ), format, m_argptr );
  988. va_end( m_argptr );
  989. CDebugOverlay::AddEntityTextOverlay(ent_index, line_offset, duration, r, g, b, a, m_text);
  990. }
  991. void AddBoxOverlay(const Vector& origin, const Vector& mins, const Vector& max, QAngle const& angles, int r, int g, int b, int a, float duration)
  992. {
  993. CDebugOverlay::AddBoxOverlay(origin, mins, max, angles, r, g, b, a, duration);
  994. }
  995. void AddSweptBoxOverlay(const Vector& start, const Vector& end, const Vector& mins, const Vector& max, const QAngle & angles, int r, int g, int b, int a, float flDuration)
  996. {
  997. CDebugOverlay::AddSweptBoxOverlay(start, end, mins, max, angles, r, g, b, a, flDuration);
  998. }
  999. void AddLineOverlay(const Vector& origin, const Vector& dest, int r, int g, int b, bool noDepthTest, float duration)
  1000. {
  1001. CDebugOverlay::AddLineOverlay(origin, dest, r, g, b, 255, noDepthTest, duration);
  1002. }
  1003. void AddTriangleOverlay(const Vector& p1, const Vector& p2, const Vector &p3, int r, int g, int b, int a, bool noDepthTest, float duration)
  1004. {
  1005. CDebugOverlay::AddTriangleOverlay(p1, p2, p3, r, g, b, a, noDepthTest, duration);
  1006. }
  1007. void AddTextOverlay(const Vector& origin, float duration, const char *format, ...)
  1008. {
  1009. va_start( m_argptr, format );
  1010. Q_vsnprintf( m_text, sizeof( m_text ), format, m_argptr );
  1011. va_end( m_argptr );
  1012. CDebugOverlay::AddTextOverlay(origin, duration, m_text);
  1013. }
  1014. void AddTextOverlay(const Vector& origin, int line_offset, float duration, const char *format, ...)
  1015. {
  1016. va_start( m_argptr, format );
  1017. Q_vsnprintf( m_text, sizeof( m_text ), format, m_argptr );
  1018. va_end( m_argptr );
  1019. CDebugOverlay::AddTextOverlay(origin, line_offset, duration, m_text);
  1020. }
  1021. void AddTextOverlayRGB(const Vector& origin, int line_offset, float duration, float r, float g, float b, float alpha, const char *format, ...)
  1022. {
  1023. va_start( m_argptr, format );
  1024. Q_vsnprintf( m_text, sizeof( m_text ), format, m_argptr );
  1025. va_end( m_argptr );
  1026. CDebugOverlay::AddTextOverlay(origin, line_offset, duration, r, g, b, alpha, m_text);
  1027. }
  1028. void AddTextOverlayRGB(const Vector& origin, int line_offset, float flDuration, int r, int g, int b, int alpha, const char *format, ...)
  1029. {
  1030. va_start( m_argptr, format );
  1031. Q_vsnprintf( m_text, sizeof( m_text ), format, m_argptr );
  1032. va_end( m_argptr );
  1033. CDebugOverlay::AddTextOverlay( origin, line_offset, flDuration, r * 1.0f/255.0f, g * 1.0f/255.0f, b * 1.0f/255.0f, alpha * 1.0f/255.0f, m_text );
  1034. }
  1035. void AddScreenTextOverlay(float flXPos, float flYPos,float flDuration, int r, int g, int b, int a, const char *text)
  1036. {
  1037. CDebugOverlay::AddScreenTextOverlay( flXPos, flYPos, flDuration, r, g, b, a, text );
  1038. }
  1039. void AddGridOverlay(const Vector& origin)
  1040. {
  1041. CDebugOverlay::AddGridOverlay( origin );
  1042. }
  1043. void AddCoordFrameOverlay(const matrix3x4_t& frame, float flScale, int vColorTable[3][3] = NULL)
  1044. {
  1045. CDebugOverlay::AddCoordFrameOverlay( frame, flScale, vColorTable );
  1046. }
  1047. int ScreenPosition(const Vector& point, Vector& screen)
  1048. {
  1049. return CDebugOverlay::ScreenPosition( point, screen );
  1050. }
  1051. int ScreenPosition(float flXPos, float flYPos, Vector& screen)
  1052. {
  1053. return CDebugOverlay::ScreenPosition( flXPos, flYPos, screen );
  1054. }
  1055. virtual OverlayText_t *GetFirst( void )
  1056. {
  1057. return CDebugOverlay::s_pOverlayText;
  1058. }
  1059. virtual OverlayText_t *GetNext( OverlayText_t *current )
  1060. {
  1061. return current->nextOverlayText;
  1062. }
  1063. virtual void ClearDeadOverlays( void )
  1064. {
  1065. CDebugOverlay::ClearDeadOverlays();
  1066. }
  1067. virtual void ClearAllOverlays()
  1068. {
  1069. CDebugOverlay::ClearAllOverlays();
  1070. }
  1071. void AddLineOverlayAlpha(const Vector& origin, const Vector& dest, int r, int g, int b, int a, bool noDepthTest, float duration)
  1072. {
  1073. CDebugOverlay::AddLineOverlay(origin, dest, r, g, b, a, noDepthTest, duration);
  1074. }
  1075. void AddBoxOverlay2( const Vector& origin, const Vector& mins, const Vector& maxs, QAngle const& orientation, const Color& faceColor, const Color& edgeColor, float duration )
  1076. {
  1077. CDebugOverlay::AddBoxOverlay2(origin, mins, maxs, orientation, faceColor, edgeColor, duration );
  1078. }
  1079. void PurgeTextOverlays()
  1080. {
  1081. CDebugOverlay::PurgeTextOverlays();
  1082. }
  1083. };
  1084. static CIVDebugOverlay g_DebugOverlay;
  1085. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CIVDebugOverlay, IVDebugOverlay, VDEBUG_OVERLAY_INTERFACE_VERSION, g_DebugOverlay );
  1086. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CIVDebugOverlay, IVPhysicsDebugOverlay, VPHYSICS_DEBUG_OVERLAY_INTERFACE_VERSION, g_DebugOverlay );