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.
 
 
 
 
 
 

467 lines
12 KiB

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#if !defined(_STATIC_LINKED) || defined(_SHARED_LIB)
#include "iscratchpad3d.h"
#include "mathlib/mathlib.h"
#include "ScratchPadUtils.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// --------------------------------------------------------------------------------------------------------------------- //
// CScratchPadGraph implementation.
// --------------------------------------------------------------------------------------------------------------------- //
CScratchPadGraph::CScratchPadGraph()
{
m_pPad = NULL;
}
void CScratchPadGraph::Init(
IScratchPad3D *pPad,
Vector vTimeAxis,
float flInchesPerSecond,
Vector vTimeLineColor,
float flTimeOrigin,
float flTimeLabelEveryNSeconds,
Vector vValueAxis,
float flInchesPerValue,
Vector vValueLineColor,
float flValueOrigin
)
{
m_pPad = pPad;
m_vTimeAxis = vTimeAxis;
m_flInchesPerSecond = flInchesPerSecond;
m_vValueAxis = vValueAxis;
m_flInchesPerValue = flInchesPerValue;
m_flTimeLabelEveryNSeconds = flTimeLabelEveryNSeconds;
m_vTimeLineColor = vTimeLineColor;
m_vValueLineColor = vValueLineColor;
m_flTimeOrigin = flTimeOrigin;
m_flValueOrigin = flValueOrigin;
m_nTimeLabelsDrawn = 0;
m_flHighestTime = flTimeOrigin;
m_flHighestValue = flValueOrigin;
}
bool CScratchPadGraph::IsInitted() const
{
return m_pPad != NULL;
}
CScratchPadGraph::LineID CScratchPadGraph::AddLine( Vector vColor )
{
CScratchPadGraph::CLineInfo info;
info.m_bFirst = true;
info.m_vColor = vColor;
return m_LineInfos.AddToTail( info );
}
void CScratchPadGraph::AddSample( LineID iLine, float flTime, float flValue )
{
CScratchPadGraph::CLineInfo *pInfo = &m_LineInfos[iLine];
UpdateTicksAndStuff( flTime, flValue );
if ( !pInfo->m_bFirst )
{
// Draw a line from the last value to the current one.
Vector vStart = GetSamplePosition( pInfo->m_flLastTime, pInfo->m_flLastValue );
Vector vEnd = GetSamplePosition( flTime, flValue );
m_pPad->DrawLine(
CSPVert( vStart, pInfo->m_vColor ),
CSPVert( vEnd, pInfo->m_vColor )
);
}
pInfo->m_flLastTime = flTime;
pInfo->m_flLastValue = flValue;
pInfo->m_bFirst = false;
}
void CScratchPadGraph::AddVerticalLine( float flTime, float flMinValue, float flMaxValue, const CSPColor &vColor )
{
Vector v1 = GetSamplePosition( flTime, flMinValue );
Vector v2 = GetSamplePosition( flTime, flMaxValue );
m_pPad->DrawLine(
CSPVert( v1, vColor ),
CSPVert( v2, vColor ) );
}
void CScratchPadGraph::UpdateTicksAndStuff( float flTime, float flValue )
{
if ( flTime > m_flHighestTime )
{
// Update the left part of the time axis.
Vector vStart = GetSamplePosition( m_flHighestTime, m_flValueOrigin );
Vector vEnd = GetSamplePosition( flTime, m_flValueOrigin );
m_pPad->DrawLine(
CSPVert( vStart, m_vTimeLineColor ),
CSPVert( vEnd, m_vTimeLineColor )
);
m_flHighestTime = flTime;
}
if ( flValue > m_flHighestValue )
{
// Update the left part of the time axis.
Vector vStart = GetSamplePosition( m_flTimeOrigin, m_flHighestValue );
Vector vEnd = GetSamplePosition( m_flTimeOrigin, flValue );
m_pPad->DrawLine(
CSPVert( vStart, m_vValueLineColor ),
CSPVert( vEnd, m_vValueLineColor )
);
// Extend the lines attached to the time labels.
for ( int i=0; i < m_nTimeLabelsDrawn; i++ )
{
float flTimeLabel = m_flTimeOrigin + m_nTimeLabelsDrawn * m_flTimeLabelEveryNSeconds;
m_pPad->DrawLine(
CSPVert((const Vector&) GetSamplePosition( flTimeLabel, m_flHighestValue )),
CSPVert((const Vector&) GetSamplePosition( flTimeLabel, flValue ) )
);
}
m_flHighestValue = flValue;
}
// More text labels?
int iHighestTextLabel = (int)ceil( (flTime - m_flTimeOrigin) / m_flTimeLabelEveryNSeconds + 0.5f );
while ( m_nTimeLabelsDrawn < iHighestTextLabel )
{
CTextParams params;
float flTimeLabel = m_flTimeOrigin + m_nTimeLabelsDrawn * m_flTimeLabelEveryNSeconds;
params.m_bSolidBackground = true;
params.m_vPos = GetSamplePosition( flTimeLabel, m_flValueOrigin-5 );
params.m_bTwoSided = true;
char str[512];
Q_snprintf( str, sizeof( str ), "time: %.2f", flTimeLabel );
m_pPad->DrawText( str, params );
// Now draw the vertical line for the value..
m_pPad->DrawLine(
CSPVert( (const Vector&)GetSamplePosition( flTimeLabel, m_flValueOrigin ) ),
CSPVert( (const Vector&)GetSamplePosition( flTimeLabel, m_flHighestValue ) )
);
m_nTimeLabelsDrawn++;
}
}
Vector CScratchPadGraph::GetSamplePosition( float flTime, float flValue )
{
Vector vRet =
m_vTimeAxis * ((flTime - m_flTimeOrigin) * m_flInchesPerSecond) +
m_vValueAxis * ((flValue - m_flValueOrigin) * m_flInchesPerValue);
return vRet;
}
// --------------------------------------------------------------------------------------------------------------------- //
// Global functions.
// --------------------------------------------------------------------------------------------------------------------- //
void ScratchPad_DrawLitCone(
IScratchPad3D *pPad,
const Vector &vBaseCenter,
const Vector &vTip,
const Vector &vBrightColor,
const Vector &vDarkColor,
const Vector &vLightDir,
float baseWidth,
int nSegments )
{
// Make orthogonal vectors.
Vector vDir = vTip - vBaseCenter;
VectorNormalize( vDir );
Vector vRight, vUp;
VectorVectors( vDir, vRight, vUp );
vRight *= baseWidth;
vUp *= baseWidth;
// Setup the top and bottom caps.
CSPVertList bottomCap, tri;
bottomCap.m_Verts.SetSize( nSegments );
tri.m_Verts.SetSize( 3 );
float flDot = -vLightDir.Dot( vDir );
Vector topColor, bottomColor;
VectorLerp( vDarkColor, vBrightColor, RemapVal( -flDot, -1, 1, 0, 1 ), bottomColor );
// Draw each quad.
Vector vPrevBottom = vBaseCenter + vRight;
for ( int i=0; i < nSegments; i++ )
{
float flAngle = (float)(i+1) * M_PI * 2.0 / nSegments;
Vector vOffset = vRight * cos( flAngle ) + vUp * sin( flAngle );
Vector vCurBottom = vBaseCenter + vOffset;
const Vector &v1 = vTip;
const Vector &v2 = vPrevBottom;
const Vector &v3 = vCurBottom;
Vector vFaceNormal = (v2 - v1).Cross( v3 - v1 );
VectorNormalize( vFaceNormal );
// Now light it.
flDot = -vLightDir.Dot( vFaceNormal );
Vector vColor;
VectorLerp( vDarkColor, vBrightColor, RemapVal( flDot, -1, 1, 0, 1 ), vColor );
// Draw the quad.
tri.m_Verts[0] = CSPVert( v1, vColor );
tri.m_Verts[1] = CSPVert( v2, vColor );
tri.m_Verts[2] = CSPVert( v3, vColor );
pPad->DrawPolygon( tri );
bottomCap.m_Verts[i] = CSPVert( vCurBottom, bottomColor );
}
pPad->DrawPolygon( bottomCap );
}
void ScratchPad_DrawLitCylinder(
IScratchPad3D *pPad,
const Vector &v1,
const Vector &v2,
const Vector &vBrightColor,
const Vector &vDarkColor,
const Vector &vLightDir,
float width,
int nSegments )
{
// Make orthogonal vectors.
Vector vDir = v2 - v1;
VectorNormalize( vDir );
Vector vRight, vUp;
VectorVectors( vDir, vRight, vUp );
vRight *= width;
vUp *= width;
// Setup the top and bottom caps.
CSPVertList topCap, bottomCap, quad;
topCap.m_Verts.SetSize( nSegments );
bottomCap.m_Verts.SetSize( nSegments );
quad.m_Verts.SetSize( 4 );
float flDot = -vLightDir.Dot( vDir );
Vector topColor, bottomColor;
VectorLerp( vDarkColor, vBrightColor, RemapVal( flDot, -1, 1, 0, 1 ), topColor );
VectorLerp( vDarkColor, vBrightColor, RemapVal( -flDot, -1, 1, 0, 1 ), bottomColor );
// Draw each quad.
Vector vPrevTop = v1 + vRight;
Vector vPrevBottom = v2 + vRight;
for ( int i=0; i < nSegments; i++ )
{
float flAngle = (float)(i+1) * M_PI * 2.0 / nSegments;
Vector vOffset = vRight * cos( flAngle ) + vUp * sin( flAngle );
Vector vCurTop = v1 + vOffset;
Vector vCurBottom = v2 + vOffset;
// Now light it.
VectorNormalize( vOffset );
flDot = -vLightDir.Dot( vOffset );
Vector vColor;
VectorLerp( vDarkColor, vBrightColor, RemapVal( flDot, -1, 1, 0, 1 ), vColor );
// Draw the quad.
quad.m_Verts[0] = CSPVert( vPrevTop, vColor );
quad.m_Verts[1] = CSPVert( vPrevBottom, vColor );
quad.m_Verts[2] = CSPVert( vCurBottom, vColor );
quad.m_Verts[3] = CSPVert( vCurTop, vColor );
pPad->DrawPolygon( quad );
topCap.m_Verts[i] = CSPVert( vCurTop, topColor );
bottomCap.m_Verts[i] = CSPVert( vCurBottom, bottomColor );
}
pPad->DrawPolygon( topCap );
pPad->DrawPolygon( bottomCap );
}
void ScratchPad_DrawArrow(
IScratchPad3D *pPad,
const Vector &vPos,
const Vector &vDirection,
const Vector &vColor,
float flLength,
float flLineWidth,
float flHeadWidth,
int nCylinderSegments,
int nHeadSegments,
float flArrowHeadPercentage
)
{
Vector vNormDir = vDirection;
VectorNormalize( vNormDir );
Vector vConeBase = vPos + vNormDir * (flLength * ( 1 - flArrowHeadPercentage ) );
Vector vConeEnd = vPos + vNormDir * flLength;
Vector vLightDir( -1, -1, -1 );
VectorNormalize( vLightDir ); // could precalculate this
pPad->SetRenderState( IScratchPad3D::RS_FillMode, IScratchPad3D::FillMode_Solid );
pPad->SetRenderState( IScratchPad3D::RS_ZRead, true );
ScratchPad_DrawLitCylinder( pPad, vPos, vConeBase, vColor, vColor*0.25f, vLightDir, flLineWidth, nCylinderSegments );
ScratchPad_DrawLitCone( pPad, vConeBase, vConeEnd, vColor, vColor*0.25f, vLightDir, flHeadWidth, nHeadSegments );
}
void ScratchPad_DrawArrowSimple(
IScratchPad3D *pPad,
const Vector &vPos,
const Vector &vDirection,
const Vector &vColor,
float flLength )
{
ScratchPad_DrawArrow(
pPad,
vPos,
vDirection,
vColor,
flLength,
flLength * 1.0/15,
flLength * 3.0/15,
4,
4 );
}
void ScratchPad_DrawSphere(
IScratchPad3D *pPad,
const Vector &vCenter,
float flRadius,
const Vector &vColor,
int nSubDivs )
{
CUtlVector<Vector> prevPoints;
prevPoints.SetSize( nSubDivs );
// For each vertical slice.. (the top and bottom ones are just a single point).
for ( int iSlice=0; iSlice < nSubDivs; iSlice++ )
{
float flHalfSliceAngle = M_PI * (float)iSlice / (nSubDivs - 1);
if ( iSlice == 0 )
{
prevPoints[0] = vCenter + Vector( 0, 0, flRadius );
for ( int z=1; z < prevPoints.Count(); z++ )
prevPoints[z] = prevPoints[0];
}
else
{
for ( int iSubPt=0; iSubPt < nSubDivs; iSubPt++ )
{
float flHalfAngle = M_PI * (float)iSubPt / (nSubDivs - 1);
float flAngle = flHalfAngle * 2;
Vector pt;
if ( iSlice == (nSubDivs - 1) )
{
pt = vCenter - Vector( 0, 0, flRadius );
}
else
{
pt.x = cos( flAngle ) * sin( flHalfSliceAngle );
pt.y = sin( flAngle ) * sin( flHalfSliceAngle );
pt.z = cos( flHalfSliceAngle );
pt *= flRadius;
pt += vCenter;
}
pPad->DrawLine( CSPVert( pt, vColor ), CSPVert( prevPoints[iSubPt], vColor ) );
prevPoints[iSubPt] = pt;
}
if ( iSlice != (nSubDivs - 1) )
{
for ( int i=0; i < nSubDivs; i++ )
pPad->DrawLine( CSPVert( prevPoints[i], vColor ), CSPVert( prevPoints[(i+1)%nSubDivs], vColor ) );
}
}
}
}
void ScratchPad_DrawAABB(
IScratchPad3D *pPad,
const Vector &vMins,
const Vector &vMaxs,
const Vector &vColor )
{
int vertOrder[4][2] = {{0,0},{1,0},{1,1},{0,1}};
const Vector *vecs[2] = {&vMins, &vMaxs};
Vector vTop, vBottom, vPrevTop, vPrevBottom;
vTop.z = vPrevTop.z = vMaxs.z;
vBottom.z = vPrevBottom.z = vMins.z;
vPrevTop.x = vPrevBottom.x = vecs[vertOrder[3][0]]->x;
vPrevTop.y = vPrevBottom.y = vecs[vertOrder[3][1]]->y;
for ( int i=0; i < 4; i++ )
{
vTop.x = vBottom.x = vecs[vertOrder[i][0]]->x;
vTop.y = vBottom.y = vecs[vertOrder[i][1]]->y;
// Draw the top line.
pPad->DrawLine( CSPVert( vPrevTop, vColor ), CSPVert( vTop, vColor ) );
pPad->DrawLine( CSPVert( vPrevBottom, vColor ), CSPVert( vBottom, vColor ) );
pPad->DrawLine( CSPVert( vTop, vColor ), CSPVert( vBottom, vColor ) );
vPrevTop = vTop;
vPrevBottom = vBottom;
}
}
#endif // !_STATIC_LINKED || _SHARED_LIB