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