//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ // //=============================================================================// //----------------------------------------------------------------------------- // The panel responsible for rendering the 3D view in orthographic mode //----------------------------------------------------------------------------- #include "cbase.h" #include #include #include #include #include #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 #include #include #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( 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); }