Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
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.
 
 
 
 
 
 

1018 lines
27 KiB

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
//-----------------------------------------------------------------------------
// The panel responsible for rendering the 3D view in orthographic mode
//-----------------------------------------------------------------------------
#include "cbase.h"
#include <vgui/VGUI.h>
#include <vgui_controls/Controls.h>
#include <vgui/IVGui.h>
#include <vgui/IInput.h>
#include <vgui/ISurface.h>
#include "clientmode_commander.h"
#include "vgui_int.h"
#include "iinput.h"
#include "kbutton.h"
#include "hud_minimap.h"
#include "usercmd.h"
#include "mapdata.h"
#include "c_basetfplayer.h"
#include "view.h"
#include "view_shared.h"
#include "CommanderOverlay.h"
#include "C_TfTeam.h"
#include <vgui/MouseCode.h>
#include <vgui/KeyCode.h>
#include <vgui/IPanel.h>
#include "commanderoverlaypanel.h"
#include "PixelWriter.h"
#include "materialsystem/imaterialvar.h"
#include "materialsystem/itexture.h"
#include "vtf/vtf.h"
#include "engine/ivdebugoverlay.h"
static inline int AlphaMapIndex(int x, int y)
{
return y * FOG_ALPHAMAP_SIZE + x;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *commander -
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::SetCommanderView( CClientModeCommander *commander )
{
m_pCommanderView = commander;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CCommanderOverlayPanel::CCommanderOverlayPanel( void ) :
vgui::Panel( NULL, "CommanderOverlayPanel" ),
m_CursorCommander(vgui::dc_arrow),
m_CursorRightMouseMove(vgui::dc_hand)
{
MakePopup();
SetPaintBackgroundEnabled( false );
m_left.m_bMouseDown = false;
m_left.m_nXStart = 0;
m_left.m_nYStart = 0;
m_right.m_bMouseDown = false;
m_right.m_nXStart = 0;
m_right.m_nYStart = 0;
m_fZoom = 0;
m_flPreviousMaxWorldWidth = 0.0f;
SetVisible( false );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CCommanderOverlayPanel::~CCommanderOverlayPanel( void )
{
}
//-----------------------------------------------------------------------------
// Initialize rendering origin
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::InitializeRenderOrigin()
{
// Initializes the rendering origin
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
if ( player )
{
m_vecTacticalOrigin = player->GetAbsOrigin();
}
else
{
MapData().GetMapOrigin( m_vecTacticalOrigin );
}
Vector mins, maxs;
MapData().GetMapBounds( mins, maxs );
m_vecTacticalOrigin.z = maxs.z + TACTICAL_ZOFFSET;
m_vecTacticalAngles.Init( 90, 90, 0 );
BoundOrigin( m_vecTacticalOrigin );
}
//-----------------------------------------------------------------------------
// Computes the view range:
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::ComputeZoomRange()
{
// This is
m_MinWorldWidth = TACTICAL_MIN_VIEWABLE_SIZE;
// Get the world size
Vector mins, maxs, size;
MapData().GetMapBounds( mins, maxs );
VectorSubtract( maxs, mins, size );
float worldAspect = size[0] / size[1];
// size[ 0 ] *= 1.05f;
// size[ 1 ] *= 1.05f;
// Find out the panel aspect ratio
int w, h;
GetVisibleSize( w, h );
float panelAspect = (float)w / (float)h;
// Store off old zoom
m_flPreviousMaxWorldWidth = m_MaxWorldWidth;
if (panelAspect > worldAspect)
{
// In this case, to see the whole map,
// we'll have black areas on the left + right sides
// Make sure we choose a width big enough to display the entire height
m_MaxWorldWidth = size[1] * panelAspect;
}
else
{
// In this case, to see the whole map,
// we'll have black areas on the top + bottom
// Make sure we choose a width big enough to display the entire height
m_MaxWorldWidth = size[0];
}
// if flipping open/close the tech tree, preserver relative zoom amount
if ( m_flPreviousMaxWorldWidth )
{
float ratio = m_MaxWorldWidth / m_flPreviousMaxWorldWidth;
m_fZoom *= ratio;
}
}
//-----------------------------------------------------------------------------
// Call when the map changes
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::LevelInit( char const* pMapName )
{
// Always look at the entire map to start with
m_fZoom = 0;
m_flPreviousMaxWorldWidth = 0.0f;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::LevelShutdown( void )
{
}
//-----------------------------------------------------------------------------
// call these when commander view is enabled/disabled
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::Enable()
{
vgui::VPANEL pRoot = VGui_GetClientDLLRootPanel();
SetCursor(m_CursorCommander);
SetVisible( true );
// Make the viewport fill the root panel.
if( pRoot)
{
int wide, tall;
vgui::ipanel()->GetSize(pRoot, wide, tall);
// subtract out the technology UI size
tall -= 0;// xxx200
SetBounds(0, 0, wide, tall);
}
// Cache the orthographic view size range
ComputeZoomRange();
// Start out looking at the whole world
if (m_fZoom == 0)
m_fZoom = m_MaxWorldWidth;
// clamp
if (m_fZoom < m_MinWorldWidth)
m_fZoom = m_MinWorldWidth;
else if (m_fZoom > m_MaxWorldWidth)
m_fZoom = m_MaxWorldWidth;
// Figure out where the camera is
InitializeRenderOrigin();
vgui::ivgui()->AddTickSignal( GetVPanel() );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::Disable()
{
SetVisible( false );
// FIXME: Need a removeTickSignal!
// vgui::ivgui()->removeTickSignal( GetVPanel() );
}
//-----------------------------------------------------------------------------
// called when we're ticked...
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::OnTick()
{
if (!IsLocalPlayerInTactical() || !engine->IsInGame())
return;
}
//-----------------------------------------------------------------------------
// Purpose: Returns up to 32 players encoded as a bit per player in a 32 bit unsigned
// Output : unsigned int
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::GetSelectedPlayerBitField( CBitVec< MAX_PLAYERS >& bits )
{
CMapPlayers *pPlayer;
bits.ClearAll();
// draw all the visible players
for ( int playerNum = 0; playerNum < MAX_PLAYERS; playerNum++ )
{
pPlayer = &MapData().m_Players[ playerNum ];
if ( pPlayer->m_bSelected )
{
bits.Set( playerNum );
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Counts how many players are selected
// Output : int
//-----------------------------------------------------------------------------
int CCommanderOverlayPanel::CountSelectedPlayers( void )
{
CMapPlayers *pPlayer;
// bitfield variable
int count = 0;
// draw all the visible players
for ( int playerNum = 0; playerNum < MAX_PLAYERS; playerNum++ )
{
pPlayer = &MapData().m_Players[ playerNum ];
if ( pPlayer->m_bSelected )
{
count++;
}
}
return count;
}
//-----------------------------------------------------------------------------
// Purpose: Called when a key is pressed
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::OnKeyPressed(vgui::KeyCode code)
{
switch(code)
{
case vgui::KEY_SPACE:
if (m_fZoom != m_MaxWorldWidth)
{
ChangeZoomLevel(m_MaxWorldWidth);
}
else
{
Vector mouseWorldPos;
CenterOnMouse( mouseWorldPos );
ChangeZoomLevel(TACTICAL_SPACEBAR_VIEWABLE_SIZE);
// Place mouse over me
m_pCommanderView->MoveMouse( mouseWorldPos );
}
break;
default:
break;
}
}
//-----------------------------------------------------------------------------
// Purpose: when space is hit, show the entire view
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::ChangeZoomLevel( float newZoom )
{
// Make sure the mouse remains over the thing it started over
// Figure out worldspace movement based on picking ray
Vector rayOrigin, rayForward;
int mx, my;
GetMousePos( mx, my );
// Need to convert from screen space back to a worldspace ray
CreatePickingRay(
mx, my,
ScreenWidth(), ScreenHeight(),
CurrentViewOrigin(),
CurrentViewAngles(),
rayOrigin,
rayForward );
m_fZoom = newZoom;
BoundOrigin( m_vecTacticalOrigin );
// move mouse to center and zero out any delta
m_pCommanderView->MoveMouse( rayOrigin );
// RequestFocus();
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CCommanderOverlayPanel::IsRightMouseMapMoving( void )
{
return m_right.m_bMouseDown;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::RightMouseMapMove( void )
{
/*
// Figure out worldspace movement based on picking ray
Vector rayForward;
Vector vecEndPosCurrent, vecEndPosPrevious;
// Need to convert from screen space back to a worldspace ray
CreatePickingRay(
m_right.m_nXCurrent, m_right.m_nYCurrent,
ScreenWidth(), ScreenHeight(),
g_vecRenderOrigin,
g_vecRenderAngles,
vecEndPosCurrent,
rayForward );
engine->Con_NPrintf( 8, "x %i y %i hit %.3f %.3f",
m_right.m_nXCurrent, m_right.m_nYCurrent, vecEndPosCurrent.x, vecEndPosCurrent.y );
*/
if ( !m_right.m_bMouseDown )
return;
/*
// See if there is a delta in the current and previous mouse positions
//
int dx, dy;
dx = m_right.m_nXCurrent - m_right.m_nXPrev;
dy = m_right.m_nYCurrent - m_right.m_nYPrev;
// No relative move
if ( !dx && !dy )
return;
// Figure out worldspace movement based on picking ray
Vector rayForward;
Vector vecEndPosCurrent, vecEndPosPrevious;
// Need to convert from screen space back to a worldspace ray
CreatePickingRay(
m_right.m_nXCurrent, m_right.m_nYCurrent,
ScreenWidth(), ScreenHeight(),
g_vecRenderOrigin,
g_vecRenderAngles,
vecEndPosCurrent,
rayForward );
// Now create ray from old position
// Need to convert from screen space back to a worldspace ray
CreatePickingRay(
m_right.m_nXPrev, m_right.m_nYPrev,
ScreenWidth(), ScreenHeight(),
g_vecRenderOrigin,
g_vecRenderAngles,
vecEndPosPrevious,
rayForward );
// Remove z component
vecEndPosPrevious.z = 0.0;
vecEndPosCurrent.z = 0.0;
// Compute offset
Vector viewDelta;
VectorSubtract( vecEndPosCurrent, vecEndPosPrevious, viewDelta );
viewDelta.z = 0.0f;
VectorAdd( m_vecTacticalOrigin, viewDelta, m_vecTacticalOrigin );
m_pCommanderView->BoundOrigin( m_vecTacticalOrigin );
*/
}
//-----------------------------------------------------------------------------
// Purpose: Right mouse button down
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::RightMousePressed( void )
{
if ( m_left.m_bMouseDown || m_right.m_bMouseDown )
return;
SetCursor(m_CursorRightMouseMove);
StartMovingMouse( m_right );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::RightMouseReleased( void )
{
if ( !m_right.m_bMouseDown )
return;
m_right.m_bMouseDown = false;
int mx, my;
GetMousePos( mx, my );
UpdateMousePos( mx, my, m_right );
// Final move
RightMouseMapMove();
vgui::input()->SetMouseCapture( NULL );
SetCursor(m_CursorCommander);
// If the player's dead, and doesn't have the special sniper upgrade
// then check for respawn stations....
C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer();
if (!pPlayer)
return;
// If the player's dead, abort
if ( pPlayer->PlayerClass() == TFCLASS_SNIPER )
{
// Sniper's can request a respawn point when dead
//
Vector rayOrigin, rayForward;
Vector vecEndPos;
// Need to convert from screen space back to a worldspace ray
CreatePickingRay(
m_right.m_nXCurrent, m_right.m_nYCurrent,
ScreenWidth(), ScreenHeight(),
CurrentViewOrigin(),
CurrentViewAngles(),
rayOrigin,
rayForward );
// Now do the trace
trace_t tr;
vecEndPos = rayOrigin + rayForward * MAX_TRACE_LENGTH;
UTIL_TraceLine( rayOrigin, vecEndPos, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &tr );
// Didn't hit anything
if ( tr.fraction == 1.0 )
return;
char cmd[ 128 ];
Q_snprintf( cmd, sizeof( cmd ), "respawnpoint %i %i %i\n",
(int)tr.endpos.x,
(int)tr.endpos.y,
(int)tr.endpos.z );
engine->ServerCmd( cmd );
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : x -
// y -
// mouse -
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::UpdateMousePos( int x, int y, MouseDown_t& mouse )
{
// store previous
mouse.m_nXPrev = mouse.m_nXCurrent;
mouse.m_nYPrev = mouse.m_nYCurrent;
// update current
mouse.m_nXCurrent = x;
mouse.m_nYCurrent = y;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : x -
// y -
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::OnCursorMoved(int x, int y)
{
UpdateMousePos( x, y, m_left );
UpdateMousePos( x, y, m_right );
RightMouseMapMove();
// RequestFocus();
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : x -
// y -
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::GetMousePos( int& x, int& y )
{
vgui::input()->GetCursorPos( x, y );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : mouse -
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::StartMovingMouse( MouseDown_t& mouse )
{
mouse.m_bMouseDown = true;
GetMousePos( mouse.m_nXStart, mouse.m_nYStart );
mouse.m_nXCurrent = mouse.m_nXPrev = mouse.m_nXStart;
mouse.m_nYCurrent = mouse.m_nYPrev = mouse.m_nYStart;
vgui::input()->SetMouseCapture( GetVPanel() );
}
//-----------------------------------------------------------------------------
// Purpose: Left mouse button down
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::LeftMousePressed( void )
{
if ( m_left.m_bMouseDown || m_right.m_bMouseDown )
return;
StartMovingMouse( m_left );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : code -
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::OnMousePressed(vgui::MouseCode code)
{
switch ( code )
{
case vgui::MOUSE_LEFT:
LeftMousePressed();
break;
case vgui::MOUSE_RIGHT:
RightMousePressed();
break;
default:
BaseClass::OnMousePressed( code );
return;
}
// RequestFocus();
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : x0 -
// y0 -
// x1 -
// y1 -
// true -
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::SelectPlayersInRectangle( int x0, int y0, int x1, int y1, bool clearOldSelections /*= true*/ )
{
int num_selected = 0;
// Assume zero players in selection
if ( clearOldSelections )
{
m_bHaveActiveSelection = false;
}
else
{
// Count # selected
num_selected = CountSelectedPlayers();
}
CMapPlayers *pPlayer;
C_BaseTFPlayer *tf2player;
// See which players on my team are within the rectangle in screen space
//
for ( int playerNum = 1; playerNum <= MAX_PLAYERS; playerNum++ )
{
pPlayer = &MapData().m_Players[ playerNum - 1 ];
if ( clearOldSelections )
{
pPlayer->m_bSelected = false;
}
if ( playerNum > gpGlobals->maxClients )
{
continue;
}
tf2player = dynamic_cast<C_BaseTFPlayer *>( cl_entitylist->GetEnt( playerNum ) );
if ( !tf2player )
{
continue;
}
// Check pvs on this guy
// If the entity was in the commander's PVS then show it on the minimap, too
//
if ( ArePlayersOnSameTeam( engine->GetLocalPlayer(), playerNum ) == false )
{
continue;
}
// Check their actual draw position
int drawX, drawY;
Vector pos, screen;
pos = tf2player->GetAbsOrigin();
// Transform
debugoverlay->ScreenPosition( pos, screen );
// FIXME: Get the player icon size from where?!?
drawX = screen.x - 32;
drawY = screen.y - 40;
int intersectX = 64;
int intersectY = 64;
// Check for intersection ( with slop )
if ( drawX + intersectX < x0 )
continue;
if ( drawX > x1 )
continue;
if ( drawY + intersectY < y0 )
continue;
if ( drawY > y1 )
continue;
// Already selected?
if ( !pPlayer->m_bSelected )
{
// Add to selected list
pPlayer->m_bSelected = true;
num_selected++;
}
}
if ( num_selected != 0 )
{
m_bHaveActiveSelection = true;
}
}
//-----------------------------------------------------------------------------
// Returns the visible area (not including the tech tree)
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::GetVisibleSize( int& w, int& h )
{
GetSize( w, h );
// FIXME: Hack to make the map appear above the tech tree
h -= 200;
}
//-----------------------------------------------------------------------------
// Returns the visible area (not including the tech tree)
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::GetVisibleArea( Vector& mins, Vector& maxs )
{
float w, h;
GetVisibleOrthoSize( w, h );
ActualToVisibleOffset( mins );
mins += m_vecTacticalOrigin;
maxs = mins;
mins.x -= w; maxs.x +=w;
mins.y -= h; maxs.y +=h;
}
//-----------------------------------------------------------------------------
// Purpose: User let go of left mouse button
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::LeftMouseReleased( void )
{
if ( !m_left.m_bMouseDown )
return;
m_left.m_bMouseDown = false;
int mx, my;
GetMousePos( mx, my );
UpdateMousePos( mx, my, m_left );
vgui::input()->SetMouseCapture( NULL );
// Normalize the rectangle
int x0, y0, x1, y1;
x0 = MIN( m_left.m_nXStart, m_left.m_nXCurrent );
x1 = MAX( m_left.m_nXStart, m_left.m_nXCurrent );
y0 = MIN( m_left.m_nYStart, m_left.m_nYCurrent );
y1 = MAX( m_left.m_nYStart, m_left.m_nYCurrent );
bool clearOldStates = true;
if ( vgui::input()->IsKeyDown( vgui::KEY_LCONTROL ) )
{
clearOldStates = false;
}
SelectPlayersInRectangle( x0, y0, x1, y1, clearOldStates );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::GetOrthoRenderBox(Vector &vCenter, float &xSize, float &ySize)
{
vCenter = m_vecTacticalOrigin;
// min and max depends on the current zoom level
int w, h;
GetParent()->GetSize( w, h );
xSize = m_fZoom;
ySize = xSize * ( (float)h / (float)w );
xSize *= 0.5f;
ySize *= 0.5f;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::GetVisibleOrthoSize(float &xSize, float &ySize)
{
// min and max depends on the current zoom level
int w, h;
GetVisibleSize( w, h );
xSize = m_fZoom;
ySize = xSize * ( (float)h / (float)w );
xSize *= 0.5f;
ySize *= 0.5f;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CCommanderOverlayPanel::WorldUnitsPerPixel()
{
int w, h;
GetParent()->GetSize( w, h );
return m_fZoom / w;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::ActualToVisibleOffset( Vector& offset )
{
// FIXME: This doesn't work arbitrarily; we assume the visible
// part is on the top of the screen..
int w, h, wact, hact;
GetVisibleSize( w, h );
GetParent()->GetSize( wact, hact );
float worldUnitsPerPixel = m_fZoom / wact;
float dWorldY = (hact - h) * 0.5f * worldUnitsPerPixel;
offset.Init( 0, dWorldY, 0 );
}
//-----------------------------------------------------------------------------
// Purpose: Make sure origin is inside map x, y bounds ( not z )
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::BoundOrigin( Vector& camera )
{
// We're going to do this entire computation assuming the camera
// is in the center of the viewable area, which it isn't. At the
// end, we'll need to apply a fixup to deal with that
Vector mins, maxs, halfsize;
MapData().GetMapBounds( mins, maxs );
VectorSubtract( maxs, mins, halfsize );
halfsize *= 0.5f;
// avoid black edges...
float dim[2];
GetVisibleOrthoSize( dim[0], dim[1] );
// Compute the position of the center of the visible area based on
// the new suggested camera position
Vector actualToVisible, newVisCenter;
ActualToVisibleOffset( actualToVisible );
VectorAdd( camera, actualToVisible, newVisCenter );
// Only bound x & y
for ( int i = 0; i < 2; i++ )
{
if (dim[i] > halfsize[i])
{
newVisCenter[i] = mins[i] + halfsize[i];
}
else
{
newVisCenter[ i ] = MAX( newVisCenter[i], mins[i] + dim[i] );
newVisCenter[ i ] = MIN( newVisCenter[i], maxs[i] - dim[i] );
}
}
// Remember: The viewport takes up the entire screen; but the visible
// area only takes up the top half of the screen. Therefore, we need to
// set the origin so that the center of what we want lies at the
// center of the visible region
VectorSubtract( newVisCenter, actualToVisible, camera );
}
//-----------------------------------------------------------------------------
// Purpose:
// Given mouse/screen positions as well as the current
// render origin and angles, returns a unit vector through the mouse position
// that can be used to trace into the world under the mouse click pixel.
// Input : fov -
// mousex -
// mousey -
// screenwidth -
// screenheight -
// vecRenderAngles -
// c_x -
// vpn -
// vup -
// 360.0 -
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::CreatePickingRay( int mousex, int mousey,
int screenwidth, int screenheight,
const Vector& vecRenderOrigin,
const QAngle& vecRenderAngles,
Vector &rayOrigin,
Vector &rayDirection
)
{
Vector vCenter;
float xSize, ySize;
GetOrthoRenderBox(vCenter, xSize, ySize);
float xPos = RemapVal(mousex, 0, screenwidth, vCenter.x-xSize, vCenter.x+xSize);
float yPos = RemapVal(mousey, 0, screenheight, vCenter.y+ySize, vCenter.y-ySize); // (flip screen y)
rayOrigin.Init(xPos, yPos, vCenter.z);
rayDirection.Init(0, 0, -1);
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::OnMouseReleased(vgui::MouseCode code)
{
switch ( code )
{
case vgui::MOUSE_LEFT:
LeftMouseReleased();
break;
case vgui::MOUSE_RIGHT:
RightMouseReleased();
break;
default:
BaseClass::OnMouseReleased( code );
return;
}
// RequestFocus();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::CenterOnMouse( Vector& mouseWorldPos )
{
// Figure out worldspace movement based on picking ray
Vector rayForward;
Vector centerOrigin;
int mx, my;
GetMousePos( mx, my );
// Need to convert from screen space back to a worldspace ray
CreatePickingRay(
mx, my,
ScreenWidth(), ScreenHeight(),
CurrentViewOrigin(),
CurrentViewAngles(),
mouseWorldPos,
rayForward );
CreatePickingRay(
ScreenWidth()/2, ScreenHeight()/2,
ScreenWidth(), ScreenHeight(),
CurrentViewOrigin(),
CurrentViewAngles(),
centerOrigin,
rayForward );
Vector offset;
VectorSubtract( mouseWorldPos, centerOrigin, offset );
offset.z = 0.0f;
VectorAdd( m_vecTacticalOrigin, offset, m_vecTacticalOrigin );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : delta -
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::OnMouseWheeled(int delta)
{
// Figure out worldspace movement based on picking ray
Vector rayOrigin;
CenterOnMouse( rayOrigin );
// Gotta do the zoom after picking the ray, or it'll use the wrong zoom factor
// for computing the picking ray
if ( delta < 0 )
{
m_fZoom *= 1.25f;
}
else if ( delta > 0 )
{
m_fZoom /= 1.25f;
}
m_fZoom = MIN( m_fZoom, m_MaxWorldWidth );
m_fZoom = MAX( m_fZoom, m_MinWorldWidth );
BoundOrigin( m_vecTacticalOrigin );
// move mouse to center and zero out any delta
m_pCommanderView->MoveMouse( rayOrigin );
// RequestFocus();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCommanderOverlayPanel::Paint()
{
if ( !m_left.m_bMouseDown )
return;
// Update mouse position, so we don't get the 1 frame lag
int mx, my;
GetMousePos( mx, my );
UpdateMousePos( mx, my, m_left );
int x0, x1, y0, y1;
// Make sure it's normalized
x0 = MIN( m_left.m_nXStart, m_left.m_nXCurrent );
x1 = MAX( m_left.m_nXStart, m_left.m_nXCurrent );
y0 = MIN( m_left.m_nYStart, m_left.m_nYCurrent );
y1 = MAX( m_left.m_nYStart, m_left.m_nYCurrent );
// Draw selection rectangle
vgui::surface()->DrawSetColor( 200, 220, 250, 192 );
vgui::surface()->DrawOutlinedRect( x0, y0, x1, y1 );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CCommanderOverlayPanel::GetZoom( void )
{
return (m_fZoom - m_MinWorldWidth) / (m_MaxWorldWidth - m_MinWorldWidth);
}