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
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 |
|
|
|
|