summaryrefslogtreecommitdiff
path: root/game/client/tf2/panel_effects.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/client/tf2/panel_effects.cpp')
-rw-r--r--game/client/tf2/panel_effects.cpp1094
1 files changed, 1094 insertions, 0 deletions
diff --git a/game/client/tf2/panel_effects.cpp b/game/client/tf2/panel_effects.cpp
new file mode 100644
index 0000000..505d2d6
--- /dev/null
+++ b/game/client/tf2/panel_effects.cpp
@@ -0,0 +1,1094 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "hud.h"
+#include "c_tf2rootpanel.h"
+#include "paneleffect.h"
+#include <vgui_controls/Controls.h>
+#include <vgui/ISurface.h>
+
+#define EFFECT_FLASH_TIME 0.7f
+
+#define EFFECT_R 100
+#define EFFECT_G 150
+#define EFFECT_B 220
+#define EFFECT_A 255
+
+#define ARROW_R 130
+#define ARROW_G 190
+#define ARROW_B 240
+#define ARROW_A 255
+
+#define AXIALLINE_R 220
+#define AXIALLINE_G 220
+#define AXIALLINE_B 255
+#define AXIALLINE_A 255
+
+//-----------------------------------------------------------------------------
+// Purpose: Helper for drawing line segments
+//-----------------------------------------------------------------------------
+class CConnectingLine
+{
+public:
+ int m_ptStart[ 2 ];
+ int m_ptEnd[ 2 ];
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Fill in the intersection between the two rectangles.
+// Input : *pRect1 -
+// *pRect2 -
+// *pOut -
+// Output : inline bool
+//-----------------------------------------------------------------------------
+inline bool GetRectIntersection( wrect_t const *pRect1, wrect_t const *pRect2, wrect_t *pOut )
+{
+ pOut->left = MAX( pRect1->left, pRect2->left );
+ pOut->right = MIN( pRect1->right, pRect2->right );
+ if( pOut->left >= pOut->right )
+ return false;
+
+ pOut->bottom = MIN( pRect1->bottom, pRect2->bottom );
+ pOut->top = MAX( pRect1->top, pRect2->top );
+ if( pOut->top >= pOut->bottom )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Edge to use
+//-----------------------------------------------------------------------------
+typedef enum
+{
+ TOPCENTER = 0,
+ RIGHTCENTER,
+ BOTTOMCENTER,
+ LEFTCENTER
+} LINEEDGE_t;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : x -
+// y -
+// rect -
+// edge -
+// border -
+//-----------------------------------------------------------------------------
+static void GetCenterPoint( int& x, int& y, const wrect_t& rect, LINEEDGE_t edge, int border )
+{
+ int xcenter;
+ int ycenter;
+
+ xcenter = ( rect.left + rect.right ) / 2;
+ ycenter = ( rect.top + rect.bottom ) / 2;
+
+ switch ( edge )
+ {
+ default:
+ case TOPCENTER:
+ x = xcenter;
+ y = rect.top - border;
+ break;
+ case RIGHTCENTER:
+ x = rect.right + border;
+ y = ycenter;
+ break;
+ case BOTTOMCENTER:
+ x = xcenter;
+ y = rect.bottom + border;
+ break;
+ case LEFTCENTER:
+ x = rect.left - border;
+ y = ycenter;
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Given two rectangles, finds a direct line between the two rectangles, unless
+// they overlap, in which case no line is output.
+// Input : x1 -
+// y1 -
+// w1 -
+// h1 -
+// x2 -
+// y2 -
+// w2 -
+// h2 -
+// output -
+//-----------------------------------------------------------------------------
+static void FindConnectingLines_Straight(
+ int x1, int y1, int w1, int h1,
+ int x2, int y2, int w2, int h2,
+ CUtlVector< CConnectingLine >& output )
+{
+ // Reset output
+ output.RemoveAll();
+
+ // If the rectangles intersect, no line needed
+ wrect_t r1;
+ r1.left = x1;
+ r1.top = y1;
+ r1.right = x1 + w1;
+ r1.bottom = y1 + h1;
+
+ wrect_t r2;
+ r2.left = x2;
+ r2.top = y2;
+ r2.right = x2 + w2;
+ r2.bottom = y2 + h2;
+
+ wrect_t dummy;
+
+ if ( GetRectIntersection( &r1, &r2, &dummy ) )
+ return;
+
+ int center1[2];
+ int center2[2];
+
+ center1[ 0 ] = x1 + w1/2;
+ center1[ 1 ] = y1 + h1/2;
+
+ center2[ 0 ] = x2 + w2/2;
+ center2[ 1 ] = y2 + h2/2;
+
+ int gaph;
+ int gapv;
+
+ LINEEDGE_t edge1 = TOPCENTER;
+ LINEEDGE_t edge2 = BOTTOMCENTER;
+
+ // Top
+ gaph = MAX( r2.left - r1.right, r1.left - r2.right );
+ gapv = MAX( r1.top - r2.bottom, r2.top - r1.bottom );
+
+ if ( gapv > gaph )
+ {
+ // vertical
+ if ( ( r1.top - r2.bottom ) > ( r2.top - r1.bottom ) )
+ {
+ edge2 = BOTTOMCENTER;
+ edge1 = TOPCENTER;
+ }
+ else
+ {
+ edge2 = TOPCENTER;
+ edge1 = BOTTOMCENTER;
+ }
+ }
+ else
+ {
+ if ( ( r1.left - r2.right ) > ( r2.left - r1.right ) )
+ {
+ // horizontal
+ edge2 = RIGHTCENTER;
+ edge1 = LEFTCENTER;
+ }
+ else
+ {
+ edge2 = LEFTCENTER;
+ edge1 = RIGHTCENTER;
+ }
+ }
+
+ int pt1[ 2 ];
+ int pt2[ 2 ];
+
+ GetCenterPoint( pt1[ 0 ], pt1[ 1 ], r1, edge1, 3 );
+ GetCenterPoint( pt2[ 0 ], pt2[ 1 ], r2, edge2, 3 );
+
+ CConnectingLine line;
+ line.m_ptStart[ 0 ] = pt1[ 0 ];
+ line.m_ptStart[ 1 ] = pt1[ 1 ];
+ line.m_ptEnd[ 0 ] = pt2[ 0 ];
+ line.m_ptEnd[ 1 ] = pt2[ 1 ];
+
+ output.AddToTail( line );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Given two non-intersecting rectangles, finds one, two or three segments
+// which connect the midpoints of two of the sides of the items together with only
+// axial lines.
+// Input : x1 -
+// y1 -
+// w1 -
+// h1 -
+// x2 -
+// y2 -
+// w2 -
+// h2 -
+// output -
+//-----------------------------------------------------------------------------
+static void FindConnectingLines_Axial(
+ int x1, int y1, int w1, int h1,
+ int x2, int y2, int w2, int h2,
+ CUtlVector< CConnectingLine >& output )
+{
+ // Reset output
+ output.RemoveAll();
+
+ // If the rectangles intersect, no line needed
+ wrect_t r1;
+ r1.left = x1;
+ r1.top = y1;
+ r1.right = x1 + w1;
+ r1.bottom = y1 + h1;
+
+ wrect_t r2;
+ r2.left = x2;
+ r2.top = y2;
+ r2.right = x2 + w2;
+ r2.bottom = y2 + h2;
+ wrect_t dummy;
+
+ if ( GetRectIntersection( &r1, &r2, &dummy ) )
+ return;
+
+ int center1[2];
+ int center2[2];
+
+ center1[ 0 ] = x1 + w1/2;
+ center1[ 1 ] = y1 + h1/2;
+
+ center2[ 0 ] = x2 + w2/2;
+ center2[ 1 ] = y2 + h2/2;
+
+ int gaph;
+ int gapv;
+
+ LINEEDGE_t edge1 = TOPCENTER;
+ LINEEDGE_t edge2 = BOTTOMCENTER;
+
+ // Top
+ gaph = MAX( r2.left - r1.right, r1.left - r2.right );
+ gapv = MAX( r1.top - r2.bottom, r2.top - r1.bottom );
+
+ if ( gapv > gaph )
+ {
+ // vertical
+ if ( ( r1.top - r2.bottom ) > ( r2.top - r1.bottom ) )
+ {
+ edge2 = BOTTOMCENTER;
+ edge1 = TOPCENTER;
+ }
+ else
+ {
+ edge2 = TOPCENTER;
+ edge1 = BOTTOMCENTER;
+ }
+ }
+ else
+ {
+ if ( ( r1.left - r2.right ) > ( r2.left - r1.right ) )
+ {
+ // horizontal
+ edge2 = RIGHTCENTER;
+ edge1 = LEFTCENTER;
+ }
+ else
+ {
+ edge2 = LEFTCENTER;
+ edge1 = RIGHTCENTER;
+ }
+ }
+
+ int pt1[ 2 ];
+ int pt2[ 2 ];
+
+ GetCenterPoint( pt1[ 0 ], pt1[ 1 ], r1, edge1, 3 );
+ GetCenterPoint( pt2[ 0 ], pt2[ 1 ], r2, edge2, 3 );
+
+ CConnectingLine line;
+
+ int mid[ 2 ];
+ int size1[ 2 ];
+ int size2[ 2 ];
+
+ mid[ 0 ] = ( pt1[ 0 ] + pt2[ 0 ] ) / 2;
+ mid[ 1 ] = ( pt1[ 1 ] + pt2[ 1 ] ) / 2;
+
+ size1[ 0 ] = r1.right - r1.left;
+ size1[ 1 ] = r1.bottom - r1.top;
+
+ size2[ 0 ] = r2.right - r2.left;
+ size2[ 1 ] = r2.bottom - r2.top;
+
+ float sizefrac = 0.25f;
+
+ if ( edge1 == TOPCENTER || edge1 == BOTTOMCENTER )
+ {
+ int dx = abs( mid[ 0 ] - pt1[ 0 ] );
+ if ( dx < ( sizefrac * size1[ 0 ] ) &&
+ dx < ( sizefrac * size2[ 0 ] ) )
+ {
+ // Gap is small, just use midpoint to align both
+ line.m_ptStart[ 0 ] = mid[ 0 ];
+ line.m_ptStart[ 1 ] = pt1[ 1 ];
+ line.m_ptEnd[ 0 ] = mid[ 0 ];
+ line.m_ptEnd[ 1 ] = pt2[ 1 ];
+
+ output.AddToTail( line );
+ }
+ else
+ {
+ // Draw an L
+ line.m_ptStart[ 0 ] = pt1[ 0 ];
+ line.m_ptStart[ 1 ] = pt1[ 1 ];
+ line.m_ptEnd[ 0 ] = pt1[ 0 ];
+ line.m_ptEnd[ 1 ] = mid[ 1 ];
+
+ output.AddToTail( line );
+
+ line.m_ptStart[ 0 ] = pt1[ 0 ];
+ line.m_ptStart[ 1 ] = mid[ 1 ];
+ line.m_ptEnd[ 0 ] = pt2[ 0 ];
+ line.m_ptEnd[ 1 ] = mid[ 1 ];
+
+ output.AddToTail( line );
+
+ line.m_ptStart[ 0 ] = pt2[ 0 ];
+ line.m_ptStart[ 1 ] = mid[ 1 ];
+ line.m_ptEnd[ 0 ] = pt2[ 0 ];
+ line.m_ptEnd[ 1 ] = pt2[ 1 ];
+
+ output.AddToTail( line );
+ }
+ }
+ else
+ {
+ int dy = abs( mid[ 1 ] - pt1[ 1 ] );
+ if ( dy < ( sizefrac * size1[ 1] ) &&
+ dy < ( sizefrac * size2[ 1 ] ) )
+ {
+ // Gap is small, just use midpoint to align both
+ line.m_ptStart[ 0 ] = pt1[ 0 ];
+ line.m_ptStart[ 1 ] = mid[ 1 ];
+ line.m_ptEnd[ 0 ] = pt2[ 0 ];
+ line.m_ptEnd[ 1 ] = mid[ 1 ];
+
+ output.AddToTail( line );
+ }
+ else
+ {
+ // Draw an L
+ line.m_ptStart[ 0 ] = pt1[ 0 ];
+ line.m_ptStart[ 1 ] = pt1[ 1 ];
+ line.m_ptEnd[ 0 ] = mid[ 0 ];
+ line.m_ptEnd[ 1 ] = pt1[ 1 ];
+
+ output.AddToTail( line );
+
+ line.m_ptStart[ 0 ] = mid[ 0 ];
+ line.m_ptStart[ 1 ] = pt1[ 1 ];
+ line.m_ptEnd[ 0 ] = mid[ 0 ];
+ line.m_ptEnd[ 1 ] = pt2[ 1 ];
+
+ output.AddToTail( line );
+
+ line.m_ptStart[ 0 ] = mid[ 0 ];
+ line.m_ptStart[ 1 ] = pt2[ 1 ];
+ line.m_ptEnd[ 0 ] = pt2[ 0 ];
+ line.m_ptEnd[ 1 ] = pt2[ 1 ];
+
+ output.AddToTail( line );
+ }
+ }
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Map input panel rectangle into space of output panel and return extents in xywh
+// Input : x -
+// y -
+// w -
+// h -
+// *output -
+// *input -
+//-----------------------------------------------------------------------------
+void PanelToPanelRectangle( int& x, int& y, int& w, int& h, vgui::Panel *output, vgui::Panel *input )
+{
+ input->GetSize( w, h );
+ w += 2;
+ h += 2;
+
+ x = y = 0;
+ input->LocalToScreen( x, y );
+ output->ScreenToLocal( x, y );
+
+ x--;
+ y--;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Cycle between in/2 and in centered at 3/4in
+// Input : in -
+// f - ranges from -1 to 1
+// Output : static int
+//-----------------------------------------------------------------------------
+static int EffectResampleColor( int in, float f )
+{
+ int base = in / 2;
+ int midpoint = ( in + base ) / 2;
+ float range = (float)( in - midpoint );
+
+ int color = midpoint + (int)( f * range );
+ return clamp( color, 0, 255 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Border flashing effect
+//-----------------------------------------------------------------------------
+class CFlashBorderPanelEffect : public CPanelEffect
+{
+ DECLARE_CLASS( CFlashBorderPanelEffect, CPanelEffect );
+public:
+
+ CFlashBorderPanelEffect( ITFHintItem *owner );
+ virtual void doPaint( vgui::Panel *panel );
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *owner -
+//-----------------------------------------------------------------------------
+CFlashBorderPanelEffect::CFlashBorderPanelEffect( ITFHintItem *owner )
+ : CPanelEffect( owner )
+{
+ // Mark type field
+ SetType( FLASHBORDER );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Paint the effect
+// Input : *panel -
+//-----------------------------------------------------------------------------
+void CFlashBorderPanelEffect::doPaint( vgui::Panel *panel )
+{
+ vgui::Panel *p = m_hPanel;
+ if ( !p || !IsVisibleIncludingParent( p ) )
+ return;
+
+ int w, h;
+ p->GetSize( w, h );
+
+ // Convert top,left to local coordinates
+ int x = 0, y = 0;
+ p->LocalToScreen( x, y );
+ panel->ScreenToLocal( x, y );
+
+ x--;
+ y--;
+ w+=2;
+ h+=2;
+
+ float frac = fmod( gpGlobals->curtime, EFFECT_FLASH_TIME );
+ frac *= 2 * M_PI;
+ frac = cos( frac );
+
+ int r, g, b;
+
+ r = EffectResampleColor( m_r, frac );
+ g = EffectResampleColor( m_g, frac );
+ b = EffectResampleColor( m_b, frac );
+
+ vgui::surface()->DrawSetColor( r, g, b, m_a );
+
+ for ( int gap = 0; gap < 3; gap++ )
+ {
+ vgui::surface()->DrawOutlinedRect( x - gap, y - gap, x + w + gap, y + h + gap );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Creates an arry from m_hPanel to m_hOtherPanel
+//-----------------------------------------------------------------------------
+class CArrowPanelEffect : public CPanelEffect
+{
+ DECLARE_CLASS( CArrowPanelEffect, CPanelEffect );
+public:
+
+ CArrowPanelEffect( ITFHintItem *owner );
+
+ virtual void doPaint( vgui::Panel *panel );
+
+ void SetDrawBorder( bool drawborder );
+ void SetFlashing( bool flashing );
+
+protected:
+ void DrawArrow( int startx, int starty, int endx, int endy, int r, int g, int b, int a );
+ void DrawLine( int startx, int starty, int endx, int endy, int r, int g, int b, int a );
+ void ComputeBestPoint( int& px, int &py, vgui::Panel *output, vgui::Panel *from, vgui::Panel *to );
+
+protected:
+
+ bool m_bDrawBorder;
+ bool m_bFlashing;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *owner -
+//-----------------------------------------------------------------------------
+CArrowPanelEffect::CArrowPanelEffect( ITFHintItem *owner )
+ : CPanelEffect( owner )
+{
+ SetType( ARROW );
+
+ m_bDrawBorder = true;
+ m_bFlashing = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : drawborder -
+//-----------------------------------------------------------------------------
+void CArrowPanelEffect::SetDrawBorder( bool drawborder )
+{
+ m_bDrawBorder = drawborder;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : flashing -
+//-----------------------------------------------------------------------------
+void CArrowPanelEffect::SetFlashing( bool flashing )
+{
+ m_bFlashing = flashing;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : startx -
+// starty -
+// endx -
+// endy -
+// r -
+// g -
+// b -
+// a -
+//-----------------------------------------------------------------------------
+void CArrowPanelEffect::DrawArrow( int startx, int starty, int endx, int endy, int r, int g, int b, int a )
+{
+ vgui::surface()->DrawSetColor( r, g, b, a );
+
+ // Draw an arrow
+
+ Vector start( startx, starty, 0.0f );
+ Vector end( endx, endy, 0.0f );
+
+ Vector delta = end - start;
+
+ Vector right;
+
+ right.x = delta.y;
+ right.y = -delta.x;
+ right.z = 0.0f;
+
+ VectorNormalize( right );
+ Vector base;
+
+ float length = VectorNormalize( delta );
+
+ float size = MIN( length / 2.0f, 15.0f );
+
+ base = start + ( length - size ) * delta;
+
+ Vector baseLeft = base + size * 0.25f * right;
+ Vector baseRight = base - size * 0.25f * right;
+
+ vgui::surface()->DrawLine( end.x, end.y, baseLeft.x, baseLeft.y );
+ vgui::surface()->DrawLine( end.x, end.y, baseRight.x, baseRight.y );
+
+ base = start + ( length - size + size * 0.3f ) * delta;
+
+ vgui::surface()->DrawLine( base.x, base.y, baseLeft.x, baseLeft.y );
+ vgui::surface()->DrawLine( base.x, base.y, baseRight.x, baseRight.y );
+
+ vgui::surface()->DrawLine( startx, starty, base.x, base.y );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : startx -
+// starty -
+// endx -
+// endy -
+// r -
+// g -
+// b -
+// a -
+//-----------------------------------------------------------------------------
+void CArrowPanelEffect::DrawLine( int startx, int starty, int endx, int endy, int r, int g, int b, int a )
+{
+ vgui::surface()->DrawSetColor( r, g, b, a );
+ vgui::surface()->DrawLine( startx, starty, endx, endy );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *panel -
+//-----------------------------------------------------------------------------
+void CArrowPanelEffect::doPaint( vgui::Panel *panel )
+{
+ vgui::Panel *from = m_hPanel;
+ if ( !from || !IsVisibleIncludingParent( from ) )
+ return;
+
+ int r, g, b;
+ // Determine flash amount
+ if ( m_bFlashing )
+ {
+ float frac = fmod( gpGlobals->curtime, EFFECT_FLASH_TIME );
+ frac *= 2 * M_PI;
+ frac = cos( frac );
+
+ // Resample color
+
+ r = EffectResampleColor( m_r, frac );
+ g = EffectResampleColor( m_g, frac );
+ b = EffectResampleColor( m_b, frac );
+ }
+ else
+ {
+ r = m_r;
+ g = m_g;
+ b = m_b;
+ }
+
+ int startx, starty, startw, starth;
+ int endx, endy, endw, endh;
+
+ PanelToPanelRectangle( startx, starty, startw, starth, panel, from );
+
+ if ( !GetTargetRectangle( panel, endx, endy, endw, endh ) )
+ return;
+
+ CUtlVector< CConnectingLine > lines;
+
+ FindConnectingLines_Straight( startx, starty, startw, starth, endx, endy, endw, endh, lines );
+
+ int i;
+
+ if ( m_bDrawBorder )
+ {
+ for ( i = 0; i < lines.Size(); i++ )
+ {
+ CConnectingLine *l = &lines[ i ];
+
+ // Make it thicker
+ int hstep = 0;
+ int vstep = 0;
+
+ if ( abs( l->m_ptEnd[ 1 ] - l->m_ptStart[ 1 ] ) > abs( l->m_ptEnd[ 0 ] - l->m_ptStart[ 0 ] ) )
+ {
+ // Taller so draw horizontally
+ hstep = 1;
+ }
+ else
+ {
+ vstep = 1;
+ }
+
+ // Draw a black border
+ for ( int x = -1; x <= 1 + hstep; x ++ )
+ {
+ for ( int y = -1; y <= 1 + vstep; y ++ )
+ {
+ if ( !x && !y )
+ continue;
+
+ if ( i == lines.Size() - 1 )
+ {
+ DrawArrow( l->m_ptStart[ 0 ] + x, l->m_ptStart[1] + y, l->m_ptEnd[0] + x, l->m_ptEnd[1] + y, 0, 0, 0, m_a );
+ }
+ else
+ {
+ DrawLine( l->m_ptStart[ 0 ] + x, l->m_ptStart[1] + y, l->m_ptEnd[0] + x, l->m_ptEnd[1] + y, 0, 0, 0, m_a );
+ }
+ }
+ }
+ }
+ }
+
+ for ( i = 0; i < lines.Size(); i++ )
+ {
+ CConnectingLine *l = &lines[ i ];
+
+ // Make it thicker
+ int hstep = 0;
+ int vstep = 0;
+
+ if ( abs( l->m_ptEnd[ 1 ] - l->m_ptStart[ 1 ] ) > abs( l->m_ptEnd[ 0 ] - l->m_ptStart[ 0 ] ) )
+ {
+ // Taller so draw horizontally
+ hstep = 1;
+ }
+ else
+ {
+ vstep = 1;
+ }
+
+ if ( i == lines.Size() - 1 )
+ {
+ // Draw arrow
+ DrawArrow( l->m_ptStart[ 0 ], l->m_ptStart[ 1 ], l->m_ptEnd[ 0 ], l->m_ptEnd[ 1 ], r, g, b, m_a );
+ // Draw a second time, but thicker
+ DrawArrow( l->m_ptStart[ 0 ] + hstep, l->m_ptStart[ 1 ] + vstep, l->m_ptEnd[ 0 ] + hstep, l->m_ptEnd[ 1 ] + vstep, r, g, b, m_a );
+ }
+ else
+ {
+ // Draw arrow
+ DrawLine( l->m_ptStart[ 0 ], l->m_ptStart[ 1 ], l->m_ptEnd[ 0 ], l->m_ptEnd[ 1 ], r, g, b, m_a );
+ // Draw a second time, but thicker
+ DrawLine( l->m_ptStart[ 0 ] + hstep, l->m_ptStart[ 1 ] + vstep, l->m_ptEnd[ 0 ] + hstep, l->m_ptEnd[ 1 ] + vstep, r, g, b, m_a );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : px -
+// &py -
+// *output -
+// *from -
+// *to -
+//-----------------------------------------------------------------------------
+void CArrowPanelEffect::ComputeBestPoint( int& px, int &py, vgui::Panel *output, vgui::Panel *from, vgui::Panel *to )
+{
+ int fw, fh;
+ int tw, th;
+ from->GetSize( fw, fh );
+ to->GetSize( tw, th );
+
+ // Convert top,left to local coordinates
+ int fx = 0, fy = 0;
+ int tx = 0, ty = 0;
+ from->LocalToScreen( fx, fy );
+ output->ScreenToLocal( fx, fy );
+
+ to->LocalToScreen( tx, ty );
+ output->ScreenToLocal( tx, ty );
+
+ fx--;
+ fy--;
+ tx--;
+ ty--;
+ fw+=2;
+ fh+=2;
+ tw+=2;
+ th+=2;
+
+ int type = 0;
+
+ // is to totally below from
+ if ( ty > ( fy + fh ) )
+ {
+ type = 0;
+ }
+ // is to totally above from
+ else if ( ty + th < fy )
+ {
+ type = 2;
+ }
+ // is to totally to the left of from
+ else if ( tx + tw < fx )
+ {
+ type = 3;
+ }
+ // is to totally to the rigth of from
+ else if ( tx > fx + fw )
+ {
+ type = 1;
+ }
+ else
+ {
+ type = 2;
+ }
+
+ int border = 1;
+
+ switch ( type )
+ {
+ // unknown, just use object center point
+ default:
+ case 4:
+ //
+ px = fx + fw / 2;
+ py = fy + fh / 2;
+ break;
+ //bottom
+ case 0:
+ px = fx + fw / 2;
+ py = fy + fh + border;
+ break;
+ // right
+ case 1:
+ px = fx + fw + border;
+ py = fy + fh / 2;
+ break;
+ // top
+ case 2:
+ px = fx + fw / 2;
+ py = fy - border;
+ break;
+ // left
+ case 3:
+ px = fx - border;
+ py = fy + fh / 2;
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Creates an axial line effect between the two specified panels
+//-----------------------------------------------------------------------------
+class CAxialLinePanelEffect : public CArrowPanelEffect
+{
+DECLARE_CLASS( CAxialLinePanelEffect, CArrowPanelEffect );
+public:
+ CAxialLinePanelEffect( ITFHintItem *owner );
+
+ virtual void doPaint( vgui::Panel *panel );
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *owner -
+//-----------------------------------------------------------------------------
+CAxialLinePanelEffect::CAxialLinePanelEffect( ITFHintItem *owner )
+: CArrowPanelEffect( owner )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *panel -
+//-----------------------------------------------------------------------------
+void CAxialLinePanelEffect::doPaint( vgui::Panel *panel )
+{
+ vgui::Panel *from = m_hPanel;
+ if ( !from || !IsVisibleIncludingParent( from ) )
+ return;
+
+ int r, g, b;
+
+ if ( m_bFlashing )
+ {
+ // Determine flash amount
+ float frac = fmod( gpGlobals->curtime, EFFECT_FLASH_TIME );
+ frac *= 2 * M_PI;
+ frac = cos( frac );
+
+ // Resample color
+ r = EffectResampleColor( m_r, frac );
+ g = EffectResampleColor( m_g, frac );
+ b = EffectResampleColor( m_b, frac );
+ }
+ else
+ {
+ r = m_r;
+ g = m_g;
+ b = m_b;
+ }
+
+ int startx, starty, startw, starth;
+ int endx, endy, endw, endh;
+
+ PanelToPanelRectangle( startx, starty, startw, starth, panel, from );
+
+ if ( !GetTargetRectangle( panel, endx, endy, endw, endh ) )
+ return;
+
+ CUtlVector< CConnectingLine > lines;
+
+ FindConnectingLines_Axial( startx, starty, startw, starth, endx, endy, endw, endh, lines );
+
+ int i;
+
+ if ( m_bDrawBorder )
+ {
+ for ( i = 0; i < lines.Size(); i++ )
+ {
+ CConnectingLine *l = &lines[ i ];
+
+ // Draw a black border
+ for ( int x = -1; x <= 1; x ++ )
+ {
+ for ( int y = -1; y <= 1; y ++ )
+ {
+ if ( !x && !y )
+ continue;
+
+ DrawLine( l->m_ptStart[ 0 ] + x, l->m_ptStart[1] + y, l->m_ptEnd[0] + x, l->m_ptEnd[1] + y, 0, 0, 0, m_a );
+ }
+ }
+ }
+ }
+
+ // Draw actual lines
+ for ( i = 0; i < lines.Size(); i++ )
+ {
+ CConnectingLine *l = &lines[ i ];
+ DrawLine( l->m_ptStart[ 0 ], l->m_ptStart[ 1 ], l->m_ptEnd[ 0 ], l->m_ptEnd[ 1 ], r, g, b, m_a );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *owner -
+// *target -
+// Output : EFFECT_HANDLE
+//-----------------------------------------------------------------------------
+EFFECT_HANDLE CreateFlashEffect( ITFHintItem *owner, vgui::Panel *target )
+{
+ if ( !g_pTF2RootPanel )
+ return EFFECT_INVALID_HANDLE;
+
+ CFlashBorderPanelEffect *e = new CFlashBorderPanelEffect( owner );
+
+ e->SetColor( EFFECT_R, EFFECT_G, EFFECT_B, EFFECT_A );
+ // e->SetEndTime( gpGlobals->curtime + 15.0f );
+ e->SetPanel( target );
+
+ g_pTF2RootPanel->AddEffect( e );
+
+ return e->GetHandle();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *owner -
+// *from -
+// *to -
+// Output : EFFECT_HANDLE
+//-----------------------------------------------------------------------------
+EFFECT_HANDLE CreateArrowEffect( ITFHintItem *owner, vgui::Panel *from, vgui::Panel *to )
+{
+ if ( !g_pTF2RootPanel )
+ return EFFECT_INVALID_HANDLE;
+
+ CArrowPanelEffect *e = new CArrowPanelEffect( owner );
+
+ e->SetColor( ARROW_R, ARROW_G, ARROW_B, ARROW_A );
+ e->SetPanel( from );
+ e->SetPanelOther( to );
+
+ g_pTF2RootPanel->AddEffect( e );
+
+ return e->GetHandle();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *owner -
+// *from -
+// *to -
+// Output : EFFECT_HANDLE
+//-----------------------------------------------------------------------------
+EFFECT_HANDLE CreateAxialLineEffect( ITFHintItem *owner, vgui::Panel *from, vgui::Panel *to )
+{
+ if ( !g_pTF2RootPanel )
+ return EFFECT_INVALID_HANDLE;
+
+ CAxialLinePanelEffect *e = new CAxialLinePanelEffect( owner );
+
+ e->SetColor( AXIALLINE_R, AXIALLINE_G, AXIALLINE_B, AXIALLINE_A );
+ e->SetPanel( from );
+ e->SetPanelOther( to );
+
+ e->SetFlashing( false );
+ e->SetDrawBorder( false );
+
+ g_pTF2RootPanel->AddEffect( e );
+
+ return e->GetHandle();
+}
+
+EFFECT_HANDLE CreateArrowEffectToPoint( ITFHintItem *owner, vgui::Panel *from, int x, int y )
+{
+ if ( !g_pTF2RootPanel )
+ return EFFECT_INVALID_HANDLE;
+
+ CArrowPanelEffect *e = new CArrowPanelEffect( owner );
+
+ e->SetColor( ARROW_R, ARROW_G, ARROW_B, ARROW_A );
+ e->SetPanel( from );
+ e->SetTargetPoint( x, y );
+
+ g_pTF2RootPanel->AddEffect( e );
+
+ return e->GetHandle();
+}
+
+EFFECT_HANDLE CreateAxialLineEffectToPoint( ITFHintItem *owner, vgui::Panel *from, int x, int y )
+{
+ if ( !g_pTF2RootPanel )
+ return EFFECT_INVALID_HANDLE;
+
+ CAxialLinePanelEffect *e = new CAxialLinePanelEffect( owner );
+
+ e->SetColor( AXIALLINE_R, AXIALLINE_G, AXIALLINE_B, AXIALLINE_A );
+ e->SetPanel( from );
+ e->SetTargetPoint( x, y );
+
+ e->SetFlashing( false );
+ e->SetDrawBorder( false );
+
+ g_pTF2RootPanel->AddEffect( e );
+
+ return e->GetHandle();
+}
+
+EFFECT_HANDLE CreateArrowEffectToRect( ITFHintItem *owner, vgui::Panel *from, int x, int y, int w, int h )
+{
+ if ( !g_pTF2RootPanel )
+ return EFFECT_INVALID_HANDLE;
+
+ CArrowPanelEffect *e = new CArrowPanelEffect( owner );
+
+ e->SetColor( ARROW_R, ARROW_G, ARROW_B, ARROW_A );
+ e->SetPanel( from );
+ e->SetTargetRect( x, y, w, h );
+
+ g_pTF2RootPanel->AddEffect( e );
+
+ return e->GetHandle();
+}
+
+EFFECT_HANDLE CreateAxialLineEffectToRect( ITFHintItem *owner, vgui::Panel *from, int x, int y, int w, int h )
+{
+ if ( !g_pTF2RootPanel )
+ return EFFECT_INVALID_HANDLE;
+
+ CAxialLinePanelEffect *e = new CAxialLinePanelEffect( owner );
+
+ e->SetColor( AXIALLINE_R, AXIALLINE_G, AXIALLINE_B, AXIALLINE_A );
+ e->SetPanel( from );
+ e->SetTargetRect( x, y, w, h );
+
+ e->SetFlashing( false );
+ e->SetDrawBorder( false );
+
+ g_pTF2RootPanel->AddEffect( e );
+
+ return e->GetHandle();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *owner -
+//-----------------------------------------------------------------------------
+void DestroyPanelEffects( ITFHintItem *owner )
+{
+ if ( !g_pTF2RootPanel )
+ return;
+
+ g_pTF2RootPanel->DestroyPanelEffects( owner );
+} \ No newline at end of file