//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // //=============================================================================// #include "cbase.h" #include "drawing_panel.h" #include "softline.h" #include #include #include "voice_status.h" // memdbgon must be the last include file in a .cpp file!!! #include extern ConVar cl_mute_all_comms; Color g_DrawPanel_TeamColors[TF_TEAM_COUNT] = { COLOR_TF_SPECTATOR, // unassigned COLOR_TF_SPECTATOR, // spectator COLOR_TF_RED, // red COLOR_TF_BLUE, // blue }; DECLARE_BUILD_FACTORY( CDrawingPanel ); CDrawingPanel::CDrawingPanel( Panel *parent, const char*name ) : Panel( parent, name ) { m_bDrawingLines = false; m_fLastMapLine = 0; m_iMouseX = 0; m_iMouseY = 0; m_iPanelType = DRAWING_PANEL_TYPE_NONE; m_bTeamColors = false; m_nWhiteTexture = vgui::surface()->CreateNewTextureID(); vgui::surface()->DrawSetTextureFile( m_nWhiteTexture, "vgui/white", true, false ); ListenForGameEvent( "cl_drawline" ); } void CDrawingPanel::SetVisible( bool bState ) { ClearAllLines(); BaseClass::SetVisible( bState ); } void CDrawingPanel::ReadColor( const char* pszToken, Color& color ) { if ( pszToken && *pszToken ) { int r = 0, g = 0, b = 0, a = 255; if ( sscanf( pszToken, "%d %d %d %d", &r, &g, &b, &a ) >= 3 ) { // it's a direct color color = Color( r, g, b, a ); } else { vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( GetScheme() ); color = pScheme->GetColor( pszToken, Color( 0, 0, 0, 0 ) ); } } } void CDrawingPanel::ApplySettings( KeyValues *inResourceData ) { BaseClass::ApplySettings( inResourceData ); ReadColor( inResourceData->GetString( "linecolor", "" ), m_colorLine ); m_bTeamColors = inResourceData->GetBool( "team_colors", false ); } void CDrawingPanel::Paint() { for ( int iIndex = 0; iIndex < ARRAYSIZE( m_vecDrawnLines ); iIndex++ ) { //Draw the lines for ( int i = 0; i < m_vecDrawnLines[iIndex].Count(); i++ ) { if ( !m_vecDrawnLines[iIndex][i].bSetBlipCentre ) { Vector vecBlipPos; vecBlipPos.x = m_vecDrawnLines[iIndex][i].worldpos.x; vecBlipPos.y = m_vecDrawnLines[iIndex][i].worldpos.y; vecBlipPos.z = 0; //Msg("drawing line with blippos %f, %f\n", vecBlipPos.x, vecBlipPos.y); m_vecDrawnLines[iIndex][i].blipcentre = m_vecDrawnLines[iIndex][i].worldpos; //Msg(" which is blipcentre=%f, %f\n", m_MapLines[i].blipcentre.x, m_MapLines[i].blipcentre.y); m_vecDrawnLines[iIndex][i].bSetBlipCentre = true; } float x = m_vecDrawnLines[iIndex][i].blipcentre.x; float y = m_vecDrawnLines[iIndex][i].blipcentre.y; if ( m_vecDrawnLines[iIndex][i].bLink ) { if ( i > 1 ) { m_vecDrawnLines[iIndex][i].linkpos = m_vecDrawnLines[iIndex][i-1].worldpos; if ( !m_vecDrawnLines[iIndex][i].bSetLinkBlipCentre ) { Vector vecBlipPos2; vecBlipPos2.x = m_vecDrawnLines[iIndex][i].linkpos.x; vecBlipPos2.y = m_vecDrawnLines[iIndex][i].linkpos.y; vecBlipPos2.z = 0; m_vecDrawnLines[iIndex][i].linkblipcentre = m_vecDrawnLines[iIndex][i].linkpos; m_vecDrawnLines[iIndex][i].bSetLinkBlipCentre = true; } float x2 = m_vecDrawnLines[iIndex][i].linkblipcentre.x; float y2 = m_vecDrawnLines[iIndex][i].linkblipcentre.y; int alpha = 255; if ( m_iPanelType == DRAWING_PANEL_TYPE_MATCH_SUMMARY ) { float t = gpGlobals->curtime - m_vecDrawnLines[iIndex][i].created_time; if ( t < DRAWN_LINE_SOLID_TIME ) { } else if ( t < DRAWN_LINE_SOLID_TIME + DRAWN_LINE_FADE_TIME ) { alpha = 255 - ( ( t - DRAWN_LINE_SOLID_TIME ) / DRAWN_LINE_FADE_TIME ) * 255.0f; } else { continue; } } //Msg("drawing line from %f,%f to %f,%f\n", x, y, x2, y2); vgui::surface()->DrawSetTexture( m_nWhiteTexture ); vgui::Vertex_t start, end; Color drawColor = m_colorLine; if ( m_bTeamColors ) { C_BasePlayer *pPlayer = UTIL_PlayerByIndex( iIndex ); if ( pPlayer ) { drawColor = g_DrawPanel_TeamColors[ pPlayer->GetTeamNumber() ]; } } // draw main line vgui::surface()->DrawSetColor( Color( drawColor.r(), drawColor.g(), drawColor.b(), alpha ) ); start.Init( Vector2D( x, y ), Vector2D( 0, 0 ) ); end.Init( Vector2D( x2, y2 ), Vector2D( 1, 1 ) ); SoftLine::DrawPolygonLine( start, end ); // draw translucent ones around it to give it some softness vgui::surface()->DrawSetColor( Color( drawColor.r(), drawColor.g(), drawColor.b(), 0.5f * alpha ) ); start.Init( Vector2D( x - 0.50f, y - 0.50f ), Vector2D( 0, 0 ) ); end.Init( Vector2D( x2 - 0.50f, y2 - 0.50f ), Vector2D( 1, 1 ) ); SoftLine::DrawPolygonLine( start, end ); start.Init( Vector2D( x + 0.50f, y - 0.50f ), Vector2D( 0, 0 ) ); end.Init( Vector2D( x2 + 0.50f, y2 - 0.50f ), Vector2D( 1, 1 ) ); SoftLine::DrawPolygonLine( start, end ); start.Init( Vector2D( x - 0.50f, y + 0.50f ), Vector2D( 0, 0 ) ); end.Init( Vector2D( x2 - 0.50f, y2 + 0.50f ), Vector2D( 1, 1 ) ); SoftLine::DrawPolygonLine( start, end ); start.Init( Vector2D( x + 0.50f, y + 0.50f ), Vector2D( 0, 0 ) ); end.Init( Vector2D( x2 + 0.50f, y2 + 0.50f ), Vector2D( 1, 1 ) ); SoftLine::DrawPolygonLine( start, end ); } } } } } void CDrawingPanel::OnMousePressed( vgui::MouseCode code ) { if ( code != MOUSE_LEFT ) return; SendMapLine( m_iMouseX, m_iMouseY, true ); m_bDrawingLines = true; } void CDrawingPanel::OnMouseReleased( vgui::MouseCode code ) { if ( code != MOUSE_LEFT ) return; m_bDrawingLines = false; } void CDrawingPanel::OnCursorExited() { //Msg("CDrawingPanel::OnCursorExited\n"); m_bDrawingLines = false; } void CDrawingPanel::OnThink() { if ( m_iPanelType == DRAWING_PANEL_TYPE_MATCH_SUMMARY ) { // clean up any segments that have faded out for ( int iIndex = 0; iIndex < ARRAYSIZE( m_vecDrawnLines ); iIndex++ ) { for ( int i = m_vecDrawnLines[iIndex].Count() - 1; i >= 0; i-- ) { if ( gpGlobals->curtime - m_vecDrawnLines[iIndex][i].created_time > DRAWN_LINE_SOLID_TIME + DRAWN_LINE_FADE_TIME ) { m_vecDrawnLines[iIndex].Remove( i ); } } } } } void CDrawingPanel::OnCursorMoved( int x, int y ) { //Msg("CDrawingPanel::OnCursorMoved %d,%d\n", x, y); m_iMouseX = x; m_iMouseY = y; const float flLineInterval = 1.f / 60.f; if ( m_bDrawingLines && gpGlobals->curtime >= m_fLastMapLine + flLineInterval ) { SendMapLine( x, y, false ); } } void CDrawingPanel::SendMapLine( int x, int y, bool bInitial ) { if ( engine->IsPlayingDemo() ) return; int iIndex = GetLocalPlayerIndex(); int nMaxLines = 750; // 12.5 seconds of drawing at 60fps if ( m_iPanelType == DRAWING_PANEL_TYPE_MATCH_SUMMARY ) { nMaxLines = 120; // 2 seconds of drawing at 60fps } // Stop adding lines after this much if ( m_vecDrawnLines[iIndex].Count() >= nMaxLines ) return; int linetype = bInitial ? 0 : 1; m_fLastMapLine = gpGlobals->curtime; // short circuit add it to your own list MapLine line; line.worldpos.x = x; line.worldpos.y = y; line.created_time = gpGlobals->curtime; if ( linetype == 1 ) // links to a previous { line.bLink = true; } m_vecDrawnLines[iIndex].AddToTail( line ); if ( m_iPanelType == DRAWING_PANEL_TYPE_MATCH_SUMMARY ) { // notify the server of this! KeyValues *kv = new KeyValues( "cl_drawline" ); kv->SetInt( "panel", m_iPanelType ); kv->SetInt( "line", linetype ); kv->SetFloat( "x", (float)x / (float)GetWide() ); kv->SetFloat( "y", (float)y / (float)GetTall() ); engine->ServerCmdKeyValues( kv ); } } void CDrawingPanel::ClearLines( int iIndex ) { m_vecDrawnLines[iIndex].Purge(); } void CDrawingPanel::ClearAllLines() { for ( int iIndex = 0; iIndex < ARRAYSIZE( m_vecDrawnLines ); iIndex++ ) { m_vecDrawnLines[iIndex].Purge(); } } void CDrawingPanel::FireGameEvent( IGameEvent *event ) { if ( FStrEq( event->GetName(), "cl_drawline" ) ) { int iIndex = event->GetInt( "player" ); // if this is NOT the local player (we've already stored our own data) if ( ( iIndex != GetLocalPlayerIndex() ) || engine->IsPlayingDemo() ) { // If a player is muted for voice, also mute them for lines because jerks gonna jerk. if ( cl_mute_all_comms.GetBool() && ( iIndex != 0 ) ) { if ( GetClientVoiceMgr() && GetClientVoiceMgr()->IsPlayerBlocked( iIndex ) ) { ClearLines( iIndex ); return; } } int iPanelType = event->GetInt( "panel" ); // if this message is about our panel type if ( iPanelType == m_iPanelType ) { int iLineType = event->GetInt( "line" ); float x = event->GetFloat( "x" ); float y = event->GetFloat( "y" ); MapLine line; line.worldpos.x = (int)( x * GetWide() ); line.worldpos.y = (int)( y * GetTall() ); line.created_time = gpGlobals->curtime; if ( iLineType == 1 ) // links to a previous { line.bLink = true; } m_vecDrawnLines[iIndex].AddToTail( line ); } } } }