source-engine/engine/debugoverlay.cpp

1309 lines
34 KiB
C++
Raw Permalink Normal View History

2020-04-22 16:56:21 +00:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Debugging overlay functions
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//===========================================================================//
#include "render_pch.h"
#include "edict.h"
#include "client.h"
#include "debugoverlay.h"
#include "cdll_int.h"
#include "ivideomode.h"
#include "materialsystem/imesh.h"
#include "gl_matsysiface.h"
#include "server.h"
#include "client_class.h"
#include "icliententitylist.h"
#include "mathlib/vmatrix.h"
#include "icliententity.h"
#include "overlaytext.h"
#include "engine/ivdebugoverlay.h"
#include "cmodel_engine.h"
#include "vphysics_interface.h"
#include "materialsystem/imaterial.h"
#include "tier2/renderutils.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern edict_t *EDICT_NUM(int n);
ConVar enable_debug_overlays( "enable_debug_overlays", "1", FCVAR_GAMEDLL | FCVAR_CHEAT, "Enable rendering of debug overlays" );
int GetOverlayTick()
{
if ( sv.IsActive() )
return sv.m_nTickCount;
return cl.GetClientTickCount();
}
bool OverlayText_t::IsDead()
{
if ( IsXbox() && cl.IsPaused() )
return false;
if ( m_nServerCount != cl.m_nServerCount )
return true;
if ( m_nCreationTick != -1 )
{
if ( GetOverlayTick() > m_nCreationTick )
return true;
return false;
}
if ( m_flEndTime == NDEBUG_PERSIST_TILL_NEXT_SERVER )
return false;
return (cl.GetTime() >= m_flEndTime);
}
void OverlayText_t::SetEndTime( float duration )
{
m_nServerCount = cl.m_nServerCount;
if ( duration <= 0.0f )
{
m_flEndTime = 0.0f;
m_nCreationTick = GetOverlayTick();
return;
}
if ( duration == NDEBUG_PERSIST_TILL_NEXT_SERVER )
{
m_flEndTime = NDEBUG_PERSIST_TILL_NEXT_SERVER;
}
else
{
m_flEndTime = cl.GetTime() + duration;
}
}
namespace CDebugOverlay
{
enum OverlayType_t
{
OVERLAY_BOX = 0,
OVERLAY_SPHERE,
OVERLAY_LINE,
OVERLAY_TRIANGLE,
OVERLAY_SWEPT_BOX,
OVERLAY_BOX2
};
struct OverlayBase_t
{
OverlayBase_t()
{
m_Type = OVERLAY_BOX;
m_nServerCount = -1;
m_nCreationTick = -1;
m_flEndTime = 0.0f;
m_pNextOverlay = NULL;
}
bool IsDead()
{
if ( IsXbox() && cl.IsPaused() )
return false;
if ( m_nServerCount != cl.m_nServerCount )
return true;
if ( m_nCreationTick != -1 )
{
if ( GetOverlayTick() > m_nCreationTick )
return true;
return false;
}
if ( m_flEndTime == NDEBUG_PERSIST_TILL_NEXT_SERVER )
return false;
return (cl.GetTime() >= m_flEndTime) ;
}
void SetEndTime( float duration )
{
m_nServerCount = cl.m_nServerCount;
if ( duration <= 0.0f )
{
m_nCreationTick = GetOverlayTick(); // stay alive for only one frame
return;
}
if ( duration == NDEBUG_PERSIST_TILL_NEXT_SERVER )
{
m_flEndTime = NDEBUG_PERSIST_TILL_NEXT_SERVER;
}
else
{
m_flEndTime = cl.GetTime() + duration;
}
}
OverlayType_t m_Type; // What type of overlay is it?
int m_nCreationTick; // Duration -1 means go away after this frame #
int m_nServerCount; // Latch server count, too
float m_flEndTime; // When does this box go away
OverlayBase_t *m_pNextOverlay;
};
struct OverlayBox_t : public OverlayBase_t
{
OverlayBox_t() { m_Type = OVERLAY_BOX; }
Vector origin;
Vector mins;
Vector maxs;
QAngle angles;
int r;
int g;
int b;
int a;
};
struct OverlayBox2_t : public OverlayBase_t
{
OverlayBox2_t() { m_Type = OVERLAY_BOX2; }
Vector origin;
Vector mins;
Vector maxs;
QAngle angles;
Color edgeColor;
Color faceColor;
};
struct OverlaySphere_t : public OverlayBase_t
{
OverlaySphere_t() { m_Type = OVERLAY_SPHERE; }
Vector vOrigin;
float flRadius;
int nTheta;
int nPhi;
int r;
int g;
int b;
int a;
};
struct OverlayLine_t : public OverlayBase_t
{
OverlayLine_t() { m_Type = OVERLAY_LINE; }
Vector origin;
Vector dest;
int r;
int g;
int b;
int a;
bool noDepthTest;
};
struct OverlayTriangle_t : public OverlayBase_t
{
OverlayTriangle_t() { m_Type = OVERLAY_TRIANGLE; }
Vector p1;
Vector p2;
Vector p3;
int r;
int g;
int b;
int a;
bool noDepthTest;
};
struct OverlaySweptBox_t : public OverlayBase_t
{
OverlaySweptBox_t() { m_Type = OVERLAY_SWEPT_BOX; }
Vector start;
Vector end;
Vector mins;
Vector maxs;
QAngle angles;
int r;
int g;
int b;
int a;
};
//-----------------------------------------------------------------------------
// Forward declarations
//-----------------------------------------------------------------------------
void DrawOverlays();
void DrawGridOverlay();
void ClearAllOverlays();
void ClearDeadOverlays();
//-----------------------------------------------------------------------------
// Init static member variables
//-----------------------------------------------------------------------------
OverlayText_t* s_pOverlayText = NULL; // text is handled differently; for backward compatibility reasons
OverlayBase_t* s_pOverlays = NULL;
Vector s_vGridPosition(0,0,0);
bool s_bDrawGrid = false;
CThreadFastMutex s_OverlayMutex;
//-----------------------------------------------------------------------------
// Purpose: Hack to allow this code to run on a client that's not connected to a server
// (i.e., demo playback, or multiplayer game )
// Input : ent_num -
// origin -
// mins -
// maxs -
// Output : static void
//-----------------------------------------------------------------------------
static bool GetEntityOriginClientOrServer( int ent_num, Vector& origin )
{
AUTO_LOCK( s_OverlayMutex );
// Assume failure
origin.Init();
if ( sv.IsActive() )
{
edict_t *e = EDICT_NUM( ent_num );
if ( e )
{
IServerEntity *serverEntity = e->GetIServerEntity();
if ( serverEntity )
{
CM_WorldSpaceCenter( serverEntity->GetCollideable(), &origin );
}
return true;
}
}
else
{
IClientEntity *clent = entitylist->GetClientEntity( ent_num );
if ( clent )
{
CM_WorldSpaceCenter( clent->GetCollideable(), &origin );
return true;
}
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose: Given a point, return the screen position
// Input :
// Output :
//-----------------------------------------------------------------------------
int ScreenPosition(const Vector& point, Vector& screen)
{
AUTO_LOCK( s_OverlayMutex );
CMatRenderContextPtr pRenderContext( materials );
int retval = g_EngineRenderer->ClipTransform(point,&screen);
int x, y, w, h;
pRenderContext->GetViewport( x, y, w, h );
screen[0] = 0.5 * screen[0] * w;
screen[1] = -0.5 * screen[1] * h;
screen[0] += 0.5 * w;
screen[1] += 0.5 * h;
return retval;
}
//-----------------------------------------------------------------------------
// Purpose: Given an xy screen pos (0-1), return the screen position
// Input :
// Output :
//-----------------------------------------------------------------------------
int ScreenPosition(float flXPos, float flYPos, Vector& screen)
{
if (flXPos > 1.0 || flYPos > 1.0 || flXPos < 0.0 || flYPos < 0.0 )
return 1; // Fail
AUTO_LOCK( s_OverlayMutex );
CMatRenderContextPtr pRenderContext( materials );
int x, y, w, h;
pRenderContext->GetViewport( x, y, w, h );
screen[0] = flXPos * w;
screen[1] = flYPos * h;
return 0;
}
//-----------------------------------------------------------------------------
// Purpose: Add new entity positioned overlay text
// Input : Entity to attach text to
// How many lines to offset text from entity origin
// The text to print
// Output :
//-----------------------------------------------------------------------------
void AddEntityTextOverlay(int ent_index, int line_offset, float duration, int r, int g, int b, int a, const char *text)
{
if ( cl.IsPaused() )
return;
AUTO_LOCK( s_OverlayMutex );
OverlayText_t *new_overlay = new OverlayText_t;
Vector myPos, myMins, myMaxs;
GetEntityOriginClientOrServer( ent_index, myPos );
VectorCopy(myPos,new_overlay->origin);
Q_strncpy(new_overlay->text,text, sizeof( new_overlay->text ) );
new_overlay->bUseOrigin = true;
new_overlay->lineOffset = line_offset;
new_overlay->SetEndTime( duration );
new_overlay->r = r;
new_overlay->g = g;
new_overlay->b = b;
new_overlay->a = a;
new_overlay->nextOverlayText = s_pOverlayText;
s_pOverlayText = new_overlay;
}
//-----------------------------------------------------------------------------
// Purpose: Add new overlay text
// Input : Position of text & text
// Output :
//-----------------------------------------------------------------------------
void AddGridOverlay(const Vector& vPos)
{
if ( cl.IsPaused() )
return;
AUTO_LOCK( s_OverlayMutex );
s_vGridPosition[0] = vPos[0];
s_vGridPosition[1] = vPos[1];
s_vGridPosition[2] = vPos[2];
s_bDrawGrid = true;
}
void AddCoordFrameOverlay(const matrix3x4_t& frame, float flScale, int vColorTable[3][3]/*=NULL*/)
{
static int s_defaultColorTable[3][3] =
{
{ 255, 0, 0 },
{ 0 , 255, 0 },
{ 0 , 0, 255 }
};
AUTO_LOCK( s_OverlayMutex );
if ( vColorTable == NULL )
vColorTable = s_defaultColorTable;
Vector startPt, endPt;
MatrixGetColumn( frame, 3, startPt );
for (int k = 0; k < 3; k++)
{
endPt.x = frame[0][3] + frame[0][k] * flScale;
endPt.y = frame[1][3] + frame[1][k] * flScale;
endPt.z = frame[2][3] + frame[2][k] * flScale;
AddLineOverlay(
startPt,
endPt,
vColorTable[k][0], vColorTable[k][1], vColorTable[k][2], 255,
true,
NDEBUG_PERSIST_TILL_NEXT_SERVER
);
}
}
//-----------------------------------------------------------------------------
// Purpose: Add new overlay text
// Input : Position of text & text
// Output :
//-----------------------------------------------------------------------------
void AddTextOverlay(const Vector& textPos, float duration, const char *text)
{
if ( cl.IsPaused() )
return;
AUTO_LOCK( s_OverlayMutex );
OverlayText_t *new_overlay = new OverlayText_t;
VectorCopy(textPos,new_overlay->origin);
Q_strncpy(new_overlay->text,text, sizeof( new_overlay->text ) );
new_overlay->bUseOrigin = true;
new_overlay->lineOffset = 0;
new_overlay->SetEndTime( duration );
new_overlay->r = 255;
new_overlay->g = 255;
new_overlay->b = 255;
new_overlay->a = 255;
new_overlay->nextOverlayText = s_pOverlayText;
s_pOverlayText = new_overlay;
}
//-----------------------------------------------------------------------------
// Purpose: Add new overlay text
// Input : Position of text & text
// Output :
//-----------------------------------------------------------------------------
void AddTextOverlay(const Vector& textPos, float duration, float alpha, const char *text)
{
if ( cl.IsPaused() )
return;
AUTO_LOCK( s_OverlayMutex );
OverlayText_t *new_overlay = new OverlayText_t;
VectorCopy(textPos,new_overlay->origin);
Q_strncpy(new_overlay->text,text, sizeof( new_overlay->text ) );
new_overlay->bUseOrigin = true;
new_overlay->lineOffset = 0;
new_overlay->SetEndTime( duration );
new_overlay->r = 255;
new_overlay->g = 255;
new_overlay->b = 255;
new_overlay->a = (int)clamp(alpha * 255.f,0.f,255.f);
new_overlay->nextOverlayText = s_pOverlayText;
s_pOverlayText = new_overlay;
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void AddScreenTextOverlay(float flXPos, float flYPos, int line_offset, float duration, int r, int g, int b, int a, const char *text)
{
if ( cl.IsPaused() )
return;
AUTO_LOCK( s_OverlayMutex );
OverlayText_t *new_overlay = new OverlayText_t;
Q_strncpy(new_overlay->text,text, sizeof( new_overlay->text ) );
new_overlay->flXPos = flXPos;
new_overlay->flYPos = flYPos;
new_overlay->bUseOrigin = false;
new_overlay->lineOffset = line_offset;
new_overlay->SetEndTime( duration );
new_overlay->r = r;
new_overlay->g = g;
new_overlay->b = b;
new_overlay->a = a;
new_overlay->nextOverlayText = s_pOverlayText;
s_pOverlayText = new_overlay;
}
void AddScreenTextOverlay( float flXPos, float flYPos, float duration, int r, int g, int b, int a, const char *text )
{
AddScreenTextOverlay( flXPos, flYPos, 0, duration, r, g, b, a, text );
}
//-----------------------------------------------------------------------------
// Purpose: Add new overlay text
// Input : Position of text
// How many lines to offset text from position
// ext
// Output :
//-----------------------------------------------------------------------------
void AddTextOverlay(const Vector& textPos, int line_offset, float duration, const char *text)
{
if ( cl.IsPaused() )
return;
AUTO_LOCK( s_OverlayMutex );
OverlayText_t *new_overlay = new OverlayText_t;
VectorCopy(textPos,new_overlay->origin);
Q_strncpy(new_overlay->text,text, sizeof( new_overlay->text ) );
new_overlay->bUseOrigin = true;
new_overlay->lineOffset = line_offset;
new_overlay->SetEndTime( duration );
new_overlay->r = 255;
new_overlay->g = 255;
new_overlay->b = 255;
new_overlay->a = 255;
new_overlay->bUseOrigin = true;
new_overlay->nextOverlayText = s_pOverlayText;
s_pOverlayText = new_overlay;
}
void AddTextOverlay(const Vector& textPos, int line_offset, float duration, float alpha, const char *text)
{
if ( cl.IsPaused() )
return;
AUTO_LOCK( s_OverlayMutex );
OverlayText_t *new_overlay = new OverlayText_t;
VectorCopy(textPos,new_overlay->origin);
Q_strncpy(new_overlay->text,text, sizeof( new_overlay->text ) );
new_overlay->bUseOrigin = true;
new_overlay->lineOffset = line_offset;
new_overlay->SetEndTime( duration );
new_overlay->r = 255;
new_overlay->g = 255;
new_overlay->b = 255;
new_overlay->a = (int)clamp(alpha * 255.f,0.f,255.f);
new_overlay->bUseOrigin = true;
new_overlay->nextOverlayText = s_pOverlayText;
s_pOverlayText = new_overlay;
}
void AddTextOverlay(const Vector& textPos, int line_offset, float duration, float r, float g, float b, float alpha, const char *text)
{
if ( cl.IsPaused() )
return;
AUTO_LOCK( s_OverlayMutex );
OverlayText_t *new_overlay = new OverlayText_t;
VectorCopy(textPos,new_overlay->origin);
Q_strncpy(new_overlay->text,text, sizeof( new_overlay->text ) );
new_overlay->bUseOrigin = true;
new_overlay->lineOffset = line_offset;
new_overlay->SetEndTime( duration );
new_overlay->r = (int)clamp(r * 255.f,0.f,255.f);
new_overlay->g = (int)clamp(g * 255.f,0.f,255.f);
new_overlay->b = (int)clamp(b * 255.f,0.f,255.f);
new_overlay->a = (int)clamp(alpha * 255.f,0.f,255.f);
new_overlay->bUseOrigin = true;
new_overlay->nextOverlayText = s_pOverlayText;
s_pOverlayText = new_overlay;
}
//-----------------------------------------------------------------------------
// Purpose: Add new overlay box
// Input : Position of box
// size of box
// angles of box
// color & alpha
// duration
// Output :
//-----------------------------------------------------------------------------
void AddBoxOverlay(const Vector& origin, const Vector& mins, const Vector& maxs, QAngle const& angles, int r, int g, int b, int a, float flDuration)
{
if ( cl.IsPaused() )
return;
AUTO_LOCK( s_OverlayMutex );
OverlayBox_t *new_overlay = new OverlayBox_t;
new_overlay->origin = origin;
new_overlay->mins[0] = mins[0];
new_overlay->mins[1] = mins[1];
new_overlay->mins[2] = mins[2];
new_overlay->maxs[0] = maxs[0];
new_overlay->maxs[1] = maxs[1];
new_overlay->maxs[2] = maxs[2];
new_overlay->angles = angles;
new_overlay->r = r;
new_overlay->g = g;
new_overlay->b = b;
new_overlay->a = a;
new_overlay->SetEndTime( flDuration );
new_overlay->m_pNextOverlay = s_pOverlays;
s_pOverlays = new_overlay;
}
void AddBoxOverlay2( const Vector& origin, const Vector& mins, const Vector& maxs, QAngle const& orientation, const Color& faceColor, const Color& edgeColor, float duration )
{
if ( cl.IsPaused() )
return;
AUTO_LOCK( s_OverlayMutex );
OverlayBox2_t *new_overlay = new OverlayBox2_t;
new_overlay->origin = origin;
new_overlay->mins[0] = mins[0];
new_overlay->mins[1] = mins[1];
new_overlay->mins[2] = mins[2];
new_overlay->maxs[0] = maxs[0];
new_overlay->maxs[1] = maxs[1];
new_overlay->maxs[2] = maxs[2];
new_overlay->angles = orientation;
new_overlay->faceColor = faceColor;
new_overlay->edgeColor = edgeColor;
new_overlay->SetEndTime( duration );
new_overlay->m_pNextOverlay = s_pOverlays;
s_pOverlays = new_overlay;
}
//-----------------------------------------------------------------------------
// Purpose: Add new overlay sphere
// Input : Position of sphere
// radius of sphere
// color & alpha
// duration
// Output :
//-----------------------------------------------------------------------------
void AddSphereOverlay(const Vector& vOrigin, float flRadius, int nTheta, int nPhi, int r, int g, int b, int a, float flDuration)
{
if ( cl.IsPaused() )
return;
AUTO_LOCK( s_OverlayMutex );
OverlaySphere_t *new_overlay = new OverlaySphere_t;
new_overlay->vOrigin = vOrigin;
new_overlay->flRadius = flRadius;
new_overlay->nTheta = nTheta;
new_overlay->nPhi = nPhi;
new_overlay->r = r;
new_overlay->g = g;
new_overlay->b = b;
new_overlay->a = a;
new_overlay->SetEndTime( flDuration );
new_overlay->m_pNextOverlay = s_pOverlays;
s_pOverlays = new_overlay;
}
void AddSweptBoxOverlay(const Vector& start, const Vector& end,
const Vector& mins, const Vector& maxs, QAngle const& angles, int r, int g, int b, int a, float flDuration)
{
if ( cl.IsPaused() )
return;
AUTO_LOCK( s_OverlayMutex );
OverlaySweptBox_t *new_overlay = new OverlaySweptBox_t;
new_overlay->start = start;
new_overlay->end = end;
new_overlay->mins[0] = mins[0];
new_overlay->mins[1] = mins[1];
new_overlay->mins[2] = mins[2];
new_overlay->maxs[0] = maxs[0];
new_overlay->maxs[1] = maxs[1];
new_overlay->maxs[2] = maxs[2];
new_overlay->angles = angles;
new_overlay->r = r;
new_overlay->g = g;
new_overlay->b = b;
new_overlay->a = a;
new_overlay->SetEndTime( flDuration );
new_overlay->m_pNextOverlay = s_pOverlays;
s_pOverlays = new_overlay;
}
//-----------------------------------------------------------------------------
// Purpose: Add new overlay text
// Input : Entity to attach text to
// How many lines to offset text from entity origin
// The text to print
// Output :
//-----------------------------------------------------------------------------
void AddLineOverlay(const Vector& origin, const Vector& dest, int r, int g, int b, int a, bool noDepthTest, float flDuration)
{
if ( cl.IsPaused() )
return;
AUTO_LOCK( s_OverlayMutex );
OverlayLine_t *new_loverlay = new OverlayLine_t;
new_loverlay->origin[0] = origin[0];
new_loverlay->origin[1] = origin[1];
new_loverlay->origin[2] = origin[2];
new_loverlay->dest[0] = dest[0];
new_loverlay->dest[1] = dest[1];
new_loverlay->dest[2] = dest[2];
new_loverlay->r = r;
new_loverlay->g = g;
new_loverlay->b = b;
new_loverlay->a = a;
new_loverlay->noDepthTest = noDepthTest;
new_loverlay->SetEndTime( flDuration );
new_loverlay->m_pNextOverlay = s_pOverlays;
s_pOverlays = new_loverlay;
}
//-----------------------------------------------------------------------------
// Purpose: Add new triangle overlay
//-----------------------------------------------------------------------------
void AddTriangleOverlay(const Vector& p1, const Vector& p2, const Vector &p3,
int r, int g, int b, int a, bool noDepthTest, float flDuration)
{
if ( cl.IsPaused() )
return;
AUTO_LOCK( s_OverlayMutex );
OverlayTriangle_t *pTriangle = new OverlayTriangle_t;
pTriangle->p1 = p1;
pTriangle->p2 = p2;
pTriangle->p3 = p3;
pTriangle->r = r;
pTriangle->g = g;
pTriangle->b = b;
pTriangle->a = a;
pTriangle->noDepthTest = noDepthTest;
pTriangle->SetEndTime( flDuration );
pTriangle->m_pNextOverlay = s_pOverlays;
s_pOverlays = pTriangle;
}
//------------------------------------------------------------------------------
// Purpose : Draw a grid around the s_vGridPosition
// Input :
// Output :
//------------------------------------------------------------------------------
void DrawGridOverlay(void)
{
AUTO_LOCK( s_OverlayMutex );
static int gridSpacing = 100;
static int numHorzSpaces = 16;
static int numVertSpaces = 3;
Vector startGrid;
startGrid[0] = gridSpacing*((int)s_vGridPosition[0]/gridSpacing);
startGrid[1] = gridSpacing*((int)s_vGridPosition[1]/gridSpacing);
startGrid[2] = s_vGridPosition[2];
// Shift to the left
startGrid[0] -= (numHorzSpaces/2)*gridSpacing;
startGrid[1] -= (numHorzSpaces/2)*gridSpacing;
Vector color( 20, 180, 190 );
for (int i=1;i<numVertSpaces+1;i++)
{
// Draw x axis lines
Vector startLine;
VectorCopy(startGrid,startLine);
for (int j=0;j<numHorzSpaces+1;j++)
{
Vector endLine;
VectorCopy(startLine,endLine);
endLine[0] += gridSpacing*numHorzSpaces;
RenderLine( startLine, endLine, Color( color.x, color.y, color.z, 255 ), true );
Vector bottomStartLine;
VectorCopy(startLine,bottomStartLine);
for ( int k=0; k<numHorzSpaces+1; k++ )
{
Vector bottomEndLine;
VectorCopy(bottomStartLine,bottomEndLine);
bottomEndLine[2] -= gridSpacing;
RenderLine( bottomStartLine, bottomEndLine, Color( color.x, color.y, color.z, 255 ), true );
bottomStartLine[0] += gridSpacing;
}
startLine[1] += gridSpacing;
}
// Draw y axis lines
VectorCopy(startGrid,startLine);
for ( int j=0; j<numHorzSpaces+1; j++ )
{
Vector endLine;
VectorCopy(startLine,endLine);
endLine[1] += gridSpacing*numHorzSpaces;
RenderLine( startLine, endLine, Color( color.x, color.y, color.z, 255 ), true );
startLine[0] += gridSpacing;
}
VectorScale( color, 0.7, color );
startGrid[2] -= gridSpacing;
}
s_bDrawGrid = false;
}
//------------------------------------------------------------------------------
// Draws a generic overlay
//------------------------------------------------------------------------------
void DrawOverlay( OverlayBase_t *pOverlay )
{
AUTO_LOCK( s_OverlayMutex );
switch( pOverlay->m_Type)
{
case OVERLAY_LINE:
{
// Draw the line
OverlayLine_t *pLine = static_cast<OverlayLine_t*>(pOverlay);
RenderLine( pLine->origin, pLine->dest, Color( pLine->r, pLine->g, pLine->b, pLine->a ), !pLine->noDepthTest);
}
break;
case OVERLAY_BOX:
{
// Draw the box
OverlayBox_t *pCurrBox = static_cast<OverlayBox_t*>(pOverlay);
if ( pCurrBox->a > 0 )
{
RenderBox( pCurrBox->origin, pCurrBox->angles, pCurrBox->mins, pCurrBox->maxs, Color( pCurrBox->r, pCurrBox->g, pCurrBox->b, pCurrBox->a ), false );
}
RenderWireframeBox( pCurrBox->origin, pCurrBox->angles, pCurrBox->mins, pCurrBox->maxs, Color( pCurrBox->r, pCurrBox->g, pCurrBox->b, 255 ), true );
}
break;
case OVERLAY_BOX2:
{
// Draw the box
OverlayBox2_t *pCurrBox = static_cast<OverlayBox2_t*>(pOverlay);
if ( pCurrBox->faceColor.a() > 0 )
{
RenderBox( pCurrBox->origin, pCurrBox->angles, pCurrBox->mins, pCurrBox->maxs, pCurrBox->faceColor, false );
}
if ( pCurrBox->edgeColor.a() > 0 )
{
RenderWireframeBox( pCurrBox->origin, pCurrBox->angles, pCurrBox->mins, pCurrBox->maxs, pCurrBox->edgeColor, false );
}
}
break;
case OVERLAY_SPHERE:
{
// Draw the sphere
OverlaySphere_t *pSphere = static_cast<OverlaySphere_t*>(pOverlay);
RenderSphere( pSphere->vOrigin, pSphere->flRadius, pSphere->nTheta, pSphere->nPhi, Color( pSphere->r, pSphere->g, pSphere->b, pSphere->a ), g_pMaterialAmbientCube );
}
break;
case OVERLAY_SWEPT_BOX:
{
OverlaySweptBox_t *pBox = static_cast<OverlaySweptBox_t*>(pOverlay);
RenderWireframeSweptBox( pBox->start, pBox->end, pBox->angles, pBox->mins, pBox->maxs, Color( pBox->r, pBox->g, pBox->b, pBox->a ), true );
}
break;
case OVERLAY_TRIANGLE:
{
OverlayTriangle_t *pTriangle = static_cast<OverlayTriangle_t*>(pOverlay);
RenderTriangle( pTriangle->p1, pTriangle->p2, pTriangle->p3,
Color( pTriangle->r, pTriangle->g, pTriangle->b, pTriangle->a ), !pTriangle->noDepthTest );
}
break;
default:
Assert(0);
}
}
void DestroyOverlay( OverlayBase_t *pOverlay )
{
AUTO_LOCK( s_OverlayMutex );
switch( pOverlay->m_Type)
{
case OVERLAY_LINE:
{
OverlayLine_t *pCurrLine = static_cast<OverlayLine_t*>(pOverlay);
delete pCurrLine;
}
break;
case OVERLAY_BOX:
{
OverlayBox_t *pCurrBox = static_cast<OverlayBox_t*>(pOverlay);
delete pCurrBox;
}
break;
case OVERLAY_BOX2:
{
OverlayBox2_t *pCurrBox = static_cast<OverlayBox2_t*>(pOverlay);
delete pCurrBox;
}
break;
case OVERLAY_SPHERE:
{
OverlaySphere_t *pCurrSphere = static_cast<OverlaySphere_t*>(pOverlay);
delete pCurrSphere;
}
break;
case OVERLAY_SWEPT_BOX:
{
OverlaySweptBox_t *pCurrBox = static_cast<OverlaySweptBox_t*>(pOverlay);
delete pCurrBox;
}
break;
case OVERLAY_TRIANGLE:
{
OverlayTriangle_t *pTriangle = static_cast<OverlayTriangle_t*>(pOverlay);
delete pTriangle;
}
break;
default:
Assert(0);
}
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void DrawAllOverlays(void)
{
if ( !enable_debug_overlays.GetBool() )
return;
AUTO_LOCK( s_OverlayMutex );
OverlayBase_t* pCurrOverlay = s_pOverlays;
OverlayBase_t* pPrevOverlay = NULL;
OverlayBase_t* pNextOverlay;
while (pCurrOverlay)
{
// Is it time to kill this overlay?
if ( pCurrOverlay->IsDead() )
{
if (pPrevOverlay)
{
// If I had a last overlay reset it's next pointer
pPrevOverlay->m_pNextOverlay = pCurrOverlay->m_pNextOverlay;
}
else
{
// If the first line, reset the s_pOverlays pointer
s_pOverlays = pCurrOverlay->m_pNextOverlay;
}
pNextOverlay = pCurrOverlay->m_pNextOverlay;
DestroyOverlay( pCurrOverlay );
pCurrOverlay = pNextOverlay;
}
else
{
DrawOverlay( pCurrOverlay );
pPrevOverlay = pCurrOverlay;
pCurrOverlay = pCurrOverlay->m_pNextOverlay;
}
}
}
//------------------------------------------------------------------------------
// Purpose : Remove from the linkedlist overlays that have the special "until next
// server tick" frametime
// Input :
// Output :
//------------------------------------------------------------------------------
//0.01234f
void PurgeServerOverlays( void )
{
AUTO_LOCK( s_OverlayMutex );
OverlayBase_t* pCurrOverlay = s_pOverlays;
while (pCurrOverlay)
{
if ( pCurrOverlay->m_flEndTime == NDEBUG_PERSIST_TILL_NEXT_SERVER )
{
pCurrOverlay->m_flEndTime = cl.GetTime() + host_state.interval_per_tick;
}
pCurrOverlay = pCurrOverlay->m_pNextOverlay;
}
OverlayText_t* pCurrText = s_pOverlayText;
while (pCurrText)
{
if ( pCurrText->m_flEndTime == NDEBUG_PERSIST_TILL_NEXT_SERVER )
{
pCurrText->m_flEndTime = cl.GetTime() + host_state.interval_per_tick;
}
pCurrText = pCurrText->nextOverlayText;
}
}
void PurgeTextOverlays( void )
{
AUTO_LOCK( s_OverlayMutex );
OverlayText_t* pCurrOverlay = s_pOverlayText;
while ( pCurrOverlay )
{
if ( pCurrOverlay->m_flEndTime == 0.0f &&
pCurrOverlay->m_nCreationTick != -1 )
{
pCurrOverlay->m_nCreationTick = 0;
}
pCurrOverlay = pCurrOverlay->nextOverlayText;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
void Draw3DOverlays(void)
{
// Clear overlays every frame
AUTO_LOCK( s_OverlayMutex );
static int previous_servercount = 0;
if ( previous_servercount != cl.m_nServerCount )
{
ClearAllOverlays();
previous_servercount = cl.m_nServerCount;
}
DrawAllOverlays();
if (s_bDrawGrid)
{
DrawGridOverlay();
}
}
//------------------------------------------------------------------------------
// Purpose : Deletes all overlays
// Input :
// Output :
//------------------------------------------------------------------------------
void ClearAllOverlays(void)
{
AUTO_LOCK( s_OverlayMutex );
while (s_pOverlays)
{
OverlayBase_t *pOldOverlay = s_pOverlays;
s_pOverlays = s_pOverlays->m_pNextOverlay;
DestroyOverlay( pOldOverlay );
}
while (s_pOverlayText)
{
OverlayText_t *cur_ol = s_pOverlayText;
s_pOverlayText = s_pOverlayText->nextOverlayText;
delete cur_ol;
}
s_bDrawGrid = false;
}
void ClearDeadOverlays( void )
{
AUTO_LOCK( s_OverlayMutex );
OverlayText_t* pCurrText = s_pOverlayText;
OverlayText_t* pLastText = NULL;
OverlayText_t* pNextText = NULL;
while (pCurrText)
{
// Is it time to kill this Text?
if ( pCurrText->IsDead() )
{
// If I had a last Text reset it's next pointer
if (pLastText)
{
pLastText->nextOverlayText = pCurrText->nextOverlayText;
}
// If the first Text, reset the s_pOverlayText pointer
else
{
s_pOverlayText = pCurrText->nextOverlayText;
}
pNextText = pCurrText->nextOverlayText;
delete pCurrText;
pCurrText = pNextText;
}
else
{
pLastText = pCurrText;
pCurrText = pCurrText->nextOverlayText;
}
}
}
} // end namespace CDebugOverlay
//-----------------------------------------------------------------------------
// Purpose: export debug overlay to client DLL
// Input :
// Output :
//-----------------------------------------------------------------------------
class CIVDebugOverlay : public IVDebugOverlay, public IVPhysicsDebugOverlay
{
private:
char m_text[1024];
va_list m_argptr;
public:
void AddEntityTextOverlay(int ent_index, int line_offset, float duration, int r, int g, int b, int a, const char *format, ...)
{
va_start( m_argptr, format );
Q_vsnprintf( m_text, sizeof( m_text ), format, m_argptr );
va_end( m_argptr );
CDebugOverlay::AddEntityTextOverlay(ent_index, line_offset, duration, r, g, b, a, m_text);
}
void AddBoxOverlay(const Vector& origin, const Vector& mins, const Vector& max, QAngle const& angles, int r, int g, int b, int a, float duration)
{
CDebugOverlay::AddBoxOverlay(origin, mins, max, angles, r, g, b, a, duration);
}
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)
{
CDebugOverlay::AddSweptBoxOverlay(start, end, mins, max, angles, r, g, b, a, flDuration);
}
void AddLineOverlay(const Vector& origin, const Vector& dest, int r, int g, int b, bool noDepthTest, float duration)
{
CDebugOverlay::AddLineOverlay(origin, dest, r, g, b, 255, noDepthTest, duration);
}
void AddTriangleOverlay(const Vector& p1, const Vector& p2, const Vector &p3, int r, int g, int b, int a, bool noDepthTest, float duration)
{
CDebugOverlay::AddTriangleOverlay(p1, p2, p3, r, g, b, a, noDepthTest, duration);
}
void AddTextOverlay(const Vector& origin, float duration, const char *format, ...)
{
va_start( m_argptr, format );
Q_vsnprintf( m_text, sizeof( m_text ), format, m_argptr );
va_end( m_argptr );
CDebugOverlay::AddTextOverlay(origin, duration, m_text);
}
void AddTextOverlay(const Vector& origin, int line_offset, float duration, const char *format, ...)
{
va_start( m_argptr, format );
Q_vsnprintf( m_text, sizeof( m_text ), format, m_argptr );
va_end( m_argptr );
CDebugOverlay::AddTextOverlay(origin, line_offset, duration, m_text);
}
void AddTextOverlayRGB(const Vector& origin, int line_offset, float duration, float r, float g, float b, float alpha, const char *format, ...)
{
va_start( m_argptr, format );
Q_vsnprintf( m_text, sizeof( m_text ), format, m_argptr );
va_end( m_argptr );
CDebugOverlay::AddTextOverlay(origin, line_offset, duration, r, g, b, alpha, m_text);
}
void AddTextOverlayRGB(const Vector& origin, int line_offset, float flDuration, int r, int g, int b, int alpha, const char *format, ...)
{
va_start( m_argptr, format );
Q_vsnprintf( m_text, sizeof( m_text ), format, m_argptr );
va_end( m_argptr );
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 );
}
void AddScreenTextOverlay(float flXPos, float flYPos,float flDuration, int r, int g, int b, int a, const char *text)
{
CDebugOverlay::AddScreenTextOverlay( flXPos, flYPos, flDuration, r, g, b, a, text );
}
void AddGridOverlay(const Vector& origin)
{
CDebugOverlay::AddGridOverlay( origin );
}
void AddCoordFrameOverlay(const matrix3x4_t& frame, float flScale, int vColorTable[3][3] = NULL)
{
CDebugOverlay::AddCoordFrameOverlay( frame, flScale, vColorTable );
}
int ScreenPosition(const Vector& point, Vector& screen)
{
return CDebugOverlay::ScreenPosition( point, screen );
}
int ScreenPosition(float flXPos, float flYPos, Vector& screen)
{
return CDebugOverlay::ScreenPosition( flXPos, flYPos, screen );
}
virtual OverlayText_t *GetFirst( void )
{
return CDebugOverlay::s_pOverlayText;
}
virtual OverlayText_t *GetNext( OverlayText_t *current )
{
return current->nextOverlayText;
}
virtual void ClearDeadOverlays( void )
{
CDebugOverlay::ClearDeadOverlays();
}
virtual void ClearAllOverlays()
{
CDebugOverlay::ClearAllOverlays();
}
void AddLineOverlayAlpha(const Vector& origin, const Vector& dest, int r, int g, int b, int a, bool noDepthTest, float duration)
{
CDebugOverlay::AddLineOverlay(origin, dest, r, g, b, a, noDepthTest, duration);
}
void AddBoxOverlay2( const Vector& origin, const Vector& mins, const Vector& maxs, QAngle const& orientation, const Color& faceColor, const Color& edgeColor, float duration )
{
CDebugOverlay::AddBoxOverlay2(origin, mins, maxs, orientation, faceColor, edgeColor, duration );
}
void PurgeTextOverlays()
{
CDebugOverlay::PurgeTextOverlays();
}
};
static CIVDebugOverlay g_DebugOverlay;
EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CIVDebugOverlay, IVDebugOverlay, VDEBUG_OVERLAY_INTERFACE_VERSION, g_DebugOverlay );
EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CIVDebugOverlay, IVPhysicsDebugOverlay, VPHYSICS_DEBUG_OVERLAY_INTERFACE_VERSION, g_DebugOverlay );