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.
1094 lines
25 KiB
1094 lines
25 KiB
5 years ago
|
//========= 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 );
|
||
|
}
|