summaryrefslogtreecommitdiff
path: root/game/client/tf2/commanderoverlaypanel.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/client/tf2/commanderoverlaypanel.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'game/client/tf2/commanderoverlaypanel.cpp')
-rw-r--r--game/client/tf2/commanderoverlaypanel.cpp1018
1 files changed, 1018 insertions, 0 deletions
diff --git a/game/client/tf2/commanderoverlaypanel.cpp b/game/client/tf2/commanderoverlaypanel.cpp
new file mode 100644
index 0000000..5ef2914
--- /dev/null
+++ b/game/client/tf2/commanderoverlaypanel.cpp
@@ -0,0 +1,1018 @@
+//========= 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);
+}