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
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); |
|
}
|
|
|