diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..4703027c --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,70 @@ +name: Compilation + +on: + push: + pull_request: + +jobs: + build: + strategy: + matrix: + include: + - os: ubuntu-22.04 + cc: clang-22 + cxx: clang++-22 + container_image: ghcr.io/alliedmodders/build-containers/debian11-clang22:latest + - os: windows-2022 + cc: msvc + fail-fast: false + + name: ${{ matrix.os }} - ${{ matrix.cc }} + runs-on: ${{ matrix.os }} + container: + image: ${{ matrix.container_image }} + + steps: + - uses: actions/checkout@v7 + name: Repository checkout + with: + fetch-depth: 0 + submodules: recursive + path: repository + + - uses: actions/checkout@v7 + name: AMBuild checkout + if: startsWith(runner.os, 'Windows') + with: + repository: alliedmodders/ambuild + ref: fe8c99ccd24fa926bf6ac6b9935a5fc03df06a72 + fetch-depth: 0 + submodules: recursive + path: ambuild + + - name: Setup AMBuild + if: startsWith(runner.os, 'Windows') + shell: bash + run: | + python3 -m pip install ./ambuild + + - name: Select clang compiler + if: startsWith(runner.os, 'Linux') + run: | + echo "CC=${{ matrix.cc }}" >> $GITHUB_ENV + echo "CXX=${{ matrix.cxx }}" >> $GITHUB_ENV + ${{ matrix.cc }} --version + ${{ matrix.cxx }} --version + + - name: Build + shell: bash + working-directory: repository + run: | + mkdir build + cd build + python3 ../configure.py + ambuild + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: libs_${{ runner.os }} + path: repository/build/lib \ No newline at end of file diff --git a/AMBuildScript b/AMBuildScript index 0cd89365..0d2670ea 100644 --- a/AMBuildScript +++ b/AMBuildScript @@ -93,6 +93,8 @@ class SDKConfig(object): '-Wno-tautological-overlap-compare', '-Wno-tautological-constant-out-of-range-compare', '-Wno-undefined-bool-conversion', + '-Wno-nontrivial-memcall', + '-Wno-sync-alignment', '-msse', '-fPIC' ] diff --git a/common/ServerBrowser/blacklisted_server_manager.cpp b/common/ServerBrowser/blacklisted_server_manager.cpp index 95fcbfc9..b542baa7 100644 --- a/common/ServerBrowser/blacklisted_server_manager.cpp +++ b/common/ServerBrowser/blacklisted_server_manager.cpp @@ -43,7 +43,7 @@ void CBlacklistedServerManager::Reset( void ) //----------------------------------------------------------------------------- int CBlacklistedServerManager::LoadServersFromFile( const char *pszFilename, bool bResetTimes ) { - KeyValues *pKV = new KeyValues( "serverblacklist" ); + KeyValuesAD pKV( "serverblacklist" ); if ( !pKV->LoadFromFile( g_pFullFileSystem, pszFilename, "MOD" ) ) return 0; @@ -75,8 +75,6 @@ int CBlacklistedServerManager::LoadServersFromFile( const char *pszFilename, boo } } - pKV->deleteThis(); - return count; } diff --git a/devtools/bin/tier0.dll b/devtools/bin/tier0.dll index c3533325..16cc2e71 100644 Binary files a/devtools/bin/tier0.dll and b/devtools/bin/tier0.dll differ diff --git a/devtools/bin/vpc.exe b/devtools/bin/vpc.exe index 8bdf3d16..e2270667 100644 Binary files a/devtools/bin/vpc.exe and b/devtools/bin/vpc.exe differ diff --git a/devtools/bin/vstdlib.dll b/devtools/bin/vstdlib.dll index 319ef7e4..44fff21e 100644 Binary files a/devtools/bin/vstdlib.dll and b/devtools/bin/vstdlib.dll differ diff --git a/game/client/c_baseentity.cpp b/game/client/c_baseentity.cpp index 14dc689c..adbd3914 100644 --- a/game/client/c_baseentity.cpp +++ b/game/client/c_baseentity.cpp @@ -457,6 +457,7 @@ BEGIN_RECV_TABLE_NOBASE(C_BaseEntity, DT_BaseEntity) RecvPropInt(RECVINFO(m_clrRender)), RecvPropInt(RECVINFO(m_iTeamNum)), RecvPropInt(RECVINFO(m_CollisionGroup)), + RecvPropFloat(RECVINFO(m_flGravity)), RecvPropFloat(RECVINFO(m_flElasticity)), RecvPropFloat(RECVINFO(m_flShadowCastDistance)), RecvPropEHandle( RECVINFO(m_hOwnerEntity) ), @@ -539,7 +540,7 @@ BEGIN_PREDICTION_DATA_NO_BASE( C_BaseEntity ) // DEFINE_FIELD( m_flLastMessageTime, FIELD_FLOAT ), DEFINE_FIELD( m_vecBaseVelocity, FIELD_VECTOR ), DEFINE_FIELD( m_iEFlags, FIELD_INTEGER ), - DEFINE_FIELD( m_flGravity, FIELD_FLOAT ), + DEFINE_PRED_FIELD( m_flGravity, FIELD_FLOAT, FTYPEDESC_INSENDTABLE | FTYPEDESC_NOERRORCHECK ), // DEFINE_FIELD( m_ModelInstance, FIELD_SHORT ), DEFINE_FIELD( m_flProxyRandomValue, FIELD_FLOAT ), diff --git a/game/client/c_baseplayer.cpp b/game/client/c_baseplayer.cpp index b5ce6728..76d66937 100644 --- a/game/client/c_baseplayer.cpp +++ b/game/client/c_baseplayer.cpp @@ -418,6 +418,9 @@ LINK_ENTITY_TO_CLASS( player, C_BasePlayer ); C_BasePlayer::C_BasePlayer() : m_iv_vecViewOffset( "C_BasePlayer::m_iv_vecViewOffset" ) { AddVar( &m_vecViewOffset, &m_iv_vecViewOffset, LATCH_SIMULATION_VAR ); + + AddVar( &m_Local.m_vecPunchAngle, &m_Local.m_iv_vecPunchAngle, LATCH_SIMULATION_VAR ); + AddVar( &m_Local.m_vecPunchAngleVel, &m_Local.m_iv_vecPunchAngleVel, LATCH_SIMULATION_VAR ); #ifdef _DEBUG m_vecLadderNormal.Init(); diff --git a/game/client/c_baseviewmodel.cpp b/game/client/c_baseviewmodel.cpp index 07a1e71c..a3431e7c 100644 --- a/game/client/c_baseviewmodel.cpp +++ b/game/client/c_baseviewmodel.cpp @@ -19,6 +19,7 @@ #include #include "hltvcamera.h" #ifdef TF_CLIENT_DLL + #include "c_tf_player.h" #include "tf_weaponbase.h" #endif @@ -91,6 +92,22 @@ void FormatViewModelAttachment( Vector &vOrigin, bool bInverse ) vOrigin = pViewSetup->origin + vOut; } +#ifdef TF_CLIENT_DLL +bool TeamFortress_ShouldFlipClientViewModel( void ) +{ + if ( IsLocalPlayerSpectator() ) + { + // Use spectated client's handedness preference + C_TFPlayer *pSpecTarget = ToTFPlayer( UTIL_PlayerByIndex( GetSpectatorTarget() ) ); + if ( pSpecTarget ) + { + return pSpecTarget->m_bFlipViewModels; + } + } + + return cl_flipviewmodels.GetBool(); +} +#endif //TF_CLIENT_DLL void C_BaseViewModel::FormatViewModelAttachment( int nAttachment, matrix3x4_t &attachmentToWorld ) { @@ -211,7 +228,7 @@ bool C_BaseViewModel::ShouldFlipViewModel() CBaseCombatWeapon *pWeapon = m_hWeapon.Get(); if ( pWeapon ) { - return pWeapon->m_bFlipViewModel != cl_flipviewmodels.GetBool(); + return pWeapon->m_bFlipViewModel != TeamFortress_ShouldFlipClientViewModel(); } #endif diff --git a/game/client/c_baseviewmodel.h b/game/client/c_baseviewmodel.h index fa59176d..2bc02945 100644 --- a/game/client/c_baseviewmodel.h +++ b/game/client/c_baseviewmodel.h @@ -16,4 +16,8 @@ #include "utlvector.h" #include "baseviewmodel_shared.h" +#ifdef TF_CLIENT_DLL +bool TeamFortress_ShouldFlipClientViewModel( void ); +#endif //TF_CLIENT_DLL + #endif // C_BASEVIEWMODEL_H diff --git a/game/client/c_point_commentary_node.cpp b/game/client/c_point_commentary_node.cpp index 527d5ca0..19131424 100644 --- a/game/client/c_point_commentary_node.cpp +++ b/game/client/c_point_commentary_node.cpp @@ -441,10 +441,10 @@ void CHudCommentary::Paint() // Draw the speaker names // Get our scheme and font information vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); - vgui::HFont hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "CommentaryDefault" ); + vgui::HFont hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "CommentaryDefault", true ); if ( !hFont ) { - hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "Default" ); + hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "Default", true ); } vgui::surface()->DrawSetTextFont( hFont ); vgui::surface()->DrawSetTextColor( clr ); diff --git a/game/client/c_slideshow_display.cpp b/game/client/c_slideshow_display.cpp index b721f4c3..6416ea35 100644 --- a/game/client/c_slideshow_display.cpp +++ b/game/client/c_slideshow_display.cpp @@ -267,7 +267,7 @@ void C_SlideshowDisplay::BuildSlideShowImagesList( void ) char szFullFileName[_MAX_PATH]; Q_snprintf( szFullFileName, sizeof( szFullFileName ), "materials/vgui/%s/%s", m_szSlideshowDirectory, szMatFileName ); - KeyValues *pMaterialKeys = new KeyValues( "material" ); + KeyValuesAD pMaterialKeys( "material" ); bool bLoaded = pMaterialKeys->LoadFromFile( g_pFullFileSystem, szFullFileName, NULL ); if ( bLoaded ) diff --git a/game/client/client_thinklist.h b/game/client/client_thinklist.h index 3d3e1744..9d3b3b54 100644 --- a/game/client/client_thinklist.h +++ b/game/client/client_thinklist.h @@ -121,7 +121,7 @@ inline ClientThinkHandle_t CClientThinkList::GetInvalidThinkHandle() inline CClientThinkList::ThinkEntry_t* CClientThinkList::GetThinkEntry( ClientThinkHandle_t hThink ) { - return &m_ThinkEntries[ (unsigned long)hThink ]; + return &m_ThinkEntries[ (uintp)hThink ]; } diff --git a/game/client/clientmode_shared.cpp b/game/client/clientmode_shared.cpp index 7fd78629..54933d24 100644 --- a/game/client/clientmode_shared.cpp +++ b/game/client/clientmode_shared.cpp @@ -837,23 +837,26 @@ void ClientModeShared::StartMessageMode( int iMessageModeType ) } #if defined( TF_CLIENT_DLL ) - bool bSuspensionInMatch = GTFGCClientSystem() && GTFGCClientSystem()->BHaveChatSuspensionInCurrentMatch(); - if ( !cl_enable_text_chat.GetBool() || bSuspensionInMatch ) + if ( iMessageModeType == MM_SAY || iMessageModeType == MM_SAY_TEAM ) { - CBaseHudChat *pHUDChat = ( CBaseHudChat * ) GET_HUDELEMENT( CHudChat ); - if ( pHUDChat ) + bool bSuspensionInMatch = GTFGCClientSystem() && GTFGCClientSystem()->BHaveChatSuspensionInCurrentMatch(); + if ( !cl_enable_text_chat.GetBool() || bSuspensionInMatch ) { - const char *pszReason = "#TF_Chat_Disabled"; - if ( bSuspensionInMatch ) + CBaseHudChat *pHUDChat = ( CBaseHudChat * ) GET_HUDELEMENT( CHudChat ); + if ( pHUDChat ) { - pszReason = "#TF_Chat_Unavailable"; - } + const char *pszReason = "#TF_Chat_Disabled"; + if ( bSuspensionInMatch ) + { + pszReason = "#TF_Chat_Unavailable"; + } - char szLocalized[100]; - g_pVGuiLocalize->ConvertUnicodeToANSI( g_pVGuiLocalize->Find( pszReason ), szLocalized, sizeof( szLocalized ) ); - pHUDChat->ChatPrintf( 0, CHAT_FILTER_NONE, "%s ", szLocalized ); + char szLocalized[100]; + g_pVGuiLocalize->ConvertUnicodeToANSI( g_pVGuiLocalize->Find( pszReason ), szLocalized, sizeof( szLocalized ) ); + pHUDChat->ChatPrintf( 0, CHAT_FILTER_NONE, "%s ", szLocalized ); + } + return; } - return; } #endif // TF_CLIENT_DLL diff --git a/game/client/econ/base_loadout_panel.cpp b/game/client/econ/base_loadout_panel.cpp index 2813c03d..a27c806e 100644 --- a/game/client/econ/base_loadout_panel.cpp +++ b/game/client/econ/base_loadout_panel.cpp @@ -19,6 +19,7 @@ #include "vgui_controls/ComboBox.h" #include "vgui/IInput.h" #include "econ_ui.h" +#include "c_tf_player.h" // memdbgon must be the last include file in a .cpp file!!! #include @@ -265,8 +266,9 @@ void CBaseLoadoutPanel::ShowPanel( int iClass, bool bBackpack, bool bReturningFr UpdateModelPanels(); // make the first slot be selected so controller input will work - static ConVarRef joystick( "joystick" ); - if( joystick.IsValid() && joystick.GetBool() && m_pItemModelPanels.Count() && m_pItemModelPanels[0] ) + //static ConVarRef joystick( "joystick" ); + bool bSteamController = ::input->IsSteamControllerActive(); + if( bSteamController && m_pItemModelPanels.Count() && m_pItemModelPanels[0] ) { m_pItemModelPanels[0]->SetSelected( true ); m_pItemModelPanels[0]->RequestFocus(); @@ -678,6 +680,7 @@ bool CBaseLoadoutPanel::HandleItemSelectionKeyPressed( vgui::KeyCode code ) if ( nButtonCode == KEY_XBUTTON_UP || nButtonCode == KEY_XSTICK1_UP || nButtonCode == KEY_XSTICK2_UP || + nButtonCode == STEAMCONTROLLER_DPAD_UP || nButtonCode == KEY_UP ) { SelectAdjacentItem( 0, -1 ); @@ -730,7 +733,7 @@ bool CBaseLoadoutPanel::HandleItemSelectionKeyPressed( vgui::KeyCode code ) } return true; } - else if ( nButtonCode == KEY_XBUTTON_Y ) + else if ( nButtonCode == KEY_XBUTTON_Y || nButtonCode == STEAMCONTROLLER_Y ) { m_bTooltipKeyPressed = true; CItemModelPanel *pSelection = GetFirstSelectedItemModelPanel( false ); @@ -754,7 +757,7 @@ bool CBaseLoadoutPanel::HandleItemSelectionKeyPressed( vgui::KeyCode code ) bool CBaseLoadoutPanel::HandleItemSelectionKeyReleased( vgui::KeyCode code ) { ButtonCode_t nButtonCode = GetBaseButtonCode( code ); - if( nButtonCode == KEY_XBUTTON_Y ) + if( nButtonCode == KEY_XBUTTON_Y || nButtonCode == STEAMCONTROLLER_Y ) { m_bTooltipKeyPressed = false; m_pMouseOverTooltip->HideTooltip(); diff --git a/game/client/econ/econ_controls.cpp b/game/client/econ/econ_controls.cpp index 8cf33516..0d2a89d0 100644 --- a/game/client/econ/econ_controls.cpp +++ b/game/client/econ/econ_controls.cpp @@ -1910,7 +1910,7 @@ void CExplanationPopup::OnKeyCodePressed( vgui::KeyCode code ) ButtonCode_t nButtonCode = GetBaseButtonCode( code ); // swallow all keys - if ( nButtonCode == KEY_XBUTTON_B ) + if ( nButtonCode == KEY_XBUTTON_B || nButtonCode == STEAMCONTROLLER_B ) { OnCommand( "close" ); return; @@ -1918,6 +1918,7 @@ void CExplanationPopup::OnKeyCodePressed( vgui::KeyCode code ) else if ( nButtonCode == KEY_XBUTTON_LEFT || nButtonCode == KEY_XSTICK1_LEFT || nButtonCode == KEY_XSTICK2_LEFT || + nButtonCode == STEAMCONTROLLER_DPAD_LEFT || code == KEY_LEFT ) { OnCommand( "prevexplanation" ); @@ -1926,6 +1927,7 @@ void CExplanationPopup::OnKeyCodePressed( vgui::KeyCode code ) else if ( nButtonCode == KEY_XBUTTON_RIGHT || nButtonCode == KEY_XSTICK1_RIGHT || nButtonCode == KEY_XSTICK2_RIGHT || + nButtonCode == STEAMCONTROLLER_DPAD_RIGHT || code == KEY_RIGHT ) { OnCommand( "nextexplanation" ); diff --git a/game/client/econ/item_pickup_panel.cpp b/game/client/econ/item_pickup_panel.cpp index 65d43b28..11d62951 100644 --- a/game/client/econ/item_pickup_panel.cpp +++ b/game/client/econ/item_pickup_panel.cpp @@ -473,6 +473,7 @@ void CItemPickupPanel::OnKeyCodePressed( vgui::KeyCode code ) else if ( nButtonCode == KEY_XBUTTON_RIGHT || nButtonCode == KEY_XSTICK1_RIGHT || nButtonCode == KEY_XSTICK2_RIGHT || + nButtonCode == STEAMCONTROLLER_DPAD_RIGHT || nButtonCode == KEY_RIGHT ) { OnCommand( "nextitem" ); @@ -480,6 +481,7 @@ void CItemPickupPanel::OnKeyCodePressed( vgui::KeyCode code ) else if ( nButtonCode == KEY_XBUTTON_LEFT || nButtonCode == KEY_XSTICK1_LEFT || nButtonCode == KEY_XSTICK2_LEFT || + nButtonCode == STEAMCONTROLLER_DPAD_LEFT || nButtonCode == KEY_LEFT ) { OnCommand( "previtem" ); @@ -848,7 +850,7 @@ void CItemDiscardPanel::OnKeyCodePressed( vgui::KeyCode code ) { ButtonCode_t nButtonCode = GetBaseButtonCode( code ); - if( nButtonCode == KEY_XBUTTON_B ) + if( nButtonCode == KEY_XBUTTON_B || nButtonCode == STEAMCONTROLLER_B ) { OnCommand( "vguicancel" ); } diff --git a/game/client/econ/item_selection_panel.cpp b/game/client/econ/item_selection_panel.cpp index 07ac094a..5f5dc7b0 100644 --- a/game/client/econ/item_selection_panel.cpp +++ b/game/client/econ/item_selection_panel.cpp @@ -378,9 +378,10 @@ void CItemSelectionPanel::OnKeyCodePressed( vgui::KeyCode code ) NotifySelectionReturned( pItemPanel ); } } - else if( nButtonCode == KEY_XBUTTON_B ) + else if( nButtonCode == KEY_XBUTTON_B || nButtonCode == STEAMCONTROLLER_B ) { - PostMessageSelectionReturned( INVALID_ITEM_ID ); + //match the same behaviour as pressing ESC + PostMessageSelectionReturned( 0 ); OnClose(); } else @@ -1085,8 +1086,9 @@ void CEquipSlotItemSelectionPanel::UpdateModelPanelsForSelection( void ) int nPageStart = GetCurrentPage() * GetNumSlotsPerPage(); nOldSelection += nPageStart; - static ConVarRef joystick( "joystick" ); - if ( joystick.IsValid() && joystick.GetBool() ) + //static ConVarRef joystick( "joystick" ); + bool bSteamController = ::input->IsSteamControllerActive(); + if ( bSteamController ) { if( nOldSelection == -1 || nOldSelection >= vecDisplayItems.Count() ) nOldSelection = nPageStart; @@ -1102,7 +1104,7 @@ void CEquipSlotItemSelectionPanel::UpdateModelPanelsForSelection( void ) m_pItemModelPanels[i]->SetShowGreyedOutTooltip( true ); m_pItemModelPanels[i]->SetGreyedOut( NULL ); m_pItemModelPanels[i]->SetNoItemText( "#SelectNoItemSlot" ); - bool bSelected = joystick.IsValid() && joystick.GetBool() && iItemIndex == nOldSelection; + bool bSelected = bSteamController && iItemIndex == nOldSelection; m_pItemModelPanels[i]->SetSelected( bSelected ); m_pItemModelPanels[i]->SetShowQuantity( true ); m_pItemModelPanels[i]->SetForceShowEquipped( false ); diff --git a/game/client/hl2/c_basehlplayer.cpp b/game/client/hl2/c_basehlplayer.cpp index 779ba954..7f838d19 100644 --- a/game/client/hl2/c_basehlplayer.cpp +++ b/game/client/hl2/c_basehlplayer.cpp @@ -76,9 +76,6 @@ static ConCommand dropprimary("dropprimary", CC_DropPrimary, "dropprimary: Drops //----------------------------------------------------------------------------- C_BaseHLPlayer::C_BaseHLPlayer() { - AddVar( &m_Local.m_vecPunchAngle, &m_Local.m_iv_vecPunchAngle, LATCH_SIMULATION_VAR ); - AddVar( &m_Local.m_vecPunchAngleVel, &m_Local.m_iv_vecPunchAngleVel, LATCH_SIMULATION_VAR ); - m_flZoomStart = 0.0f; m_flZoomEnd = 0.0f; m_flZoomRate = 0.0f; diff --git a/game/client/hud_basechat.cpp b/game/client/hud_basechat.cpp index 20122a33..cc17aa80 100644 --- a/game/client/hud_basechat.cpp +++ b/game/client/hud_basechat.cpp @@ -1186,7 +1186,7 @@ void CBaseHudChat::StartMessageMode( int iMessageModeType ) { case MM_SAY: pszPrompt = g_pVGuiLocalize->Find( "#chat_say" ); break; case MM_SAY_TEAM: pszPrompt = g_pVGuiLocalize->Find( "#chat_say_team" ); break; - case MM_SAY_PARTY: pszPrompt = g_pVGuiLocalize->Find( "#chat_party" ); break; + case MM_SAY_PARTY: pszPrompt = g_pVGuiLocalize->Find( "#chat_say_party" ); break; } if ( pszPrompt ) diff --git a/game/client/hud_closecaption.cpp b/game/client/hud_closecaption.cpp index 2d9ca9da..311cd4c0 100644 --- a/game/client/hud_closecaption.cpp +++ b/game/client/hud_closecaption.cpp @@ -1596,7 +1596,7 @@ void CHudCloseCaption::CreateFonts( void ) { vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( GetScheme() ); - m_hFonts[CCFONT_NORMAL] = pScheme->GetFont( "CloseCaption_Normal", true ); + m_hFonts[CCFONT_NORMAL] = pScheme->GetFont( "CloseCaption", true ); if ( IsPC() ) { diff --git a/game/client/in_camera.cpp b/game/client/in_camera.cpp index ec40ac18..68bcb68a 100644 --- a/game/client/in_camera.cpp +++ b/game/client/in_camera.cpp @@ -683,7 +683,7 @@ void CInput::CAM_ToThirdPerson(void) { m_fCameraInThirdPerson = true; - g_ThirdPersonManager.SetCameraOffsetAngles( Vector( viewangles[ YAW ], viewangles[ PITCH ], CAM_MIN_DIST ) ); + g_ThirdPersonManager.SetCameraOffsetAngles( Vector( viewangles[ PITCH ], viewangles[ YAW ], CAM_MIN_DIST ) ); } cam_command.SetValue( 0 ); diff --git a/game/client/movehelper_client.cpp b/game/client/movehelper_client.cpp index ccdba935..cb4b3e16 100644 --- a/game/client/movehelper_client.cpp +++ b/game/client/movehelper_client.cpp @@ -191,12 +191,12 @@ void CMoveHelperClient::ProcessImpacts( void ) } // misyl: Debug - if ( vOldLocalVel != vOldAbsVel ) - { - Msg( "%d\n", gpGlobals->tickcount ); - Msg( "vOldLocalVel: %f %f %f\n", vOldLocalVel.x, vOldLocalVel.y, vOldLocalVel.z ); - Msg( "vOldAbsVel: %f %f %f\n", vOldAbsVel.x, vOldAbsVel.y, vOldAbsVel.z ); - } +// if ( vOldLocalVel != vOldAbsVel ) +// { +// Msg( "%d\n", gpGlobals->tickcount ); +// Msg( "vOldLocalVel: %f %f %f\n", vOldLocalVel.x, vOldLocalVel.y, vOldLocalVel.z ); +// Msg( "vOldAbsVel: %f %f %f\n", vOldAbsVel.x, vOldAbsVel.y, vOldAbsVel.z ); +// } // Restore the velocity m_pHost->SetAbsVelocity( vOldAbsVel ); //m_pHost->SetLocalVelocity( vOldLocalVel ); diff --git a/game/client/particlemgr.cpp b/game/client/particlemgr.cpp index bf2b394b..0ff7365f 100644 --- a/game/client/particlemgr.cpp +++ b/game/client/particlemgr.cpp @@ -146,6 +146,7 @@ CParticleEffectBinding::CParticleEffectBinding() m_LastMin = m_Min; m_LastMax = m_Max; + m_flParticleCullRadius = -1.f; // dummy value, is overwritten below SetParticleCullRadius( 0.0f ); m_nActiveParticles = 0; diff --git a/game/client/spritemodel.cpp b/game/client/spritemodel.cpp index 09284865..2a1f9be5 100644 --- a/game/client/spritemodel.cpp +++ b/game/client/spritemodel.cpp @@ -269,7 +269,7 @@ bool CEngineSprite::Init( const char *pName ) Q_strncpy( pMaterialPath, pMaterialName, sizeof(pMaterialPath) ); Q_SetExtension( pMaterialPath, ".vmt", sizeof(pMaterialPath) ); - KeyValues *kv = new KeyValues( "vmt" ); + KeyValuesAD kv( "vmt" ); if ( !kv->LoadFromFile( g_pFullFileSystem, pMaterialPath, "GAME" ) ) { Warning( "Unable to load sprite material %s!\n", pMaterialPath ); @@ -291,8 +291,6 @@ bool CEngineSprite::Init( const char *pName ) m_material[ i ]->IncrementReferenceCount(); } - kv->deleteThis(); - m_width = m_material[0]->GetMappingWidth(); m_height = m_material[0]->GetMappingHeight(); m_numFrames = m_material[0]->GetNumAnimationFrames(); diff --git a/game/client/tf/c_baseobject.cpp b/game/client/tf/c_baseobject.cpp index d6123efb..41268e9f 100644 --- a/game/client/tf/c_baseobject.cpp +++ b/game/client/tf/c_baseobject.cpp @@ -420,15 +420,18 @@ void C_BaseObject::Simulate( void ) } else if ( !IsPlacing() && !IsCarried() && m_iLastPlacementPosValid == 0 ) { - // HACK HACK: This sentry has been placed, but was placed on the server before the client updated + float flPlaybackRate = GetPlaybackRate(); + + // HACK HACK: This object has been placed, but was placed on the server before the client updated // from the carry position to see that was a valid placement. // It missed its chance to set the correct activity, so we're doing it now. - SetActivity( ACT_OBJ_RUNNING ); + SetActivity( IsBuilding() ? ACT_OBJ_ASSEMBLING : ACT_OBJ_RUNNING ); + SetPlaybackRate( flPlaybackRate ); // Check if the activity was valid because it might have still been using the older placement model if ( GetActivity() != ACT_INVALID ) { - // Remember to retest our placement, but don't keep forcing the running activity + // Remember to retest our placement, but don't keep forcing the new activity m_iLastPlacementPosValid = -1; } } diff --git a/game/client/tf/c_obj_sentrygun.cpp b/game/client/tf/c_obj_sentrygun.cpp index 3cc421c2..7285164c 100644 --- a/game/client/tf/c_obj_sentrygun.cpp +++ b/game/client/tf/c_obj_sentrygun.cpp @@ -60,7 +60,7 @@ C_ObjectSentrygun::C_ObjectSentrygun() m_nShieldLevel = SHIELD_NONE; m_nOldShieldLevel = SHIELD_NONE; m_hLaserBeamEffect = NULL; - m_pTempShield = NULL; + m_hShieldModel = NULL; m_bNearMiss = false; m_flNextNearMissCheck = 0.f; @@ -312,7 +312,7 @@ void C_ObjectSentrygun::SetDormant( bool bDormant ) if ( IsDormant() && !bDormant ) { // Make sure our shield is where we are. We may have moved since last seen. - if ( m_pTempShield ) + if ( m_hShieldModel ) { m_bRecreateShield = true; m_bRecreateLaserBeam = true; @@ -329,13 +329,12 @@ void C_ObjectSentrygun::CreateShield( void ) { DestroyShield(); - model_t *pModel = (model_t *) engine->LoadModel( "models/buildables/sentry_shield.mdl" ); - m_pTempShield = tempents->SpawnTempModel( pModel, GetAbsOrigin(), GetAbsAngles(), Vector(0, 0, 0), 1, FTENT_NEVERDIE ); - if ( m_pTempShield ) + m_hShieldModel = C_SentrygunShield::Create( "models/buildables/sentry_shield.mdl" ); + if ( m_hShieldModel ) { - m_pTempShield->ChangeTeam( GetTeamNumber() ); - m_pTempShield->m_nSkin = ( GetTeamNumber() == TF_TEAM_RED ) ? 0 : 1; - //m_pTempShield->m_nRenderFX = kRenderFxDistort; + m_hShieldModel->FollowEntity( this, false ); + m_hShieldModel->ChangeTeam( GetTeamNumber() ); + m_hShieldModel->m_nSkin = ( GetTeamNumber() == TF_TEAM_RED ) ? 0 : 1; } m_hShieldEffect = ParticleProp()->Create( "turret_shield", PATTACH_ABSORIGIN_FOLLOW, 0, Vector( 0,0,30) ); @@ -356,12 +355,10 @@ void C_ObjectSentrygun::CreateShield( void ) //----------------------------------------------------------------------------- void C_ObjectSentrygun::DestroyShield( void ) { - if ( m_pTempShield ) + if ( m_hShieldModel ) { - m_pTempShield->flags = FTENT_FADEOUT; - m_pTempShield->die = gpGlobals->curtime; - m_pTempShield->fadeSpeed = 1.0f; - m_pTempShield = NULL; + m_hShieldModel->StartFadeOut( 1.0f ); + m_hShieldModel = NULL; } if ( m_hShieldEffect ) @@ -758,4 +755,49 @@ const char* C_ObjectSentrygun::GetStatusName() const return "#TF_Object_Sentry"; } +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_SentrygunShield *C_SentrygunShield::Create( const char *pszModelName ) +{ + C_SentrygunShield *pShield = new C_SentrygunShield(); + if ( !pShield ) + return NULL; + if ( !pShield->InitializeAsClientEntity( pszModelName, RENDER_GROUP_TRANSLUCENT_ENTITY ) ) + { + pShield->Release(); + return NULL; + } + + pShield->AddEffects( EF_NORECEIVESHADOW | EF_NOSHADOW ); + return pShield; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_SentrygunShield::ClientThink() +{ + if ( m_flFadeOutEndTime <= gpGlobals->curtime ) + { + Release(); + return; + } + + float flAlpha = RemapVal( gpGlobals->curtime, m_flFadeOutStartTime, m_flFadeOutEndTime, 255.0f, 0.0f ); + SetRenderColorA( (byte)flAlpha ); + SetNextClientThink( CLIENT_THINK_ALWAYS ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_SentrygunShield::StartFadeOut( float flDuration ) +{ + SetRenderMode( kRenderTransTexture ); + + m_flFadeOutStartTime = gpGlobals->curtime; + m_flFadeOutEndTime = gpGlobals->curtime + flDuration; + SetNextClientThink( gpGlobals->curtime ); +} diff --git a/game/client/tf/c_obj_sentrygun.h b/game/client/tf/c_obj_sentrygun.h index edbc2385..f39f3334 100644 --- a/game/client/tf/c_obj_sentrygun.h +++ b/game/client/tf/c_obj_sentrygun.h @@ -27,6 +27,26 @@ enum SHIELD_MAX, // 10% damage taken, no inactive period }; +//----------------------------------------------------------------------------- +// Purpose: Wrangler shield +//----------------------------------------------------------------------------- +class C_SentrygunShield : public C_BaseAnimating +{ + DECLARE_CLASS( C_SentrygunShield, C_BaseAnimating ); + +public: + static C_SentrygunShield *Create( const char *pszModelName ); + + virtual void ClientThink(); + + void StartFadeOut( float flDuration ); + +private: + float m_flFadeOutStartTime; + float m_flFadeOutEndTime; +}; + + //----------------------------------------------------------------------------- // Purpose: Sentry object //----------------------------------------------------------------------------- @@ -124,7 +144,7 @@ private: bool m_bRecreateLaserBeam; float m_flNextNearMissCheck; - C_LocalTempEntity *m_pTempShield; + CHandle m_hShieldModel; HPARTICLEFFECT m_hSirenEffect; HPARTICLEFFECT m_hShieldEffect; diff --git a/game/client/tf/c_obj_teleporter.cpp b/game/client/tf/c_obj_teleporter.cpp index bd2cfee0..a3e5dbfd 100644 --- a/game/client/tf/c_obj_teleporter.cpp +++ b/game/client/tf/c_obj_teleporter.cpp @@ -186,6 +186,13 @@ void C_ObjectTeleporter::StopActiveEffects() ParticleProp()->StopEmission( m_hChargedRightArmEffect ); m_hChargedRightArmEffect = NULL; } + + if ( m_pSpinSound && IsCarried() ) + { + CSoundEnvelopeController& controller = CSoundEnvelopeController::GetController(); + controller.SoundDestroy( m_pSpinSound ); + m_pSpinSound = NULL; + } } //----------------------------------------------------------------------------- diff --git a/game/client/tf/c_tf_player.cpp b/game/client/tf/c_tf_player.cpp index 0d2be67b..4d625143 100644 --- a/game/client/tf/c_tf_player.cpp +++ b/game/client/tf/c_tf_player.cpp @@ -76,6 +76,9 @@ #include "netadr.h" #include "input.h" +// for rescue ranger +#include "materialsystem/imaterialproxy.h" + #include "gcsdk/gcclientsdk.h" #include "econ_gcmessages.h" #include "rtime.h" @@ -2289,12 +2292,31 @@ public: EXPOSE_INTERFACE( CProxyBenefactorLevel, IMaterialProxy, "BenefactorLevel" IMATERIAL_PROXY_INTERFACE_VERSION ); //----------------------------------------------------------------------------- -// Purpose: Used for scaling the oscilloscope on the Building Rescue Gun -// Flattens the Wave when the player has no energy +// Purpose: Used for scaling the oscilloscope on the Rescue Ranger +// Flattens the Wave when the player has insufficent energy to rescue buildings +// Wave has horizontal scrolling whose speed and direction can be controlled from material proxy //----------------------------------------------------------------------------- + class CProxyBuildingRescueLevel : public CResultProxy { public: +// Add this member (default to something safe) + float m_flScrollSpeed = -0.1f; + + virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ) + { + // Call base init first if needed + if ( !CResultProxy::Init( pMaterial, pKeyValues ) ) + return false; + + // pKeyValues points to the { "screenScrollRate" "#" ... } subkey + if ( pKeyValues ) + { + m_flScrollSpeed = pKeyValues->GetFloat( "screenScrollRate", -0.1f ); // fallback if missing + } + + return true; + } void OnBind( void *pC_BaseEntity ) { Assert( m_pResult ); @@ -2338,6 +2360,17 @@ public: MatrixBuildTranslation( temp, center.x, center.y, 0.0f ); MatrixMultiply( temp, mat, mat ); + + float flScrollSpeed = m_flScrollSpeed; + + float scrollOffset = fmodf( gpGlobals->curtime * flScrollSpeed, 1.0f ); + if ( scrollOffset < 0.0f ) + scrollOffset += 1.0f; // [0,1) range for seamless loop + + // Apply horizontal scroll AFTER the existing scale/center operations + MatrixBuildTranslation( temp, scrollOffset, 0.0f, 0.0f ); + MatrixMultiply( temp, mat, mat ); + m_pResult->SetMatrixValue( mat ); if ( ToolsEnabled() ) @@ -2347,7 +2380,7 @@ public: } }; -EXPOSE_INTERFACE( CProxyBuildingRescueLevel, IMaterialProxy, "BuildingRescueLevel" IMATERIAL_PROXY_INTERFACE_VERSION ); +EXPOSE_INTERFACE(CProxyBuildingRescueLevel, IMaterialProxy, "BuildingRescueLevel" IMATERIAL_PROXY_INTERFACE_VERSION); //----------------------------------------------------------------------------- @@ -3727,6 +3760,7 @@ IMPLEMENT_CLIENTCLASS_DT( C_TFPlayer, DT_TFPlayer, CTFPlayer ) RecvPropFloat( RECVINFO( m_flMvMLastDamageTime ) ), RecvPropFloat( RECVINFO_NAME( m_flMvMLastDamageTime, "m_flLastDamageTime" ) ), // Renamed RecvPropInt( RECVINFO( m_iSpawnCounter ) ), + RecvPropBool( RECVINFO( m_bFlipViewModels ) ), RecvPropBool( RECVINFO( m_bArenaSpectator ) ), RecvPropDataTable( RECVINFO_DT( m_AttributeManager ), 0, &REFERENCE_RECV_TABLE(DT_AttributeManager) ), @@ -3756,6 +3790,7 @@ IMPLEMENT_CLIENTCLASS_DT( C_TFPlayer, DT_TFPlayer, CTFPlayer ) RecvPropInt( RECVINFO( m_iPlayerSkinOverride ) ), RecvPropBool( RECVINFO( m_bViewingCYOAPDA ) ), RecvPropBool( RECVINFO( m_bRegenerating ) ), + RecvPropEHandle( RECVINFO( m_hOffHandWeapon ) ), END_RECV_TABLE() @@ -5852,6 +5887,17 @@ bool C_TFPlayer::IsPlayerOnSteamFriendsList( C_BasePlayer *pPlayer ) return false; } +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_TFPlayer::PreThink( void ) +{ + // Update timers. + UpdateTimers(); + + // Pass through to the base class think. + BaseClass::PreThink(); +} //----------------------------------------------------------------------------- // Purpose: @@ -6050,13 +6096,18 @@ void C_TFPlayer::ClientThink() // // Passtime ask for ball button // - if ( m_nButtons & IN_ATTACK3 ) + if ( m_afButtonPressed & IN_ATTACK3 ) { engine->ClientCmd("voicemenu 1 8"); } } } +void C_TFPlayer::UpdateTimers( void ) +{ + m_Shared.SharedThink(); +} + void C_TFPlayer::Touch( CBaseEntity *pOther ) { BaseClass::Touch( pOther ); @@ -7001,6 +7052,15 @@ void C_TFPlayer::UpdateIDTarget() if ( tr.m_pEnt && tr.m_pEnt->IsPlayer() ) { + trace_t trShot; + // use the shot mask to replicate the medigun's trace + UTIL_TraceLine( vecStart, vecEnd, MASK_SHOT, this, COLLISION_GROUP_NONE, &trShot ); + + if ( trShot.fraction != 1.0 && trShot.m_pEnt && trShot.m_pEnt->IsPlayer() && ( !tr.startsolid || tr.m_pEnt != trShot.m_pEnt ) ) + { + tr = trShot; + } + // It's okay to start solid against enemies because we sometimes press right against them bIsEnemyPlayer = GetTeamNumber() != tr.m_pEnt->GetTeamNumber(); } @@ -9125,7 +9185,7 @@ CNewParticleEffect *C_TFPlayer::SpawnHalloweenSpellFootsteps( ParticleAttachment kHalloweenSpell_RGBConstant_HHH = 2, kHalloweenSpell_RGBConstant_TeamColor = 1, kHalloweenSpell_RGB_Red = 12073019, - kHalloweenSpell_RGB_Blue = 5801378, + kHalloweenSpell_RGB_Blue = 2192591, }; if ( iHalloweenFootstepType == kHalloweenSpell_RGBConstant_HHH ) @@ -11610,26 +11670,24 @@ void C_TFPlayer::ClientAdjustVOPitch( int& pitch ) { pitch *= 1.3f; } + // Halloween voice futzery? - else + float flVoicePitchScale = 1.f; + CALL_ATTRIB_HOOK_FLOAT( flVoicePitchScale, voice_pitch_scale ); + + int iHalloweenVoiceSpell = 0; + if ( TF_IsHolidayActive( kHoliday_HalloweenOrFullMoon ) ) { - float flVoicePitchScale = 1.f; - CALL_ATTRIB_HOOK_FLOAT( flVoicePitchScale, voice_pitch_scale ); + CALL_ATTRIB_HOOK_INT( iHalloweenVoiceSpell, halloween_voice_modulation ); + } - int iHalloweenVoiceSpell = 0; - if ( TF_IsHolidayActive( kHoliday_HalloweenOrFullMoon ) ) - { - CALL_ATTRIB_HOOK_INT( iHalloweenVoiceSpell, halloween_voice_modulation ); - } - - if ( iHalloweenVoiceSpell > 0 ) - { - pitch *= 0.8f; - } - else if ( flVoicePitchScale != 1.f ) - { - pitch *= flVoicePitchScale; - } + if ( iHalloweenVoiceSpell > 0 ) + { + pitch *= 0.8f; + } + else if ( flVoicePitchScale != 1.f ) + { + pitch *= flVoicePitchScale; } } diff --git a/game/client/tf/c_tf_player.h b/game/client/tf/c_tf_player.h index 0fcee373..23ecbc6b 100644 --- a/game/client/tf/c_tf_player.h +++ b/game/client/tf/c_tf_player.h @@ -111,8 +111,11 @@ public: void StopViewModelParticles( C_BaseEntity *pParticleEnt ); + virtual void PreThink( void ); virtual void ClientThink(); + void UpdateTimers(); + // Deal with recording virtual void GetToolRecordingState( KeyValues *msg ); @@ -124,6 +127,7 @@ public: virtual void Simulate( void ); virtual void FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options ) OVERRIDE; virtual void UpdateStepSound( surfacedata_t *psurface, const Vector &vecOrigin, const Vector &vecVelocity ) OVERRIDE; + virtual void PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool force ); CNewParticleEffect *SpawnHalloweenSpellFootsteps( ParticleAttachment_t eParticleAttachment, int iHalloweenFootstepType ); @@ -662,6 +666,8 @@ public: int m_iSpawnCounter; bool m_bArenaSpectator; + bool m_bFlipViewModels; + bool m_bIsMiniBoss; bool m_bIsABot; int m_nBotSkill; diff --git a/game/client/tf/clientmode_tf.cpp b/game/client/tf/clientmode_tf.cpp index ff97ca31..25ee8d37 100644 --- a/game/client/tf/clientmode_tf.cpp +++ b/game/client/tf/clientmode_tf.cpp @@ -531,6 +531,7 @@ void ClientModeTFNormal::Shutdown() { RemoveFilesInPath( "materials/temp" ); RemoveFilesInPath( "download/user_custom" ); + RemoveFilesInPath( "sound/temp" ); } DestroyStatsSummaryPanel(); diff --git a/game/client/tf/tf_autorp.cpp b/game/client/tf/tf_autorp.cpp index 32e2b93c..616e8691 100644 --- a/game/client/tf/tf_autorp.cpp +++ b/game/client/tf/tf_autorp.cpp @@ -35,7 +35,7 @@ void CTFAutoRP::ParseDataFile( void ) Assert( !m_pDataFileKV ); // Load & parse the word files - KeyValues *pFileKV = new KeyValues( "AutoRPFile" ); + KeyValuesAD pFileKV( "AutoRPFile" ); if ( pFileKV->LoadFromFile( filesystem, "scripts/autorp.txt", "MOD" ) == false ) return; @@ -547,7 +547,7 @@ void CTFAutoRP::ModifySpeech( const char *pszInText, char *pszOutText, int iOutL { szStoredWord[0] = toupper( szStoredWord[0] ); } - else if ( pszCurWord[0] >= 'a' && pszCurWord[0] <= 'a' ) + else if ( pszCurWord[0] >= 'a' && pszCurWord[0] <= 'z' ) { szStoredWord[0] = tolower( szStoredWord[0] ); } diff --git a/game/client/tf/tf_hud_account.cpp b/game/client/tf/tf_hud_account.cpp index 34e21c06..20070cff 100644 --- a/game/client/tf/tf_hud_account.cpp +++ b/game/client/tf/tf_hud_account.cpp @@ -198,7 +198,7 @@ public: virtual const char *GetResFileName( void ) { return "resource/UI/HudAccountPanel.res"; } protected: - virtual Color GetColor( const account_delta_t::eAccountDeltaType_t& type ); + virtual Color GetColor( const account_delta_t::eAccountDeltaType_t &type, const int iDeltaValue = 0 ); CUtlVector m_AccountDeltaItems; @@ -1030,7 +1030,7 @@ account_delta_t *CAccountPanel::OnAccountValueChanged( int iOldValue, int iNewVa pNewDeltaItem->m_bLargeFont = false; pNewDeltaItem->m_eDataType = type; pNewDeltaItem->m_wzText[0] = NULL; - pNewDeltaItem->m_color = GetColor( type ); + pNewDeltaItem->m_color = GetColor( type, iDelta ); pNewDeltaItem->m_bShadows = false; return &m_AccountDeltaItems[index]; } @@ -1038,7 +1038,7 @@ account_delta_t *CAccountPanel::OnAccountValueChanged( int iOldValue, int iNewVa return NULL; } -Color CAccountPanel::GetColor( const account_delta_t::eAccountDeltaType_t& type ) +Color CAccountPanel::GetColor( const account_delta_t::eAccountDeltaType_t &type, const int iDeltaValue ) { if ( type == account_delta_t::ACCOUNT_DELTA_BONUS_POINTS ) { @@ -1046,7 +1046,7 @@ Color CAccountPanel::GetColor( const account_delta_t::eAccountDeltaType_t& type } else if ( type == account_delta_t::ACCOUNT_DELTA_HEALING ) { - return m_DeltaPositiveColor; + return ( iDeltaValue < 0 ) ? m_DeltaNegativeColor : m_DeltaPositiveColor; } else if ( type == account_delta_t::ACCOUNT_DELTA_DAMAGE ) { diff --git a/game/client/tf/tf_hud_mainmenuoverride.cpp b/game/client/tf/tf_hud_mainmenuoverride.cpp index f7828cb2..516e180d 100644 --- a/game/client/tf/tf_hud_mainmenuoverride.cpp +++ b/game/client/tf/tf_hud_mainmenuoverride.cpp @@ -777,7 +777,7 @@ void CHudMainMenuOverride::LoadCharacterImageFile( void ) //----------------------------------------------------------------------------- void CHudMainMenuOverride::LoadMenuEntries( void ) { - KeyValues *datafile = new KeyValues("GameMenu"); + KeyValuesAD datafile("GameMenu"); datafile->UsesEscapeSequences( true ); // VGUI uses escape sequences bool bLoaded = datafile->LoadFromFile( g_pFullFileSystem, "Resource/GameMenu.res", "custom_mod" ); if ( !bLoaded ) @@ -2274,7 +2274,7 @@ public: //V_strcpy_safe( uilanguage, "german" ); - KeyValues *pEntriesKV = new KeyValues( "motd_entries"); + KeyValuesAD pEntriesKV( "motd_entries"); // Try and load the cache file. If we fail, we'll just create a new one. if ( !pMMPanel->ReloadedAllMOTDs() ) diff --git a/game/client/tf/tf_hud_mann_vs_machine_status.cpp b/game/client/tf/tf_hud_mann_vs_machine_status.cpp index d8fa9e01..c43ee87c 100644 --- a/game/client/tf/tf_hud_mann_vs_machine_status.cpp +++ b/game/client/tf/tf_hud_mann_vs_machine_status.cpp @@ -851,7 +851,14 @@ void CWaveStatusPanel::UpdateEnemyCounts( void ) if ( pPanel->m_pEnemyCountImageBG ) { - pPanel->m_pEnemyCountImageBG->SetBgColor( m_clrNormal ); + if ( support[i].iFlags & MVM_CLASS_FLAG_MINIBOSS ) + { + pPanel->m_pEnemyCountImageBG->SetBgColor( m_clrMiniBoss ); + } + else + { + pPanel->m_pEnemyCountImageBG->SetBgColor( m_clrNormal ); + } } if ( pPanel->m_pEnemyCountCritBG ) diff --git a/game/client/tf/tf_hud_match_status.cpp b/game/client/tf/tf_hud_match_status.cpp index b2a9f804..a1dc004b 100644 --- a/game/client/tf/tf_hud_match_status.cpp +++ b/game/client/tf/tf_hud_match_status.cpp @@ -358,7 +358,7 @@ void CTFHudMatchStatus::ApplySchemeSettings(IScheme *pScheme) pConditions = new KeyValues( "conditions" ); AddSubKeyNamed( pConditions, "if_match" ); - const IMatchGroupDescription* pMatchDesc = GetMatchGroupDescription( GTFGCClientSystem()->GetLiveMatchGroup() ); + const IMatchGroupDescription* pMatchDesc = GetMatchGroupDescription( TFGameRules() ? TFGameRules()->GetCurrentMatchGroup() : GTFGCClientSystem()->GetLiveMatchGroup() ); if ( pMatchDesc ) { if ( pMatchDesc->GetMatchSize() > 12 ) @@ -574,16 +574,39 @@ void CTFHudMatchStatus::FireGameEvent( IGameEvent * event ) } const IMatchGroupDescription* pMatchDesc = GetMatchGroupDescription( TFGameRules()->GetCurrentMatchGroup() ); - bool bForceDoors = false; - if ( bForceDoors || ( pMatchDesc && pMatchDesc->BUsesPostRoundDoors() ) ) + + if ( pMatchDesc ) { - if ( TFGameRules() && TFGameRules()->MapHasMatchSummaryStage() && ( bForceDoors || pMatchDesc->BUseMatchSummaryStage() ) ) + // FIX: Refresh versus doors so late-joiners do not see the wrong skin + int nSkin = 0; + int nSubModel = 0; + if ( pMatchDesc->BGetRoundDoorParameters( nSkin, nSubModel ) ) { - g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "HudMatchStatus_ShowMatchWinDoors", false ); + if ( m_pMatchStartModelPanel ) + { + // Is VS doors model not initialized yet? + if ( m_pMatchStartModelPanel->m_hModel == NULL ) + { + m_pMatchStartModelPanel->UpdateModel(); + } + + m_pMatchStartModelPanel->SetBodyGroup( "logos", nSubModel ); + m_pMatchStartModelPanel->UpdateModel(); + m_pMatchStartModelPanel->SetSkin( nSkin ); + } } - else + + bool bForceDoors = false; + if ( bForceDoors || ( pMatchDesc && pMatchDesc->BUsesPostRoundDoors() ) ) { - g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "HudMatchStatus_ShowMatchWinDoors_NoOpen", false ); + if ( TFGameRules() && TFGameRules()->MapHasMatchSummaryStage() && ( bForceDoors || pMatchDesc->BUseMatchSummaryStage() ) ) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "HudMatchStatus_ShowMatchWinDoors", false ); + } + else + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "HudMatchStatus_ShowMatchWinDoors_NoOpen", false ); + } } } } diff --git a/game/client/tf/tf_hud_passtime.cpp b/game/client/tf/tf_hud_passtime.cpp index 17a4b6d2..14c35389 100644 --- a/game/client/tf/tf_hud_passtime.cpp +++ b/game/client/tf/tf_hud_passtime.cpp @@ -813,6 +813,8 @@ CTFHudPasstimeBallStatus::CTFHudPasstimeBallStatus( Panel *pParent ) //----------------------------------------------------------------------------- CTFHudPasstimeBallStatus::~CTFHudPasstimeBallStatus() { + delete m_pEventText; + m_pEventText = nullptr; } //----------------------------------------------------------------------------- diff --git a/game/client/tf/tf_hud_scope.cpp b/game/client/tf/tf_hud_scope.cpp index 686c68ff..4ba0957c 100644 --- a/game/client/tf/tf_hud_scope.cpp +++ b/game/client/tf/tf_hud_scope.cpp @@ -242,6 +242,7 @@ protected: virtual void ApplySchemeSettings(vgui::IScheme *scheme); virtual void Paint( void ); virtual bool ShouldDraw( void ); + virtual bool CanAnimate() const OVERRIDE { return false; } private: int m_iScopeTexture[4]; diff --git a/game/client/tf/vgui/character_info_panel.cpp b/game/client/tf/vgui/character_info_panel.cpp index 2bd1afaa..c992b520 100644 --- a/game/client/tf/vgui/character_info_panel.cpp +++ b/game/client/tf/vgui/character_info_panel.cpp @@ -403,7 +403,7 @@ void CCharacterInfoPanel::OnKeyCodePressed(vgui::KeyCode code) { ButtonCode_t nButtonCode = GetBaseButtonCode( code ); - if ( nButtonCode == KEY_XBUTTON_B ) + if ( nButtonCode == KEY_XBUTTON_B || nButtonCode == STEAMCONTROLLER_B ) { if ( !m_bPreventClosure ) { diff --git a/game/client/tf/vgui/charinfo_armory_subpanel.cpp b/game/client/tf/vgui/charinfo_armory_subpanel.cpp index 1532fefd..4df78168 100644 --- a/game/client/tf/vgui/charinfo_armory_subpanel.cpp +++ b/game/client/tf/vgui/charinfo_armory_subpanel.cpp @@ -23,6 +23,7 @@ #include ConVar tf_explanations_charinfo_armory_panel( "tf_explanations_charinfo_armory_panel", "0", FCVAR_ARCHIVE, "Whether the user has seen explanations for this panel." ); +ConVar tf_armory_page_skip( "tf_armory_page_skip", "10", FCVAR_ARCHIVE, "Number of pages to skip in the Mann Co. Catalog", true, 1, true, 100 ); const char *g_szArmoryFilterStrings[ARMFILT_TOTAL] = { @@ -60,8 +61,6 @@ CArmoryPanel::CArmoryPanel(Panel *parent, const char *panelName) : vgui::Editabl m_CurrentFilter = ARMFILT_ALL_ITEMS; m_OldFilter = ARMFILT_ALL_ITEMS; m_iFilterPage = 0; - m_pNextPageButton = NULL; - m_pPrevPageButton = NULL; m_pViewSetButton = NULL; m_pStoreButton = NULL; m_bAllowGotoStore = false; @@ -109,8 +108,6 @@ void CArmoryPanel::ApplySchemeSettings( vgui::IScheme *pScheme ) m_pMouseOverItemPanel->SetBorder( pScheme->GetBorder("LoadoutItemPopupBorder") ); m_pDataTextRichText = dynamic_cast( m_pDataPanel->FindChildByName( "Data_TextRichText" ) ); - m_pNextPageButton = dynamic_cast( FindChildByName("NextPageButton") ); - m_pPrevPageButton = dynamic_cast( FindChildByName("PrevPageButton") ); m_pViewSetButton = dynamic_cast( FindChildByName("ViewSetButton") ); m_pStoreButton = dynamic_cast( FindChildByName("StoreButton") ); @@ -311,26 +308,63 @@ void CArmoryPanel::OnClosing() //----------------------------------------------------------------------------- void CArmoryPanel::OnCommand( const char *command ) { - if ( !Q_strnicmp( command, "prevpage", 8 ) ) + if ( !Q_stricmp( command, "prevpage" ) ) { if ( m_iFilterPage > 0 ) { m_iFilterPage--; - UpdateItemList(); - UpdateSelectedItem(); } - return; - } - else if ( !Q_strnicmp( command, "nextpage", 8 ) ) - { - int nMaxPages = MAX( 1, ceil(m_FilteredItemList.Count() / (float)(m_iThumbnailRows * m_iThumbnailColumns)) ); - if ( m_iFilterPage < (nMaxPages-1) ) + else { - m_iFilterPage++; - UpdateItemList(); - UpdateSelectedItem(); + m_iFilterPage = ceil( m_FilteredItemList.Count() / (float)( m_iThumbnailRows * m_iThumbnailColumns ) ) - 1; } - return; + UpdateItemList(); + UpdateSelectedItem(); + } + else if ( !Q_stricmp( command, "prevpageskip" ) ) + { + for ( int i = 0; i < tf_armory_page_skip.GetInt(); i++ ) + { + if ( m_iFilterPage > 0 ) + { + m_iFilterPage--; + } + else + { + m_iFilterPage = ceil( m_FilteredItemList.Count() / (float)( m_iThumbnailRows * m_iThumbnailColumns ) ) - 1; + } + } + UpdateItemList(); + UpdateSelectedItem(); + } + else if ( !Q_stricmp( command, "skiptostart" ) ) + { + m_iFilterPage = 0; + UpdateItemList(); + UpdateSelectedItem(); + } + else if ( !Q_stricmp( command, "nextpage" ) ) + { + m_iFilterPage++; + if ( m_iFilterPage > ceil( m_FilteredItemList.Count() / (float)( m_iThumbnailRows * m_iThumbnailColumns ) ) - 1 ) + { + m_iFilterPage = 0; + } + UpdateItemList(); + UpdateSelectedItem(); + } + else if ( !Q_stricmp( command, "nextpageskip" ) ) + { + uint32 unNumPages = ceil( m_FilteredItemList.Count() / (float)( m_iThumbnailRows * m_iThumbnailColumns ) ); + m_iFilterPage = ( ( m_iFilterPage + tf_armory_page_skip.GetInt() ) % unNumPages ); + UpdateItemList(); + UpdateSelectedItem(); + } + else if ( !Q_stricmp( command, "skiptoend" ) ) + { + m_iFilterPage = ceil( m_FilteredItemList.Count() / (float)( m_iThumbnailRows * m_iThumbnailColumns ) ) - 1; + UpdateItemList(); + UpdateSelectedItem(); } else if ( !Q_strnicmp( command, "back", 4 ) ) { @@ -366,7 +400,7 @@ void CArmoryPanel::OnCommand( const char *command ) ELanguage iLang = PchLanguageToELanguage( uilanguage ); char szURL[512]; - Q_snprintf( szURL, sizeof(szURL), "http://wiki.teamfortress.com/scripts/itemredirect.php?id=%d&lang=%s", m_SelectedItem.GetItemDefIndex(), GetLanguageICUName( iLang ) ); + Q_snprintf( szURL, sizeof( szURL ), "https://wiki.teamfortress.com/scripts/itemredirect.php?id=%d&lang=%s", m_SelectedItem.GetItemDefIndex(), GetLanguageICUName( iLang ) ); steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( szURL ); C_CTF_GameStats.Event_Catalog( IE_ARMORY_BROWSE_WIKI, NULL, &m_SelectedItem ); @@ -682,10 +716,6 @@ void CArmoryPanel::UpdateItemList( void ) int nMaxPages = MAX( 1, ceil(m_FilteredItemList.Count() / (float)(m_iThumbnailRows * m_iThumbnailColumns)) ); Q_snprintf(szTmp, 16, "%d/%d", m_iFilterPage+1, nMaxPages ); SetDialogVariable( "thumbnailpage", szTmp ); - - bool bNextEnabled = m_iFilterPage < (nMaxPages-1); - m_pNextPageButton->SetEnabled( bNextEnabled ); - m_pPrevPageButton->SetEnabled( m_iFilterPage > 0 ); } //----------------------------------------------------------------------------- diff --git a/game/client/tf/vgui/charinfo_armory_subpanel.h b/game/client/tf/vgui/charinfo_armory_subpanel.h index 04fc0793..ddcbabf9 100644 --- a/game/client/tf/vgui/charinfo_armory_subpanel.h +++ b/game/client/tf/vgui/charinfo_armory_subpanel.h @@ -112,8 +112,6 @@ private: armory_filters_t m_CurrentFilter; armory_filters_t m_OldFilter; int m_iFilterPage; - CExButton *m_pNextPageButton; - CExButton *m_pPrevPageButton; CUtlVector m_FilteredItemList; CUtlVector m_CustomFilteredList; diff --git a/game/client/tf/vgui/charinfo_loadout_subpanel.cpp b/game/client/tf/vgui/charinfo_loadout_subpanel.cpp index 5c6e342b..aa146a52 100644 --- a/game/client/tf/vgui/charinfo_loadout_subpanel.cpp +++ b/game/client/tf/vgui/charinfo_loadout_subpanel.cpp @@ -1232,7 +1232,7 @@ void CCharInfoLoadoutSubPanel::OnKeyCodePressed(vgui::KeyCode code) { // let escape and B (aka "go back") through so we // can actually get out of the loadout screen - if ( nButtonCode == KEY_XBUTTON_B ) + if ( nButtonCode == KEY_XBUTTON_B || nButtonCode == STEAMCONTROLLER_B ) { BaseClass::OnKeyCodePressed( code ); } diff --git a/game/client/tf/vgui/tf_controls.cpp b/game/client/tf/vgui/tf_controls.cpp index cebe5014..14697794 100644 --- a/game/client/tf/vgui/tf_controls.cpp +++ b/game/client/tf/vgui/tf_controls.cpp @@ -2215,6 +2215,7 @@ void CTFLogoPanel::PaintTFLogo( float flAngle, const Color& color ) const void CTFLogoPanel::Paint() { m_flOffsetAngle += gpGlobals->frametime * m_flVelocity; + m_flOffsetAngle = fmodf( m_flOffsetAngle, 360.f ); PaintTFLogo( m_flOffsetAngle, GetFgColor() ); BaseClass::Paint(); } diff --git a/game/client/tf/vgui/tf_mapinfomenu.cpp b/game/client/tf/vgui/tf_mapinfomenu.cpp index 18ae20f9..0d5af08d 100644 --- a/game/client/tf/vgui/tf_mapinfomenu.cpp +++ b/game/client/tf/vgui/tf_mapinfomenu.cpp @@ -385,14 +385,6 @@ void CTFMapInfoMenu::LoadMapPage() { m_pMapInfo->SetText( wszMapDescription ); } - else if ( StringHasPrefix( m_szMapName, "vsh_" ) ) - { - m_pMapInfo->SetText( "#default_vsh_description" ); - } - else if ( StringHasPrefix( m_szMapName, "zi_" ) ) - { - m_pMapInfo->SetText( "#default_zi_description" ); - } else { // try loading map descriptions from .txt files first @@ -497,7 +489,15 @@ void CTFMapInfoMenu::LoadMapPage() if( !g_pVGuiLocalize->Find( mapInfoKey ) ) { - if ( TFGameRules() ) + if ( MapHasPrefix( m_szMapName, "vsh_" ) ) + { + pszDescription = "#default_vsh_description"; + } + else if ( MapHasPrefix( m_szMapName, "zi_" ) ) + { + pszDescription = "#default_zi_description"; + } + else if ( TFGameRules() ) { if ( TFGameRules()->IsMannVsMachineMode() ) { diff --git a/game/client/tf/vgui/tf_matchmaking_dashboard_party_member.cpp b/game/client/tf/vgui/tf_matchmaking_dashboard_party_member.cpp index 85cf6dec..efcd5b0c 100644 --- a/game/client/tf/vgui/tf_matchmaking_dashboard_party_member.cpp +++ b/game/client/tf/vgui/tf_matchmaking_dashboard_party_member.cpp @@ -392,7 +392,7 @@ void CDashboardPartyMember::OnCommand( const char *command ) { case MEMBER_PRESENT: { - // You can always send a message to party memebers + // You can always send a message to party members contextMenuBuilder.AddMenuItem( "#TF_Friends_SendMessage", new KeyValues( "Context_SendMessage" ), "party" ); // If we're the leader, we can kick diff --git a/game/client/tf/vgui/tf_playermodelpanel.cpp b/game/client/tf/vgui/tf_playermodelpanel.cpp index 5fc2219c..53715b62 100644 --- a/game/client/tf/vgui/tf_playermodelpanel.cpp +++ b/game/client/tf/vgui/tf_playermodelpanel.cpp @@ -34,6 +34,8 @@ DECLARE_BUILD_FACTORY( CTFPlayerModelPanel ); +#define SCENE_LERP_TIME 0.1f + char g_szSceneTmpName[256]; static bool IsTauntItem( GameItemDefinition_t *pItemDef, const int iTeam, const int iClass, const char **ppSequence = NULL, const char **ppRequiredItem = NULL, const char **ppScene = NULL ) @@ -466,7 +468,7 @@ CChoreoScene *LoadSceneForModel( const char *filename, IChoreoEventCallback *pCa if ( bSetEndTime ) { - *flSceneEndTime += 0.1f; // give time for lerp to idle pose + *flSceneEndTime += SCENE_LERP_TIME; // give time for lerp to idle pose } } @@ -547,6 +549,7 @@ void CTFPlayerModelPanel::SwitchHeldItemTo( CEconItemView *pItem ) m_StatTrackModel.m_bDisabled = true; m_StatTrackModel.m_MDL.SetMDL( MDLHANDLE_INVALID ); + m_StatTrackModel.m_pStudioHdr = NULL; // ADDED: Clear the studio header CAttribute_String attrModule; if ( GetStattrak( m_pHeldItem, &attrModule ) ) @@ -587,13 +590,28 @@ void CTFPlayerModelPanel::SwitchHeldItemTo( CEconItemView *pItem ) { hStatTrackMDL = MDLHANDLE_INVALID; } - m_StatTrackModel.m_MDL.SetMDL( hStatTrackMDL ); - mdlcache->Release( hStatTrackMDL ); // counterbalance addref from within FindMDL - m_StatTrackModel.m_MDL.m_pProxyData = static_cast(pItem); - m_StatTrackModel.m_bDisabled = false; - m_StatTrackModel.m_MDL.m_nSequence = ACT_IDLE; - SetIdentityMatrix( m_StatTrackModel.m_MDLToWorld ); + if ( hStatTrackMDL != MDLHANDLE_INVALID ) + { + m_StatTrackModel.m_MDL.SetMDL( hStatTrackMDL ); + + studiohdr_t* pStudioHdr = mdlcache->GetStudioHdr( hStatTrackMDL ); + if ( pStudioHdr ) + { + if ( !m_StatTrackModel.m_pStudioHdr ) + { + m_StatTrackModel.m_pStudioHdr = new CStudioHdr(); + } + m_StatTrackModel.m_pStudioHdr->Init( pStudioHdr, mdlcache ); + } + + mdlcache->Release( hStatTrackMDL ); + + m_StatTrackModel.m_MDL.m_pProxyData = static_cast( pItem ); + m_StatTrackModel.m_bDisabled = false; + m_StatTrackModel.m_MDL.m_nSequence = ACT_IDLE; + SetIdentityMatrix( m_StatTrackModel.m_MDLToWorld ); + } } } @@ -952,6 +970,7 @@ static const char *s_pszDefaultAnimForWpnSlot[] = "ACT_MP_STAND_PRIMARY", // TF_WPN_TYPE_PRIMARY2 "ACT_MP_STAND_ITEM3", // TF_WPN_TYPE_ITEM3 "ACT_MP_STAND_ITEM4", // TF_WPN_TYPE_ITEM4 + "ACT_MP_STAND_PASSTIME", // TF_WPN_TYPE_PASSTIME_BALL }; COMPILE_TIME_ASSERT( ARRAYSIZE( s_pszDefaultAnimForWpnSlot ) == TF_WPN_TYPE_COUNT ); @@ -1250,6 +1269,14 @@ void CTFPlayerModelPanel::UpdatePreviewVisuals() SetMDLSkinForTeam( GetMergeMDL( m_MergeMDL ), GetPreviewItem( m_pHeldItem ), m_iTeam ); } + // Set the StatTrack model skin + if ( !m_StatTrackModel.m_bDisabled ) + { + int iSkin = 0; + iSkin = m_iTeam == TF_TEAM_RED ? 0 : 1; + m_StatTrackModel.m_MDL.m_nSkin = iSkin; + } + // Set the skin for all other equipped items (wearables, etc). for ( int i=0; inumbones(); ++i ) { MatrixScaleBy( m_flStatTrackScale, pMergeBoneToWorld[i] ); } @@ -2291,10 +2332,11 @@ void CTFPlayerModelPanel::SetupFlexWeights( void ) // Advance time if ( m_flLastTickTime < FLT_EPSILON ) { - m_flLastTickTime = m_RootMDL.m_MDL.m_flTime - 0.1; + m_flLastTickTime = m_RootMDL.m_MDL.m_flTime - SCENE_LERP_TIME; } m_flSceneTime += (m_RootMDL.m_MDL.m_flTime - m_flLastTickTime); + m_flSceneTime = Max( m_flSceneTime, -SCENE_LERP_TIME ); m_flLastTickTime = m_RootMDL.m_MDL.m_flTime; if ( m_flSceneEndTime > FLT_EPSILON && m_flSceneTime > m_flSceneEndTime ) diff --git a/game/client/tf/workshop/item_import.cpp b/game/client/tf/workshop/item_import.cpp index d1d69262..a4a07d3d 100644 --- a/game/client/tf/workshop/item_import.cpp +++ b/game/client/tf/workshop/item_import.cpp @@ -88,6 +88,7 @@ static const char *kBodygroupArray[] = "headphones", "shoes", "shoes_socks", + "bullets" }; extern IFileSystem *g_pFullFileSystem; @@ -6998,6 +6999,9 @@ CTFFileImportDialog::LOAD_RESULT CTFFileImportDialog::LoadTxt( const char *pszFi } } + char szFileBase[ MAX_PATH ]; + V_FileBase( pszSourceFile, szFileBase, sizeof( szFileBase ) ); + LOAD_RESULT result = SetAnimationSource( nClassIndex, pszSourceFile ); if ( result != LOAD_OKAY ) { @@ -7013,6 +7017,23 @@ CTFFileImportDialog::LOAD_RESULT CTFFileImportDialog::LoadTxt( const char *pszFi V_ComposeFileName( pszBasePath, pszVCDFile, pszLoadPath, sizeof(pszLoadPath) ); pszVCDFile = pszLoadPath; } + + if ( !g_pFullFileSystem->FileExists( pszVCDFile, "MOD" ) ) + { + const char *pszTempVCDFile = pszVCDFile; + + // If the file isn't found using the path in the manifest, let's look where we think it should be on disk. + // We're sometimes seeing absolute paths for the creator's hard drive in the manifest for the vcd_file. + char szFallbackTest[ MAX_PATH ]; + V_sprintf_safe( szFallbackTest, "%sgame\\scenes\\%s\\player\\%s\\low\\%s.vcd", pszBasePath, GetWorkshopFolder(), kClassFolders[ nClassIndex ], szFileBase ); + pszVCDFile = szFallbackTest; + + if ( !g_pFullFileSystem->FileExists( pszVCDFile, "MOD" ) ) + { + // Set it back to the original value and let it fail below. + pszVCDFile = pszTempVCDFile; + } + } } result = SetAnimationVCD( nClassIndex, pszVCDFile ); diff --git a/game/client/vgui_netgraphpanel.cpp b/game/client/vgui_netgraphpanel.cpp index ab369cba..8723254e 100644 --- a/game/client/vgui_netgraphpanel.cpp +++ b/game/client/vgui_netgraphpanel.cpp @@ -768,10 +768,10 @@ void CNetGraphPanel::DrawTextFields( int graphvalue, int x, int y, int w, netban g_pMatSystemSurface->DrawColoredText( font, x, y, GRAPH_RED, GRAPH_GREEN, GRAPH_BLUE, 255, "%s", sz ); - Q_snprintf( sz, sizeof( sz ), "lerp: %5.1f ms", GetClientInterpAmount() * 1000.0f ); + Q_snprintf( sz, sizeof( sz ), "lerp: %5.1f ms", ROUND_TO_TICKS( GetClientInterpAmount() ) * 1000.0f ); int interpcolor[ 3 ] = { (int)GRAPH_RED, (int)GRAPH_GREEN, (int)GRAPH_BLUE }; - float flInterp = GetClientInterpAmount(); + float flInterp = ROUND_TO_TICKS( GetClientInterpAmount() ); if ( flInterp > 0.001f ) { // Server framerate is lower than interp can possibly deal with @@ -782,7 +782,7 @@ void CNetGraphPanel::DrawTextFields( int graphvalue, int x, int y, int w, netban interpcolor[ 2 ] = 31; } // flInterp is below recommended setting!!! - else if ( flInterp < ( 2.0f / cl_updaterate->GetFloat() ) ) + else if ( flInterp < ROUND_TO_TICKS( 2.0f / cl_updaterate->GetFloat() ) ) { interpcolor[ 0 ] = 255; interpcolor[ 1 ] = 125; diff --git a/game/client/voice_menu.cpp b/game/client/voice_menu.cpp index 0a6d3786..c5836349 100644 --- a/game/client/voice_menu.cpp +++ b/game/client/voice_menu.cpp @@ -17,6 +17,10 @@ static int g_ActiveVoiceMenu = 0; +#if defined( TF_CLIENT_DLL ) +extern ConVar tf_voice_command_suspension_mode; +#endif + void OpenVoiceMenu( int index ) { // do not show the menu if the player is dead or is an observer @@ -28,7 +32,7 @@ void OpenVoiceMenu( int index ) return; #if defined ( TF_CLIENT_DLL ) - if ( GTFGCClientSystem() && GTFGCClientSystem()->BHaveChatSuspensionInCurrentMatch() ) + if ( GTFGCClientSystem() && GTFGCClientSystem()->BHaveChatSuspensionInCurrentMatch() && tf_voice_command_suspension_mode.GetInt() == 1 ) { CBaseHudChat *pHUDChat = ( CBaseHudChat * ) GET_HUDELEMENT( CHudChat ); if ( pHUDChat ) diff --git a/game/server/NextBot/NextBot.h b/game/server/NextBot/NextBot.h index 369f6988..51c9403b 100644 --- a/game/server/NextBot/NextBot.h +++ b/game/server/NextBot/NextBot.h @@ -40,6 +40,7 @@ public: virtual Vector EyePosition( void ); virtual INextBot *MyNextBotPointer( void ) { return this; } + virtual bool IsNextBot(void) const { return true; } // Event hooks into NextBot system --------------------------------------- virtual int OnTakeDamage_Alive( const CTakeDamageInfo &info ); diff --git a/game/server/SkyCamera.cpp b/game/server/SkyCamera.cpp index ede4ec97..237ec759 100644 --- a/game/server/SkyCamera.cpp +++ b/game/server/SkyCamera.cpp @@ -146,4 +146,10 @@ void CSkyCamera::Activate( ) } } #endif + + // matches the behavior of fog controller + if ( GameRules()->IsOfficialMap() ) + { + m_skyboxData.fog.radial = true; + } } diff --git a/game/server/ai_behavior_assault.cpp b/game/server/ai_behavior_assault.cpp index e02627cc..d57ec618 100644 --- a/game/server/ai_behavior_assault.cpp +++ b/game/server/ai_behavior_assault.cpp @@ -1257,7 +1257,7 @@ int CAI_AssaultBehavior::TranslateSchedule( int scheduleType ) break; case SCHED_HOLD_RALLY_POINT: - if( HasCondition(COND_NO_PRIMARY_AMMO) | HasCondition(COND_LOW_PRIMARY_AMMO) ) + if( HasCondition(COND_NO_PRIMARY_AMMO) || HasCondition(COND_LOW_PRIMARY_AMMO) ) { return SCHED_RELOAD; } diff --git a/game/server/ai_utils.h b/game/server/ai_utils.h index d608ba5e..8cdde7ba 100644 --- a/game/server/ai_utils.h +++ b/game/server/ai_utils.h @@ -70,7 +70,7 @@ public: bool IsMarkSet() { - return ( m_flMarkTolerance != (float)NO_MARK ); + return ( m_flMarkTolerance != NO_MARK ); } bool TargetMoved( CBaseEntity *pEntity ) diff --git a/game/server/baseentity.cpp b/game/server/baseentity.cpp index 3462fd37..306ce370 100644 --- a/game/server/baseentity.cpp +++ b/game/server/baseentity.cpp @@ -279,6 +279,7 @@ IMPLEMENT_SERVERCLASS_ST_NOBASE( CBaseEntity, DT_BaseEntity ) SendPropInt (SENDINFO(m_clrRender), 32, SPROP_UNSIGNED), SendPropInt (SENDINFO(m_iTeamNum), TEAMNUM_NUM_BITS, 0), SendPropInt (SENDINFO(m_CollisionGroup), 5, SPROP_UNSIGNED), + SendPropFloat (SENDINFO(m_flGravity)), SendPropFloat (SENDINFO(m_flElasticity), 0, SPROP_COORD), SendPropFloat (SENDINFO(m_flShadowCastDistance), 12, SPROP_UNSIGNED ), SendPropEHandle (SENDINFO(m_hOwnerEntity)), diff --git a/game/server/baseentity.h b/game/server/baseentity.h index 73eeae0b..afed3bfa 100644 --- a/game/server/baseentity.h +++ b/game/server/baseentity.h @@ -996,6 +996,9 @@ public: void TraceBleed( float flDamage, const Vector &vecDir, trace_t *ptr, int bitsDamageType ); virtual bool IsTriggered( CBaseEntity *pActivator ) {return true;} virtual bool IsNPC( void ) const { return false; } +#ifdef NEXT_BOT + virtual bool IsNextBot(void) const { return false; } +#endif CAI_BaseNPC *MyNPCPointer( void ); virtual CBaseCombatCharacter *MyCombatCharacterPointer( void ) { return NULL; } virtual INextBot *MyNextBotPointer( void ) { return NULL; } @@ -1872,7 +1875,7 @@ private: EHANDLE m_pBlocker; // was pev->gravity; - float m_flGravity; // rename to m_flGravityScale; + CNetworkVar( float, m_flGravity ); // rename to m_flGravityScale; // was pev->friction CNetworkVarForDerived( float, m_flFriction ); CNetworkVar( float, m_flElasticity ); diff --git a/game/server/hl2/npc_combine.cpp b/game/server/hl2/npc_combine.cpp index fb335e67..d1243f33 100644 --- a/game/server/hl2/npc_combine.cpp +++ b/game/server/hl2/npc_combine.cpp @@ -1885,7 +1885,7 @@ int CNPC_Combine::SelectFailSchedule( int failedSchedule, int failedTask, AI_Tas { // This eases the effects of an unfortunate bug that usually plagues shotgunners. Since their rate of fire is low, // they spend relatively long periods of time without an attack squad slot. If you corner a shotgunner, usually - // the other memebers of the squad will hog all of the attack slots and pick schedules to move to establish line of + // the other members of the squad will hog all of the attack slots and pick schedules to move to establish line of // fire. During this time, the shotgunner is prevented from attacking. If he also cannot find cover (the fallback case) // he will stand around like an idiot, right in front of you. Instead of this, we have him run up to you for a melee attack. return SCHED_COMBINE_MOVE_TO_MELEE; diff --git a/game/server/hl2mp/bot/hl2mp_bot_squad.cpp b/game/server/hl2mp/bot/hl2mp_bot_squad.cpp index 8c3e9e9b..68bf1c5e 100644 --- a/game/server/hl2mp/bot/hl2mp_bot_squad.cpp +++ b/game/server/hl2mp/bot/hl2mp_bot_squad.cpp @@ -190,7 +190,7 @@ float CHL2MPBotSquad::GetSlowestMemberIdealSpeed( bool includeLeader ) const //---------------------------------------------------------------------- -// Return the maximum formation error of the squad's memebers. +// Return the maximum formation error of the squad's members. float CHL2MPBotSquad::GetMaxSquadFormationError( void ) const { float maxError = 0.0f; diff --git a/game/server/info_camera_link.cpp b/game/server/info_camera_link.cpp index 8724008d..11941950 100644 --- a/game/server/info_camera_link.cpp +++ b/game/server/info_camera_link.cpp @@ -145,9 +145,11 @@ CBaseEntity *CreateInfoCameraLink( CBaseEntity *pTarget, CPointCamera *pCamera ) //----------------------------------------------------------------------------- void PointCameraSetupVisibility( CBaseEntity *pPlayer, int area, unsigned char *pvs, int pvssize ) { + int nPlayerIndex = pPlayer->entindex(); + for ( CPointCamera *pCameraEnt = GetPointCameraList(); pCameraEnt != NULL; pCameraEnt = pCameraEnt->m_pNext ) { - pCameraEnt->SetActive( false ); + pCameraEnt->TransmitToPlayer( nPlayerIndex, false ); } intp nNext; @@ -175,7 +177,7 @@ void PointCameraSetupVisibility( CBaseEntity *pPlayer, int area, unsigned char * if ( pCameraEnt ) { engine->AddOriginToPVS( pCameraEnt->GetAbsOrigin() ); - pCameraEnt->SetActive( true ); + pCameraEnt->TransmitToPlayer( nPlayerIndex, true ); } } } diff --git a/game/server/player.cpp b/game/server/player.cpp index 8df710cc..b8a0519d 100644 --- a/game/server/player.cpp +++ b/game/server/player.cpp @@ -95,9 +95,9 @@ ConVar spec_freeze_traveltime( "spec_freeze_traveltime", "0.4", FCVAR_CHEAT | FC ConVar sv_bonus_challenge( "sv_bonus_challenge", "0", FCVAR_REPLICATED, "Set to values other than 0 to select a bonus map challenge type." ); -ConVar sv_chat_bucket_size_tier1( "sv_chat_bucket_size_tier1", "4", FCVAR_NONE, "The maxmimum size of the short term chat msg bucket." ); +ConVar sv_chat_bucket_size_tier1( "sv_chat_bucket_size_tier1", "4", FCVAR_NONE, "The maximum size of the short term chat msg bucket." ); ConVar sv_chat_seconds_per_msg_tier1( "sv_chat_seconds_per_msg_tier1", "3", FCVAR_NONE, "The number of seconds to accrue an additional short term chat msg." ); -ConVar sv_chat_bucket_size_tier2( "sv_chat_bucket_size_tier2", "30", FCVAR_NONE, "The maxmimum size of the long term chat msg bucket." ); +ConVar sv_chat_bucket_size_tier2( "sv_chat_bucket_size_tier2", "30", FCVAR_NONE, "The maximum size of the long term chat msg bucket." ); ConVar sv_chat_seconds_per_msg_tier2( "sv_chat_seconds_per_msg_tier2", "10", FCVAR_NONE, "The number of seconds to accrue an additional long term chat msg." ); static ConVar sv_maxusrcmdprocessticks( "sv_maxusrcmdprocessticks", "24", FCVAR_NOTIFY, "Maximum number of client-issued usrcmd ticks that can be replayed in packet loss conditions, 0 to allow no restrictions" ); @@ -8102,13 +8102,6 @@ void CMovementSpeedMod::InputSpeedMod(inputdata_t &data) } -void SendProxy_CropFlagsToPlayerFlagBitsLength( const SendProp *pProp, const void *pStruct, const void *pVarData, DVariant *pOut, int iElement, int objectID) -{ - int mask = (1<m_Int = ( data & mask ); -} // -------------------------------------------------------------------------------- // // SendTable for CPlayerState. // -------------------------------------------------------------------------------- // @@ -8187,7 +8180,7 @@ void SendProxy_CropFlagsToPlayerFlagBitsLength( const SendProp *pProp, const voi SendPropInt (SENDINFO(m_iBonusProgress), 15 ), SendPropInt (SENDINFO(m_iBonusChallenge), 4 ), SendPropFloat (SENDINFO(m_flMaxspeed), 12, SPROP_ROUNDDOWN, 0.0f, 2048.0f ), // CL - SendPropInt (SENDINFO(m_fFlags), PLAYER_FLAG_BITS, SPROP_UNSIGNED|SPROP_CHANGES_OFTEN, SendProxy_CropFlagsToPlayerFlagBitsLength ), + SendPropInt (SENDINFO(m_fFlags), 0, SPROP_UNSIGNED|SPROP_CHANGES_OFTEN ), SendPropInt (SENDINFO(m_iObserverMode), 3, SPROP_UNSIGNED ), SendPropEHandle (SENDINFO(m_hObserverTarget) ), SendPropInt (SENDINFO(m_iFOV), 8, SPROP_UNSIGNED ), diff --git a/game/server/point_camera.cpp b/game/server/point_camera.cpp index ebbd6fcd..a711cc80 100644 --- a/game/server/point_camera.cpp +++ b/game/server/point_camera.cpp @@ -52,6 +52,9 @@ CPointCamera::CPointCamera() m_bFogEnable = false; m_bFogRadial = false; + // By default, transmit to everyone + m_bitsTransmitPlayers.SetAll(); + g_PointCameraList.Insert( this ); } @@ -74,34 +77,43 @@ void CPointCamera::Spawn( void ) SetActive( m_bIsOn ); } +//----------------------------------------------------------------------------- +// Purpose: Transmit only to players who are in PVS of the camera and its link +// See PointCameraSetupVisibility +//----------------------------------------------------------------------------- +int CPointCamera::ShouldTransmit( const CCheckTransmitInfo *pInfo ) +{ + if ( m_bitsTransmitPlayers.IsBitSet( pInfo->m_pClientEnt->m_EdictIndex ) ) + return FL_EDICT_ALWAYS; + + return FL_EDICT_DONTSEND; +} + //----------------------------------------------------------------------------- // Purpose: Override ShouldTransmit since we want to be sent even though we don't have a model, etc. // All that matters is if we are in the pvs. //----------------------------------------------------------------------------- int CPointCamera::UpdateTransmitState() { - if ( m_bActive ) - { - return SetTransmitState( FL_EDICT_ALWAYS ); - } - else - { - return SetTransmitState( FL_EDICT_DONTSEND ); - } + return SetTransmitState( FL_EDICT_FULLCHECK ); } +//----------------------------------------------------------------------------- +// Purpose: Toggle networking of the camera to the specified player +//----------------------------------------------------------------------------- +void CPointCamera::TransmitToPlayer( int nPlayerIndex, bool bTransmit ) +{ + if ( bTransmit ) + m_bitsTransmitPlayers.Set( nPlayerIndex ); + else + m_bitsTransmitPlayers.Clear( nPlayerIndex ); +} //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CPointCamera::SetActive( bool bActive ) { - // If the mapmaker's told the camera it's off, it enforces inactive state - if ( !m_bIsOn ) - { - bActive = false; - } - if ( m_bActive != bActive ) { m_bActive = bActive; diff --git a/game/server/point_camera.h b/game/server/point_camera.h index f0c0567d..f70ba639 100644 --- a/game/server/point_camera.h +++ b/game/server/point_camera.h @@ -29,7 +29,9 @@ public: // Tell the client that this camera needs to be rendered void SetActive( bool bActive ); - int UpdateTransmitState(void); + int ShouldTransmit( const CCheckTransmitInfo *pInfo ); + int UpdateTransmitState( void ); + void TransmitToPlayer( int nPlayerIndex, bool bTransmit ); void ChangeFOVThink( void ); @@ -56,6 +58,8 @@ private: // Allows the mapmaker to control whether a camera is active or not bool m_bIsOn; + CBitVec< MAX_PLAYERS > m_bitsTransmitPlayers; + public: CPointCamera *m_pNext; }; diff --git a/game/server/slideshow_display.cpp b/game/server/slideshow_display.cpp index 12e19ceb..75bdfb10 100644 --- a/game/server/slideshow_display.cpp +++ b/game/server/slideshow_display.cpp @@ -523,7 +523,7 @@ void CSlideshowDisplay::BuildSlideShowImagesList( void ) char szFullFileName[_MAX_PATH]; Q_snprintf( szFullFileName, sizeof( szFullFileName ), "materials/vgui/%s/%s", m_szSlideshowDirectory.Get(), szMatFileName ); - KeyValues *pMaterialKeys = new KeyValues( "material" ); + KeyValuesAD pMaterialKeys( "material" ); bool bLoaded = pMaterialKeys->LoadFromFile( g_pFullFileSystem, szFullFileName, NULL ); if ( bLoaded ) diff --git a/game/server/team_control_point.cpp b/game/server/team_control_point.cpp index 1a104c8b..02d1bb83 100644 --- a/game/server/team_control_point.cpp +++ b/game/server/team_control_point.cpp @@ -336,11 +336,6 @@ void CTeamControlPoint::InputSetOwner( inputdata_t &input ) Assert( iCapTeam >= 0 && iCapTeam < GetNumberOfTeams() ); - Assert( input.pCaller ); - - if ( !input.pCaller ) - return; - if ( GetOwner() == iCapTeam ) return; @@ -349,7 +344,7 @@ void CTeamControlPoint::InputSetOwner( inputdata_t &input ) // must be done before setting the owner HandleScoring( iCapTeam ); - if ( input.pCaller->IsPlayer() ) + if ( input.pCaller && input.pCaller->IsPlayer() ) { int iCappingPlayer = input.pCaller->entindex(); InternalSetOwner( iCapTeam, true, 1, &iCappingPlayer ); diff --git a/game/server/team_control_point_master.cpp b/game/server/team_control_point_master.cpp index 94b21d2b..22bd774d 100644 --- a/game/server/team_control_point_master.cpp +++ b/game/server/team_control_point_master.cpp @@ -1156,6 +1156,9 @@ int CTeamControlPointMaster::GetNumPointsOwnedByTeam( int iTeam ) //----------------------------------------------------------------------------- int CTeamControlPointMaster::CalcNumRoundsRemaining( int iTeam ) { + if ( m_ControlPointRounds.IsEmpty() ) + return 0; + // To determine how many rounds remain for a given team if it consistently wins mini-rounds, we have to // simulate forward each mini-round and track the control point ownership that would result diff --git a/game/server/tf/bot/behavior/engineer/tf_bot_engineer_build_teleport_entrance.cpp b/game/server/tf/bot/behavior/engineer/tf_bot_engineer_build_teleport_entrance.cpp index c6924aa9..fa16adf9 100644 --- a/game/server/tf/bot/behavior/engineer/tf_bot_engineer_build_teleport_entrance.cpp +++ b/game/server/tf/bot/behavior/engineer/tf_bot_engineer_build_teleport_entrance.cpp @@ -29,7 +29,8 @@ ActionResult< CTFBot > CTFBotEngineerBuildTeleportEntrance::OnStart( CTFBot *me, ActionResult< CTFBot > CTFBotEngineerBuildTeleportEntrance::Update( CTFBot *me, float interval ) { CTeamControlPoint *point = me->GetMyControlPoint(); - if ( !point ) + CCaptureZone *zone = me->GetFlagCaptureZone(); + if ( !point && !zone ) { // wait until a control point becomes available return Continue(); @@ -64,7 +65,14 @@ ActionResult< CTFBot > CTFBotEngineerBuildTeleportEntrance::Update( CTFBot *me, if ( !m_path.IsValid() ) { CTFBotPathCost cost( me, FASTEST_ROUTE ); - m_path.Compute( me, point->GetAbsOrigin(), cost ); + if ( point ) + { + m_path.Compute( me, point->GetAbsOrigin(), cost ); + } + else if ( zone ) + { + m_path.Compute( me, zone->WorldSpaceCenter(), cost ); + } } m_path.Update( me ); diff --git a/game/server/tf/bot/behavior/scenario/capture_the_flag/tf_bot_deliver_flag.cpp b/game/server/tf/bot/behavior/scenario/capture_the_flag/tf_bot_deliver_flag.cpp index 873c36ed..166dbc30 100644 --- a/game/server/tf/bot/behavior/scenario/capture_the_flag/tf_bot_deliver_flag.cpp +++ b/game/server/tf/bot/behavior/scenario/capture_the_flag/tf_bot_deliver_flag.cpp @@ -243,7 +243,7 @@ ActionResult< CTFBot > CTFBotDeliverFlag::Update( CTFBot *me, float interval ) m_flTotalTravelDistance = NavAreaTravelDistance( me->GetLastKnownArea(), TheNavMesh->GetNavArea( zone->WorldSpaceCenter() ), cost ); - if ( flOldTravelDistance != -1.0f && m_flTotalTravelDistance - flOldTravelDistance > 2000.0f ) + if ( TFGameRules()->IsMannVsMachineMode() && flOldTravelDistance != -1.0f && m_flTotalTravelDistance - flOldTravelDistance > 2000.0f ) { TFGameRules()->BroadcastSound( 255, "Announcer.MVM_Bomb_Reset" ); diff --git a/game/server/tf/bot/behavior/spy/tf_bot_spy_hide.cpp b/game/server/tf/bot/behavior/spy/tf_bot_spy_hide.cpp index 2a35b313..914b2d95 100644 --- a/game/server/tf/bot/behavior/spy/tf_bot_spy_hide.cpp +++ b/game/server/tf/bot/behavior/spy/tf_bot_spy_hide.cpp @@ -70,7 +70,14 @@ ActionResult< CTFBot > CTFBotSpyHide::Update( CTFBot *me, float interval ) if ( m_talkTimer.IsElapsed() ) { m_talkTimer.Start( RandomFloat( 5.0f, 10.0f ) ); - me->EmitSound( "Spy.TeaseVictim" ); + if ( TFGameRules()->IsMannVsMachineMode() && me->GetTeamNumber() == TF_TEAM_PVE_INVADERS ) + { + me->EmitSound( "Spy.MVM_TeaseVictim" ); + } + else + { + me->EmitSound( "Spy.TeaseVictim" ); + } } if ( m_isAtGoal ) diff --git a/game/server/tf/bot/tf_bot.cpp b/game/server/tf/bot/tf_bot.cpp index d4b6810c..240941a8 100644 --- a/game/server/tf/bot/tf_bot.cpp +++ b/game/server/tf/bot/tf_bot.cpp @@ -704,9 +704,9 @@ DEFINE_SCRIPTFUNC( IsOnAnyMission, "Return true if this bot has a current missio DEFINE_SCRIPTFUNC_WRAPPED( SetMissionTarget, "Set this bot's mission target to the given entity" ) DEFINE_SCRIPTFUNC_WRAPPED( GetMissionTarget, "Get this bot's current mission target" ) -DEFINE_SCRIPTFUNC( SetBehaviorFlag, "Set the given behavior flag(s) for this bot" ) -DEFINE_SCRIPTFUNC( ClearBehaviorFlag, "Clear the given behavior flag(s) for this bot" ) -DEFINE_SCRIPTFUNC( IsBehaviorFlagSet, "Return true if the given behavior flag(s) are set for this bot" ) +DEFINE_SCRIPTFUNC_WRAPPED( SetBehaviorFlag, "Set the given behavior flag(s) for this bot" ) +DEFINE_SCRIPTFUNC_WRAPPED( ClearBehaviorFlag, "Clear the given behavior flag(s) for this bot" ) +DEFINE_SCRIPTFUNC_WRAPPED( IsBehaviorFlagSet, "Return true if the given behavior flag(s) are set for this bot" ) DEFINE_SCRIPTFUNC_WRAPPED( SetActionPoint, "Set the given action point for this bot" ) DEFINE_SCRIPTFUNC_WRAPPED( GetActionPoint, "Get the given action point for this bot" ) @@ -4597,15 +4597,15 @@ Action< CTFBot > *CTFBot::OpportunisticallyUseWeaponAbilities( void ) } } } - else if ( weapon->GetWeaponID() == TF_WEAPON_BAT_WOOD ) + else if ( ( weapon->GetWeaponID() == TF_WEAPON_BAT_WOOD ) || ( weapon->GetWeaponID() == TF_WEAPON_BAT_GIFTWRAP ) ) { - // sandman + // sandman or wrap assassin if ( GetAmmoCount( TF_AMMO_GRENADES1 ) > 0 ) { const CKnownEntity *threat = GetVisionInterface()->GetPrimaryKnownThreat(); if ( threat && threat->IsVisibleInFOVNow() ) { - // hit a stunball + // hit a stunball or bauble PressAltFireButton(); } } diff --git a/game/server/tf/bot/tf_bot.h b/game/server/tf/bot/tf_bot.h index 2d79db6d..cce41e3a 100644 --- a/game/server/tf/bot/tf_bot.h +++ b/game/server/tf/bot/tf_bot.h @@ -331,6 +331,9 @@ public: void SetBehaviorFlag( unsigned int flags ); void ClearBehaviorFlag( unsigned int flags ); bool IsBehaviorFlagSet( unsigned int flags ) const; + void ScriptSetBehaviorFlag( int flags ) { this->SetBehaviorFlag( (unsigned int)flags ); } + void ScriptClearBehaviorFlag( int flags ) { this->ClearBehaviorFlag( (unsigned int)flags ); } + bool ScriptIsBehaviorFlagSet( int flags ) const { return this->IsBehaviorFlagSet( (unsigned int)flags ); } bool FindSplashTarget( CBaseEntity *target, float maxSplashRadius, Vector *splashTarget ) const; @@ -358,11 +361,11 @@ public: CBaseEntity *GetMissionTarget( void ) const; void SetMissionString( CUtlString string ); CUtlString *GetMissionString( void ); - void ScriptSetMission( unsigned int mission, bool resetBehaviorSystem = true ) { this->SetMission( (MissionType)mission, resetBehaviorSystem ); } - void ScriptSetPrevMission( unsigned int mission ) { this->SetPrevMission( (MissionType)mission ); } - unsigned int ScriptGetMission( void ) const { return (unsigned int)this->GetMission(); } - unsigned int ScriptGetPrevMission( void ) const { return (unsigned int)this->GetPrevMission(); } - bool ScriptHasMission( unsigned int mission ) const { return this->HasMission( (MissionType)mission ); } + void ScriptSetMission( int mission, bool resetBehaviorSystem = true ) { this->SetMission( (MissionType)mission, resetBehaviorSystem ); } + void ScriptSetPrevMission( int mission ) { this->SetPrevMission( (MissionType)mission ); } + int ScriptGetMission( void ) const { return (int)this->GetMission(); } + int ScriptGetPrevMission( void ) const { return (int)this->GetPrevMission(); } + bool ScriptHasMission( int mission ) const { return this->HasMission( (MissionType)mission ); } void ScriptSetMissionTarget( HSCRIPT hTarget ) { this->SetMissionTarget( ToEnt( hTarget ) ); } HSCRIPT ScriptGetMissionTarget( void ) const { return ToHScript( this->GetMissionTarget() ); } diff --git a/game/server/tf/bot/tf_bot_squad.cpp b/game/server/tf/bot/tf_bot_squad.cpp index 91cc9144..f8e0b295 100644 --- a/game/server/tf/bot/tf_bot_squad.cpp +++ b/game/server/tf/bot/tf_bot_squad.cpp @@ -202,7 +202,7 @@ float CTFBotSquad::GetSlowestMemberIdealSpeed( bool includeLeader ) const //---------------------------------------------------------------------- -// Return the maximum formation error of the squad's memebers. +// Return the maximum formation error of the squad's members. float CTFBotSquad::GetMaxSquadFormationError( void ) const { float maxError = 0.0f; diff --git a/game/server/tf/entity_bird.cpp b/game/server/tf/entity_bird.cpp index b2d21b9e..a5a26db9 100644 --- a/game/server/tf/entity_bird.cpp +++ b/game/server/tf/entity_bird.cpp @@ -88,7 +88,7 @@ void CEntityBird::SpawnRandomBirds( void ) if ( !pszMapName || !pszMapName[0] ) return; - KeyValues *pFileKV = new KeyValues( "birds" ); + KeyValuesAD pFileKV( "birds" ); if ( !pFileKV->LoadFromFile( g_pFullFileSystem, "scripts/birds.txt", "MOD" ) ) return; @@ -139,8 +139,6 @@ void CEntityBird::SpawnRandomBirds( void ) } } } - - pFileKV->deleteThis(); } diff --git a/game/server/tf/entity_currencypack.cpp b/game/server/tf/entity_currencypack.cpp index b2dc51de..480f9d50 100644 --- a/game/server/tf/entity_currencypack.cpp +++ b/game/server/tf/entity_currencypack.cpp @@ -17,6 +17,7 @@ #include "particle_parse.h" #include "player_vs_environment/tf_population_manager.h" #include "collisionutils.h" +#include "func_respawnroom.h" #include "tf_objective_resource.h" //============================================================================= @@ -209,6 +210,21 @@ void CCurrencyPack::ComeToRest( void ) } } } + + // Or a func_respawnroom (robots can drop money in their own spawn) + for ( int i = 0; i < IFuncRespawnRoomAutoList::AutoList().Count(); i++ ) + { + CFuncRespawnRoom *pRespawnRoom = static_cast( IFuncRespawnRoomAutoList::AutoList()[ i ] ); + Vector vecMins, vecMaxs; + pRespawnRoom->GetCollideable()->WorldSpaceSurroundingBounds( &vecMins, &vecMaxs ); + if ( IsPointInBox( GetCollideable()->GetCollisionOrigin(), vecMins, vecMaxs ) ) + { + TFGameRules()->DistributeCurrencyAmount( m_nAmount ); + + m_bTouched = true; + UTIL_Remove( this ); + } + } } //----------------------------------------------------------------------------- diff --git a/game/server/tf/entity_healthkit.cpp b/game/server/tf/entity_healthkit.cpp index c02121ec..48990d38 100644 --- a/game/server/tf/entity_healthkit.cpp +++ b/game/server/tf/entity_healthkit.cpp @@ -304,5 +304,5 @@ bool CHealthAmmoKit::MyTouch( CBasePlayer *pPlayer ) } } - return bAmmoSuccess | bHealthSuccess; + return bAmmoSuccess || bHealthSuccess; } \ No newline at end of file diff --git a/game/server/tf/player_vs_environment/tf_population_manager.cpp b/game/server/tf/player_vs_environment/tf_population_manager.cpp index 4eaa037a..7d5b1bf5 100644 --- a/game/server/tf/player_vs_environment/tf_population_manager.cpp +++ b/game/server/tf/player_vs_environment/tf_population_manager.cpp @@ -2626,7 +2626,7 @@ void CPopulationManager::AllocateBots() Warning( "%d bots were already allocated some how before CPopulationManager::AllocateBots was called\n", botVector.Count() ); } - for ( int i = nNumEnemyBots; i < MVM_INVADERS_TEAM_SIZE; ++i ) + for ( int i = nNumEnemyBots; i < tf_mvm_max_invaders.GetInt(); ++i ) { CTFBot* newBot = NextBotCreatePlayerBot< CTFBot >( "TFBot", false ); if ( newBot ) diff --git a/game/server/tf/player_vs_environment/tf_population_manager.h b/game/server/tf/player_vs_environment/tf_population_manager.h index 2ce60bc8..c6ca3d22 100644 --- a/game/server/tf/player_vs_environment/tf_population_manager.h +++ b/game/server/tf/player_vs_environment/tf_population_manager.h @@ -137,8 +137,6 @@ public: bool IsBonusRound() const { return m_bBonusRound; } CBaseCombatCharacter* GetBonusBoss() const { return m_hBonusBoss; } - enum { MVM_INVADERS_TEAM_SIZE = 22 }; - static bool GetWavesUseReadyBetween() { return true; } void SetDefaultEventChangeAttributesName( const char* pszDefaultEventChangeAttributesName ) { m_defaultEventChangeAttributesName = pszDefaultEventChangeAttributesName; } diff --git a/game/server/tf/player_vs_environment/tf_populator_spawners.cpp b/game/server/tf/player_vs_environment/tf_populator_spawners.cpp index 2c5a0879..635edd70 100644 --- a/game/server/tf/player_vs_environment/tf_populator_spawners.cpp +++ b/game/server/tf/player_vs_environment/tf_populator_spawners.cpp @@ -1014,7 +1014,7 @@ bool CTFBotSpawner::Spawn( const Vector &rawHere, EntityHandleVector_t *result ) nNumEnemyBots = botVector.Count(); - if ( nNumEnemyBots >= CPopulationManager::MVM_INVADERS_TEAM_SIZE ) + if ( nNumEnemyBots >= tf_mvm_max_invaders.GetInt() ) { // no room for more if ( tf_populator_debug.GetBool() ) @@ -1023,10 +1023,10 @@ bool CTFBotSpawner::Spawn( const Vector &rawHere, EntityHandleVector_t *result ) } // extra guard if we're over full on bots - if ( nNumEnemyBots > CPopulationManager::MVM_INVADERS_TEAM_SIZE ) + if ( nNumEnemyBots > tf_mvm_max_invaders.GetInt() ) { // Kick bots until we are at the proper number starting with spectator bots - int iNumberToKick = nNumEnemyBots - CPopulationManager::MVM_INVADERS_TEAM_SIZE; + int iNumberToKick = nNumEnemyBots - tf_mvm_max_invaders.GetInt(); int iKickedBots = 0; // loop through spectators and invaders in that order diff --git a/game/server/tf/player_vs_environment/tf_populators.cpp b/game/server/tf/player_vs_environment/tf_populators.cpp index a568bb6c..05539bb7 100644 --- a/game/server/tf/player_vs_environment/tf_populators.cpp +++ b/game/server/tf/player_vs_environment/tf_populators.cpp @@ -741,7 +741,7 @@ bool CMissionPopulator::UpdateMission( CTFBot::MissionType mission ) // are there enough free slots? int currentEnemyCount = GetGlobalTeam( TF_TEAM_PVE_INVADERS )->GetNumPlayers(); - if ( currentEnemyCount + m_desiredCount > CPopulationManager::MVM_INVADERS_TEAM_SIZE ) + if ( currentEnemyCount + m_desiredCount > tf_mvm_max_invaders.GetInt() ) { // not enough slots yet if ( tf_populator_debug.GetBool() ) @@ -1578,7 +1578,7 @@ void CWaveSpawnPopulator::Update( void ) int currentEnemyCount = GetGlobalTeam( TF_TEAM_PVE_INVADERS )->GetNumPlayers(); - if ( currentEnemyCount + m_spawnCount + m_reservedPlayerSlotCount > CPopulationManager::MVM_INVADERS_TEAM_SIZE ) + if ( currentEnemyCount + m_spawnCount + m_reservedPlayerSlotCount > tf_mvm_max_invaders.GetInt() ) { // no space right now return; diff --git a/game/server/tf/tf_obj_sentrygun.cpp b/game/server/tf/tf_obj_sentrygun.cpp index d5ec343d..aa261cba 100644 --- a/game/server/tf/tf_obj_sentrygun.cpp +++ b/game/server/tf/tf_obj_sentrygun.cpp @@ -1367,6 +1367,7 @@ bool CObjectSentrygun::FireRocket() // Setup next rocket shot if ( m_bPlayerControlled ) { + AddGesture( ACT_RANGE_ATTACK2, 2.25, true ); m_flNextRocketAttack = gpGlobals->curtime + 2.25; } else diff --git a/game/server/tf/tf_obj_teleporter.cpp b/game/server/tf/tf_obj_teleporter.cpp index 723eb88e..e2a4c6f3 100644 --- a/game/server/tf/tf_obj_teleporter.cpp +++ b/game/server/tf/tf_obj_teleporter.cpp @@ -1166,6 +1166,12 @@ void CObjectTeleporter::TeleporterThink( void ) SetState( TELEPORTER_STATE_RECHARGING ); m_flCurrentRechargeDuration = (float)g_iTeleporterRechargeTimes[GetUpgradeLevel()]; + if ( !m_bWasMapPlaced ) + { + CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( GetBuilder(), m_flCurrentRechargeDuration, mult_teleporter_recharge_rate ); + } + + m_flRechargeTime = gpGlobals->curtime + m_flCurrentRechargeDuration; m_flMyNextThink = gpGlobals->curtime + m_flCurrentRechargeDuration; } break; diff --git a/game/server/tf/tf_passtime_logic.cpp b/game/server/tf/tf_passtime_logic.cpp index 098b8c2c..5ba9a2f6 100644 --- a/game/server/tf/tf_passtime_logic.cpp +++ b/game/server/tf/tf_passtime_logic.cpp @@ -1853,11 +1853,14 @@ bool CTFPasstimeLogic::ParseSetSection( const char *pStr, SetSectionParams &s ) { char pszStartName[64]; char pszEndName[64]; - const int iScanCount = sscanf( pStr, "%i %s %s", &s.num, pszStartName, pszEndName ); // WHAT YEAR IS IT + const int iScanCount = sscanf( pStr, "%i %63s %63s", &s.num, pszStartName, pszEndName ); // WHAT YEAR IS IT if ( iScanCount != 3 ) { return false; } + pszStartName[ ARRAYSIZE( pszStartName ) - 1 ] = '\0'; + pszEndName[ ARRAYSIZE( pszEndName ) - 1 ] = '\0'; + s.pSectionStart = dynamic_cast( gEntList.FindEntityByName( 0, pszStartName ) ); s.pSectionEnd = dynamic_cast( gEntList.FindEntityByName( 0, pszEndName ) ); diff --git a/game/server/tf/tf_player.cpp b/game/server/tf/tf_player.cpp index 940b946a..d29e346d 100644 --- a/game/server/tf/tf_player.cpp +++ b/game/server/tf/tf_player.cpp @@ -126,7 +126,6 @@ #include "tf_revive.h" #include "tf_logic_halloween_2014.h" #include "tf_logic_player_destruction.h" -#include "tf_weapon_rocketpack.h" #include "tf_weapon_slap.h" #include "func_croc.h" #include "tf_weapon_bonesaw.h" @@ -278,6 +277,7 @@ extern ConVar sv_vote_allow_spectators; ConVar sv_vote_late_join_time( "sv_vote_late_join_time", "90", FCVAR_NONE, "Grace period after the match starts before players who join the match receive a vote-creation cooldown" ); ConVar sv_vote_late_join_cooldown( "sv_vote_late_join_cooldown", "300", FCVAR_NONE, "Length of the vote-creation cooldown when joining the server after the grace period has expired" ); +extern ConVar tf_voice_command_suspension_mode; extern ConVar tf_feign_death_duration; extern ConVar spec_freeze_time; extern ConVar spec_freeze_traveltime; @@ -815,6 +815,7 @@ IMPLEMENT_SERVERCLASS_ST( CTFPlayer, DT_TFPlayer ) SendPropFloat( SENDINFO( m_flMvMLastDamageTime ), 16, SPROP_ROUNDUP ), SendPropInt( SENDINFO( m_iSpawnCounter ) ), + SendPropBool( SENDINFO( m_bFlipViewModels ) ), SendPropBool( SENDINFO( m_bArenaSpectator ) ), SendPropFloat( SENDINFO( m_flHeadScale ) ), SendPropFloat( SENDINFO( m_flTorsoScale ) ), @@ -843,6 +844,7 @@ IMPLEMENT_SERVERCLASS_ST( CTFPlayer, DT_TFPlayer ) SendPropInt( SENDINFO( m_iPlayerSkinOverride ) ), SendPropBool( SENDINFO( m_bViewingCYOAPDA ) ), SendPropBool( SENDINFO( m_bRegenerating ) ), + SendPropEHandle( SENDINFO( m_hOffHandWeapon ) ), END_SEND_TABLE() // -------------------------------------------------------------------------------- // @@ -997,7 +999,6 @@ CTFPlayer::CTFPlayer() m_flNextChangeClassTime = 0.0f; m_flNextChangeTeamTime = 0.0f; - m_bScattergunJump = false; m_iOldStunFlags = 0; m_iLastWeaponSlot = 1; m_iNumberofDominations = 0; @@ -1453,35 +1454,6 @@ void CTFPlayer::TFPlayerThink() else { m_iLeftGroundHealth = -1; - if ( GetFlags() & FL_ONGROUND ) - { - // Airborne conditions end on ground contact - m_Shared.RemoveCond( TF_COND_KNOCKED_INTO_AIR ); - m_Shared.RemoveCond( TF_COND_AIR_CURRENT ); - - if ( m_Shared.InCond( TF_COND_ROCKETPACK ) ) - { - // Make sure we're still not dealing with launch, where it's possible - // to hit your head and fall to the ground before the second stage. - CTFWeaponBase *pRocketPack = Weapon_OwnsThisID( TF_WEAPON_ROCKETPACK ); - if ( pRocketPack ) - { - if ( gpGlobals->curtime > ( static_cast< CTFRocketPack* >( pRocketPack )->GetRefireTime() ) ) - { - EmitSound( "Weapon_RocketPack.BoostersShutdown" ); - EmitSound( "Weapon_RocketPack.Land" ); - m_Shared.RemoveCond( TF_COND_ROCKETPACK ); - - IGameEvent *pEvent = gameeventmanager->CreateEvent( "rocketpack_landed" ); - if ( pEvent ) - { - pEvent->SetInt( "userid", GetUserID() ); - gameeventmanager->FireEvent( pEvent ); - } - } - } - } - } if ( m_iBlastJumpState ) { @@ -2833,6 +2805,7 @@ void CTFPlayer::PrecacheMvM() PrecacheScriptSound( "MVM.DeployBombGiant" ); PrecacheScriptSound( "Weapon_Upgrade.ExplosiveHeadshot" ); PrecacheScriptSound( "Spy.MVM_Chuckle" ); + PrecacheScriptSound( "Spy.MVM_TeaseVictim" ); PrecacheScriptSound( "MVM.Robot_Engineer_Spawn" ); PrecacheScriptSound( "MVM.Robot_Teleporter_Deliver" ); PrecacheScriptSound( "MVM.MoneyPickup" ); @@ -3781,7 +3754,6 @@ void CTFPlayer::Spawn() m_Shared.SetFeignDeathReady( false ); - m_bScattergunJump = false; m_iOldStunFlags = 0; m_flAccumulatedHealthRegen = 0; @@ -5979,8 +5951,9 @@ void CTFPlayer::HandleAnimEvent( animevent_t *pEvent ) char szAttrName[128]; float flVal; float flDuration; - if ( sscanf( pEvent->options, "%s %f %f", szAttrName, &flVal, &flDuration ) == 3 ) + if ( sscanf( pEvent->options, "%127s %f %f", szAttrName, &flVal, &flDuration ) == 3 ) { + szAttrName[ ARRAYSIZE( szAttrName ) - 1 ] = '\0'; Assert( flDuration > 0.f ); AddCustomAttribute( szAttrName, flVal, flDuration ); } @@ -6898,20 +6871,29 @@ void CTFPlayer::HandleCommand_JoinClass( const char *pClassName, bool bAllowSpaw } else { - int iTries = 20; - // The player has selected Random class...so let's pick one for them. - do{ - // Don't let them be the same class twice in a row - iClass = random->RandomInt( TF_FIRST_NORMAL_CLASS, TF_LAST_NORMAL_CLASS - 1 ); // -1 to remove the civilian from the randomness - iTries--; - } while( iClass == GetPlayerClass()->GetClassIndex() || (iTries > 0 && !TFGameRules()->CanPlayerChooseClass(this,iClass)) ); + int iChoices = 0; + int iClasses[ TF_LAST_NORMAL_CLASS - 1 ] = {}; // -1 to remove the civilian from the randomness + int iCurrentClass = GetPlayerClass()->GetClassIndex(); - if ( iTries <= 0 ) + for ( iClass = TF_FIRST_NORMAL_CLASS; iClass < TF_LAST_NORMAL_CLASS; iClass++ ) { + if ( iClass != iCurrentClass && TFGameRules()->CanPlayerChooseClass( this, iClass ) ) + { + iClasses[ iChoices++ ] = iClass; + } + } + + if ( !iChoices ) + { + if ( TFGameRules()->CanPlayerChooseClass( this, iCurrentClass ) ) + return; + // We failed to find a random class. Bring up the class menu again. ShowViewPortPanel( ( GetTeamNumber() == TF_TEAM_RED ) ? PANEL_CLASS_RED : PANEL_CLASS_BLUE ); return; } + + iClass = iClasses[ random->RandomInt( 0, iChoices - 1 ) ]; } if ( TFGameRules() && TFGameRules()->State_Get() == GR_STATE_RND_RUNNING ) @@ -7362,7 +7344,7 @@ bool CTFPlayer::ClientCommand( const CCommand &args ) if ( FStrEq( pcmd, "jointeam" ) ) { // don't let them spam the server with changes - if ( GetNextChangeTeamTime() > gpGlobals->curtime ) + if ( ( GetNextChangeTeamTime() > gpGlobals->curtime ) && ( GetTeamNumber() != TEAM_UNASSIGNED ) ) return true; SetNextChangeTeamTime( gpGlobals->curtime + 2.0f ); // limit to one change every 2 secs @@ -9127,44 +9109,40 @@ int CTFPlayer::OnTakeDamage( const CTakeDamageInfo &inputInfo ) } } - if ( pTFAttacker && pTFAttacker->IsPlayerClass( TF_CLASS_MEDIC ) ) + if ( pTFAttacker && pTFAttacker->IsPlayerClass( TF_CLASS_MEDIC ) && pWeapon && pWeapon->GetWeaponID() == TF_WEAPON_BONESAW ) { - CTFWeaponBase *pAttackerWeapon = pTFAttacker->GetActiveTFWeapon(); - if ( pAttackerWeapon && pAttackerWeapon->GetWeaponID() == TF_WEAPON_BONESAW ) + CTFBonesaw *pBoneSaw = static_cast< CTFBonesaw* >( pWeapon ); + if ( pBoneSaw->GetBonesawType() == BONESAW_UBER_SAVEDONDEATH ) { - CTFBonesaw *pBoneSaw = static_cast< CTFBonesaw* >( pAttackerWeapon ); - if ( pBoneSaw->GetBonesawType() == BONESAW_UBER_SAVEDONDEATH ) + // Spawn their spleen + CPhysicsProp *pRandomInternalOrgan = dynamic_cast< CPhysicsProp* >( CreateEntityByName( "prop_physics_override" ) ); + if ( pRandomInternalOrgan ) { - // Spawn their spleen - CPhysicsProp *pRandomInternalOrgan = dynamic_cast< CPhysicsProp* >( CreateEntityByName( "prop_physics_override" ) ); - if ( pRandomInternalOrgan ) - { - pRandomInternalOrgan->SetCollisionGroup( COLLISION_GROUP_DEBRIS ); - pRandomInternalOrgan->AddFlag( FL_GRENADE ); - char buf[512]; - Q_snprintf( buf, sizeof( buf ), "%.10f %.10f %.10f", GetAbsOrigin().x, GetAbsOrigin().y, GetAbsOrigin().z ); - pRandomInternalOrgan->KeyValue( "origin", buf ); - Q_snprintf( buf, sizeof( buf ), "%.10f %.10f %.10f", GetAbsAngles().x, GetAbsAngles().y, GetAbsAngles().z ); - pRandomInternalOrgan->KeyValue( "angles", buf ); - pRandomInternalOrgan->KeyValue( "model", "models/player/gibs/random_organ.mdl" ); - pRandomInternalOrgan->KeyValue( "fademindist", "-1" ); - pRandomInternalOrgan->KeyValue( "fademaxdist", "0" ); - pRandomInternalOrgan->KeyValue( "fadescale", "1" ); - pRandomInternalOrgan->KeyValue( "inertiaScale", "1.0" ); - pRandomInternalOrgan->KeyValue( "physdamagescale", "0.1" ); - DispatchSpawn( pRandomInternalOrgan ); - pRandomInternalOrgan->m_takedamage = DAMAGE_YES; // Take damage, otherwise this can block trains - pRandomInternalOrgan->SetHealth( 100 ); - pRandomInternalOrgan->Activate(); + pRandomInternalOrgan->SetCollisionGroup( COLLISION_GROUP_DEBRIS ); + pRandomInternalOrgan->AddFlag( FL_GRENADE ); + char buf[512]; + Q_snprintf( buf, sizeof( buf ), "%.10f %.10f %.10f", GetAbsOrigin().x, GetAbsOrigin().y, GetAbsOrigin().z ); + pRandomInternalOrgan->KeyValue( "origin", buf ); + Q_snprintf( buf, sizeof( buf ), "%.10f %.10f %.10f", GetAbsAngles().x, GetAbsAngles().y, GetAbsAngles().z ); + pRandomInternalOrgan->KeyValue( "angles", buf ); + pRandomInternalOrgan->KeyValue( "model", "models/player/gibs/random_organ.mdl" ); + pRandomInternalOrgan->KeyValue( "fademindist", "-1" ); + pRandomInternalOrgan->KeyValue( "fademaxdist", "0" ); + pRandomInternalOrgan->KeyValue( "fadescale", "1" ); + pRandomInternalOrgan->KeyValue( "inertiaScale", "1.0" ); + pRandomInternalOrgan->KeyValue( "physdamagescale", "0.1" ); + DispatchSpawn( pRandomInternalOrgan ); + pRandomInternalOrgan->m_takedamage = DAMAGE_YES; // Take damage, otherwise this can block trains + pRandomInternalOrgan->SetHealth( 100 ); + pRandomInternalOrgan->Activate(); - Vector vecImpulse = RandomVector( -1.f, 1.f ); - vecImpulse.z = 1.f; - VectorNormalize( vecImpulse ); - Vector vecVelocity = vecImpulse * 250.0; - pRandomInternalOrgan->ApplyAbsVelocityImpulse( vecVelocity ); + Vector vecImpulse = RandomVector( -1.f, 1.f ); + vecImpulse.z = 1.f; + VectorNormalize( vecImpulse ); + Vector vecVelocity = vecImpulse * 250.0; + pRandomInternalOrgan->ApplyAbsVelocityImpulse( vecVelocity ); - pRandomInternalOrgan->ThinkSet( &CBaseEntity::SUB_Remove, gpGlobals->curtime + 5.f, "DieContext" ); - } + pRandomInternalOrgan->ThinkSet( &CBaseEntity::SUB_Remove, gpGlobals->curtime + 5.f, "DieContext" ); } } } @@ -14786,10 +14764,7 @@ void CTFPlayer::CheatImpulseCommands( int iImpulse ) pWeapon->GiveDefaultAmmo(); - if ( pWeapon->IsEnergyWeapon() ) - { - pWeapon->WeaponRegenerate(); - } + pWeapon->WeaponRegenerate(); } m_Shared.m_flRageMeter = 100.f; @@ -19157,6 +19132,30 @@ void CTFPlayer::DoTauntAttack( void ) pLoser->TakeDamage( CTakeDamageInfo( pWinner, pWinner, NULL, 999, DMG_GENERIC, 0 ) ); } } + else if ( iTauntAttack == TAUNTATK_ENGINEER_TRICKSHOT ) + { + // Engineer "Texan Trickshot" attack + Vector vecForward; + AngleVectors( EyeAngles(), &vecForward ); + Vector vecEnd = EyePosition() + vecForward * 500; + + trace_t tr; + UTIL_TraceLine( EyePosition(), vecEnd, ( MASK_SOLID | CONTENTS_HITBOX ), this, COLLISION_GROUP_PLAYER, &tr ); + // DebugDrawLine( EyePosition(), vecEnd, 0, 0, 255, true, 3.0f ); + + if ( tr.fraction < 1.0 ) + { + CBaseEntity *pEnt = tr.m_pEnt; + + if ( pEnt && pEnt->IsPlayer() && pEnt->GetTeamNumber() > LAST_SHARED_TEAM && pEnt->GetTeamNumber() != GetTeamNumber() ) + { + // Launch them up a little + AngleVectors( QAngle( -45, m_angEyeAngles[ YAW ], 0 ), &vecForward ); + pEnt->TakeDamage( CTakeDamageInfo( this, this, GetActiveTFWeapon(), vecForward * 25000, WorldSpaceCenter(), 500.0f, DMG_BULLET, TF_DMG_CUSTOM_TAUNTATK_TRICKSHOT ) ); + } + } + } + // Particle Being played in VCD instead //else if ( iTauntAttack == TAUNTATK_FLIP_LAND_PARTICLE ) //{ @@ -20028,7 +20027,20 @@ bool CTFPlayer::ShouldShowVoiceSubtitleToEnemy( void ) //----------------------------------------------------------------------------- bool CTFPlayer::CanSpeakVoiceCommand( void ) { - return ( gpGlobals->curtime > m_flNextVoiceCommandTime ); + if ( tf_voice_command_suspension_mode.GetInt() == 1 ) + return false; + + if ( gpGlobals->curtime <= m_flNextVoiceCommandTime ) + return false; + + // misyl: New F2P voice command rate-limiting path. + if ( BHaveChatSuspensionInCurrentMatch() && tf_voice_command_suspension_mode.GetInt() == 2 ) + { + if ( !m_RateLimitedVoiceCommandTokenBucket.BTakeToken( gpGlobals->curtime ) ) + return false; + } + + return true; } //----------------------------------------------------------------------------- @@ -21593,6 +21605,7 @@ static bool SelectPartnerTaunt( const GameItemDefinition_t *pItemDef, CTFPlayer { static CSchemaItemDefHandle pItemDef_rpsTaunt( "RPS Taunt" ); static CSchemaItemDefHandle pItemDef_TauntNeckSnap( "Taunt: Neck Snap" ); + static CSchemaItemDefHandle pItemDef_TauntBearHug( "Taunt: Bear Hug" ); CTFTauntInfo *pTauntData = pItemDef->GetTauntData(); if ( !pTauntData ) @@ -21642,6 +21655,13 @@ static bool SelectPartnerTaunt( const GameItemDefinition_t *pItemDef, CTFPlayer iInitiator = 0; iReceiver = ( iReceiverClass != TF_CLASS_SOLDIER ) ? 0 : 1; } + else if ( pItemDef == pItemDef_TauntBearHug ) + { + Assert( iInitiatorSceneCount == 2 && iReceiverSceneCount > 0 ); + + iInitiator = 0; + iReceiver = ( iReceiverClass != TF_CLASS_HEAVYWEAPONS ) ? 0 : 1; + } else { // randomly select a player to pick 0 (could be silent taunt) diff --git a/game/server/tf/tf_player.h b/game/server/tf/tf_player.h index 532d5b6e..d2affa28 100644 --- a/game/server/tf/tf_player.h +++ b/game/server/tf/tf_player.h @@ -66,6 +66,46 @@ enum EAmmoSource kAmmoSource_ResourceMeter, // it regenerated after a cooldown }; +extern ConVar tf_voice_command_suspension_rate_limit_bucket_count; +extern ConVar tf_voice_command_suspension_rate_limit_bucket_refill_rate; + +class CVoiceCommandBucketSizer +{ +public: + int GetBucketSize() const { return tf_voice_command_suspension_rate_limit_bucket_count.GetInt(); } + float GetBucketRefillRate() const { return tf_voice_command_suspension_rate_limit_bucket_refill_rate.GetFloat(); } +}; + +template +class CRateLimitingTokenBucket : public TBucketSizer +{ +public: + CRateLimitingTokenBucket() + : m_nBucket( this->GetBucketSize() ) + { + } + + bool BTakeToken( float flNow ) + { + // misyl: This token bucket doesn't go negative, so you don't ever dig yourself into a hole by spamming. + // You might want that if you use this class, feel free to add something to the BucketSizer. + + int nNewBucket = MIN( m_nBucket + ( flNow - m_flLastTokenTaken ) / this->GetBucketRefillRate(), this->GetBucketSize() ) - 1; + if ( nNewBucket <= 0 ) + { + return false; + } + + m_nBucket = nNewBucket; + m_flLastTokenTaken = flNow; + + return true; + } +private: + float m_flLastTokenTaken = 0.0f; + int m_nBucket = 0; +}; + //============================================================================= // // TF Player @@ -483,6 +523,8 @@ public: float m_flNextVoiceCommandTime; int m_iVoiceSpamCounter; + CRateLimitingTokenBucket m_RateLimitedVoiceCommandTokenBucket; + float m_flNextSpeakWeaponFire; virtual int CalculateTeamBalanceScore( void ); @@ -911,6 +953,8 @@ public: CTFWeaponBase *Weapon_OwnsThisID( int iWeaponID ) const; CTFWeaponBase *Weapon_GetWeaponByType( int iType ); + virtual void PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool force ); + medigun_charge_types GetChargeEffectBeingProvided( void ); // Achievements @@ -938,10 +982,9 @@ public: bool m_bSuicideExplode; - bool m_bScattergunJump; int m_iOldStunFlags; - bool m_bFlipViewModels; + CNetworkVar( bool, m_bFlipViewModels ); int m_iBlastJumpState; float m_flBlastJumpLandTime; bool m_bTakenBlastDamageSinceLastMovement; diff --git a/game/server/tf/tf_projectile_flare.cpp b/game/server/tf/tf_projectile_flare.cpp index effa29d1..373dfbea 100644 --- a/game/server/tf/tf_projectile_flare.cpp +++ b/game/server/tf/tf_projectile_flare.cpp @@ -413,7 +413,7 @@ void CTFProjectile_Flare::Explode_Air( trace_t *pTrace, int bitsDamageType, bool if ( bSelfOnly ) { bitsDamageType |= DMG_BLAST; - nSound = SPECIAL2; + nSound = SPECIAL3; } CTakeDamageInfo info( this, pAttacker, m_hLauncher, vec3_origin, vecOrigin, GetDamage(), bitsDamageType | DMG_HALF_FALLOFF, TF_DMG_CUSTOM_FLARE_EXPLOSION ); diff --git a/game/server/tf/tf_projectile_rocket.cpp b/game/server/tf/tf_projectile_rocket.cpp index 2d829bd7..528b2907 100644 --- a/game/server/tf/tf_projectile_rocket.cpp +++ b/game/server/tf/tf_projectile_rocket.cpp @@ -153,7 +153,15 @@ void CTFProjectile_Rocket::Deflected( CBaseEntity *pDeflectedBy, Vector &vecDir ChangeTeam( pTFDeflector->GetTeamNumber() ); SetLauncher( pTFDeflector->GetActiveWeapon() ); - CTFPlayer* pOldOwner = ToTFPlayer( GetOwnerEntity() ); + CTFPlayer *pOldOwner = ToTFPlayer( GetOwnerEntity() ); + if ( pOldOwner == nullptr ) + { + CBaseObject *pBaseObject = dynamic_cast< CBaseObject* >( GetOwnerEntity() ); + if ( pBaseObject && pBaseObject->GetOwner() ) + { + pOldOwner = ToTFPlayer( pBaseObject->GetOwner() ); + } + } SetOwnerEntity( pTFDeflector ); if ( pOldOwner ) diff --git a/game/server/variant_t.h b/game/server/variant_t.h index 91b94207..d5e93ea4 100644 --- a/game/server/variant_t.h +++ b/game/server/variant_t.h @@ -39,7 +39,7 @@ class variant_t public: // constructor - variant_t() : iVal(0), fieldType(FIELD_VOID) {} + variant_t() : fieldType(FIELD_VOID), iVal(0) {} inline bool Bool( void ) const { return( fieldType == FIELD_BOOLEAN ) ? bVal : false; } inline const char *String( void ) const { return( fieldType == FIELD_STRING ) ? STRING(iszVal) : ToString(); } diff --git a/game/server/vscript_server.cpp b/game/server/vscript_server.cpp index 43ff4f53..c1b2eae8 100644 --- a/game/server/vscript_server.cpp +++ b/game/server/vscript_server.cpp @@ -3370,6 +3370,7 @@ DECLARE_SCRIPT_CONST( ETFDmgCustom, TF_DMG_CUSTOM_SLAP_KILL ) DECLARE_SCRIPT_CONST( ETFDmgCustom, TF_DMG_CUSTOM_CROC ) DECLARE_SCRIPT_CONST( ETFDmgCustom, TF_DMG_CUSTOM_TAUNTATK_GASBLAST ) DECLARE_SCRIPT_CONST( ETFDmgCustom, TF_DMG_CUSTOM_AXTINGUISHER_BOOSTED ) +DECLARE_SCRIPT_CONST( ETFDmgCustom, TF_DMG_CUSTOM_TAUNTATK_TRICKSHOT ) DECLARE_SCRIPT_CONST( ETFDmgCustom, TF_DMG_CUSTOM_END ) REGISTER_SCRIPT_CONST_TABLE( ETFDmgCustom ) diff --git a/game/shared/achievementmgr.cpp b/game/shared/achievementmgr.cpp index 66c5e9c3..6b5e6a09 100644 --- a/game/shared/achievementmgr.cpp +++ b/game/shared/achievementmgr.cpp @@ -801,7 +801,7 @@ void CAchievementMgr::LoadGlobalState() // HPE_END //============================================================================= - KeyValues *pKV = new KeyValues("GameState" ); + KeyValuesAD pKV("GameState" ); if ( pKV->LoadFromFile( filesystem, szFilename, "MOD" ) ) { KeyValues *pNode = pKV->GetFirstSubKey(); diff --git a/game/shared/activitylist.cpp b/game/shared/activitylist.cpp index a57513fd..edfcb66b 100644 --- a/game/shared/activitylist.cpp +++ b/game/shared/activitylist.cpp @@ -2607,7 +2607,7 @@ void UTIL_LoadActivityRemapFile( const char *filename, const char *section, CUtl return; } - KeyValues *pkvFile = new KeyValues( section ); + KeyValuesAD pkvFile( section ); if ( pkvFile->LoadFromFile( filesystem, filename, NULL ) ) { diff --git a/game/shared/basegrenade_shared.cpp b/game/shared/basegrenade_shared.cpp index b981d078..421bfaed 100644 --- a/game/shared/basegrenade_shared.cpp +++ b/game/shared/basegrenade_shared.cpp @@ -54,8 +54,6 @@ BEGIN_DATADESC( CBaseGrenade ) END_DATADESC() -void SendProxy_CropFlagsToPlayerFlagBitsLength( const SendProp *pProp, const void *pStruct, const void *pVarData, DVariant *pOut, int iElement, int objectID); - #endif IMPLEMENT_NETWORKCLASS_ALIASED( BaseGrenade, DT_BaseGrenade ) @@ -70,7 +68,7 @@ BEGIN_NETWORK_TABLE( CBaseGrenade, DT_BaseGrenade ) SendPropVector( SENDINFO( m_vecVelocity ), 0, SPROP_NOSCALE ), // HACK: Use same flag bits as player for now - SendPropInt ( SENDINFO(m_fFlags), PLAYER_FLAG_BITS, SPROP_UNSIGNED, SendProxy_CropFlagsToPlayerFlagBitsLength ), + SendPropInt ( SENDINFO(m_fFlags), 0, SPROP_UNSIGNED ), #else RecvPropFloat( RECVINFO( m_flDamage ) ), RecvPropFloat( RECVINFO( m_DmgRadius ) ), diff --git a/game/shared/econ/econ_entity.cpp b/game/shared/econ/econ_entity.cpp index dd48f4c4..f3aa69b2 100644 --- a/game/shared/econ/econ_entity.cpp +++ b/game/shared/econ/econ_entity.cpp @@ -20,6 +20,7 @@ #if defined(TF_CLIENT_DLL) #include "c_tf_player.h" +#include "c_baseviewmodel.h" #include "tf_gamerules.h" #include "c_playerresource.h" #include "tf_shareddefs.h" @@ -92,7 +93,6 @@ END_SCRIPTDESC(); #endif #ifdef TF_CLIENT_DLL -extern ConVar cl_flipviewmodels; #endif @@ -857,7 +857,7 @@ int C_ViewmodelAttachmentModel::InternalDrawModel( int flags ) { #ifdef TF_CLIENT_DLL CMatRenderContextPtr pRenderContext( materials ); - if ( cl_flipviewmodels.GetBool() != m_bAlwaysFlip ) + if ( TeamFortress_ShouldFlipClientViewModel() != m_bAlwaysFlip ) { pRenderContext->CullMode( MATERIAL_CULLMODE_CW ); } diff --git a/game/shared/econ/econ_holidays.cpp b/game/shared/econ/econ_holidays.cpp index 1bbe3371..8a3369d7 100644 --- a/game/shared/econ/econ_holidays.cpp +++ b/game/shared/econ/econ_holidays.cpp @@ -316,7 +316,7 @@ static CDateBasedHolidayNoSpecificYear g_Holiday_ValentinesDay ( "valentines", " static CDateBasedHoliday g_Holiday_MeetThePyro ( "meet_the_pyro", "2012-06-26", "2012-07-05" ); /* starting date cycle length in days bonus time in days on both sides */ -static CCyclicalHoliday g_Holiday_FullMoon ( "fullmoon", 12, 15, 2024, 29.53f, 1.0f ); +static CCyclicalHoliday g_Holiday_FullMoon ( "fullmoon", 10, 06, 2025, 29.53f, 1.0f ); // note: the cycle length is 29.5 instead of 29.53 so that the time calculations always start at noon based on the way CCyclicalHoliday works static COrHoliday g_Holiday_HalloweenOrFullMoon ( "halloween_or_fullmoon", &g_Holiday_Halloween, &g_Holiday_FullMoon ); @@ -330,8 +330,8 @@ static CDateBasedHoliday g_Holiday_CommunityUpdate ( "community_update", "2015 static CDateBasedHolidayNoSpecificYear g_Holiday_Soldier ( "soldier", "04-12", "04-14" ); -// only setup for 2024 right now...need to figure out how we want future events to run and maybe remove the year -static CDateBasedHoliday g_Holiday_Summer( "summer", "2024-07-01", "2024-09-16" ); +// only setup for 2025 right now...need to figure out how we want future events to run and maybe remove the year +static CDateBasedHoliday g_Holiday_Summer( "summer", "2025-07-16", "2025-09-16" ); // ORDER NEEDS TO MATCH enum EHoliday static IIsHolidayActive *s_HolidayChecks[] = diff --git a/game/shared/econ/econ_item_description.cpp b/game/shared/econ/econ_item_description.cpp index e491cb6c..529e8350 100644 --- a/game/shared/econ/econ_item_description.cpp +++ b/game/shared/econ/econ_item_description.cpp @@ -2817,6 +2817,10 @@ void CEconItemDescription::Generate_CollectionDesc( const CLocalizationProvider if ( !pItemDef ) return; + // Adding a check for if the collection we are browsing contains cosmetics or decorated weapons. + // We can handle decorated weapons the same as cosmetics, since they have proper schema entries + bool bIsHatOrDecorated = false; + // For War Painted items (not War Paints themselves) we want highlight the row of the // War Paint itself in the collection. Look up our corresponding War Paint's item def // and use that as our own if there is one. @@ -2824,6 +2828,10 @@ void CEconItemDescription::Generate_CollectionDesc( const CLocalizationProvider if ( GetPaintKitDefIndex( pEconItem, &nPaintkitDefindex ) ) { auto pPaintkitItemDef = GetItemSchema()->GetPaintKitItemDefinition( nPaintkitDefindex ); + if ( pPaintkitItemDef == NULL ) + { + bIsHatOrDecorated = true; + } pItemDef = pPaintkitItemDef ? pPaintkitItemDef : pItemDef; } @@ -2885,7 +2893,7 @@ void CEconItemDescription::Generate_CollectionDesc( const CLocalizationProvider return &vecItemsWithDefindex; uint32 unPaintkitDefidnex = 0; - if ( GetPaintKitDefIndex( pItemDef, &unPaintkitDefidnex ) ) + if ( GetPaintKitDefIndex( pItemDef, &unPaintkitDefidnex ) && !bIsHatOrDecorated ) { auto& vecItemsWithPaintkit = pLocalInv->GetItemsWithPaintkitDefindex( unPaintkitDefidnex ); if ( !vecItemsWithPaintkit.IsEmpty() ) @@ -3689,7 +3697,8 @@ void CEconItemDescription::AddAttributeDescription( const CLocalizationProvider } // They can also be from Halloween spells. These are intended to expire after Halloween in any // event, but for display purposes they'll appear in grey unless the holiday is active. - else if ( pAttribDef->GetUserGenerationType() == kUserGeneratedAttributeType_HalloweenSpell && !EconHolidays_IsHolidayActive( kHoliday_Halloween, CRTime::RTime32TimeCur() ) ) + else if ( pAttribDef->GetUserGenerationType() == kUserGeneratedAttributeType_HalloweenSpell && + !(EconHolidays_IsHolidayActive(kHoliday_Halloween, CRTime::RTime32TimeCur()) || EconHolidays_IsHolidayActive(kHoliday_FullMoon, CRTime::RTime32TimeCur())) ) { eDefaultAttribColor = ATTRIB_COL_ITEMSET_MISSING; } diff --git a/game/shared/econ/econ_item_system.cpp b/game/shared/econ/econ_item_system.cpp index aa68d574..91c5801f 100644 --- a/game/shared/econ/econ_item_system.cpp +++ b/game/shared/econ/econ_item_system.cpp @@ -177,10 +177,14 @@ void CEconItemSystem::ReloadWhitelist( void ) // If we didn't find a file, we're done. if ( !bFoundWhitelist ) + { + pWhitelistKV->deleteThis(); return; + } // Otherwise, go through the KVs and turn on the matching items. Msg("Parsing item whitelist (default: %s)\n", bDefault ? "allowed" : "disallowed" ); + KeyValues* ownerWhitelistKV = pWhitelistKV; pWhitelistKV = pWhitelistKV->GetFirstSubKey(); while ( pWhitelistKV ) { @@ -204,6 +208,8 @@ void CEconItemSystem::ReloadWhitelist( void ) pWhitelistKV = pWhitelistKV->GetNextKey(); } Msg("Finished.\n"); + + ownerWhitelistKV->deleteThis(); } #ifdef GAME_DLL diff --git a/game/shared/econ/econ_quests.cpp b/game/shared/econ/econ_quests.cpp index a19e8bb5..695f438f 100644 --- a/game/shared/econ/econ_quests.cpp +++ b/game/shared/econ/econ_quests.cpp @@ -64,7 +64,7 @@ COMPILE_TIME_ASSERT( ARRAYSIZE( g_QuestPointsDefs ) == EQuestPoints_ARRAYSIZE ); extern bool InitPerClassRandomChanceStringArray( KeyValues *pPerClassData, CRandomChanceString (&outputArray)[LOADOUT_COUNT], CUtlVector* pVecErrors ); #ifdef CLIENT_DLL -CON_COMMAND( set_party_contract_progress_enabled, "Set whether or not you'd like your party memebers to be able to make progress on your Contracts along with you." ) +CON_COMMAND( set_party_contract_progress_enabled, "Set whether or not you'd like your party members to be able to make progress on your Contracts along with you." ) { if ( args.ArgC() != 2 ) { diff --git a/game/shared/gamemovement.cpp b/game/shared/gamemovement.cpp index ad1e4709..4b79f72c 100644 --- a/game/shared/gamemovement.cpp +++ b/game/shared/gamemovement.cpp @@ -4011,6 +4011,18 @@ void CGameMovement::PlayerRoughLandingEffects( float fvol ) } } +//----------------------------------------------------------------------------- +// Purpose: Reset interpolation when player duck state changes +// Input : direction - +//----------------------------------------------------------------------------- +void CGameMovement::ResetDuckLatched() +{ +#ifdef CLIENT_DLL + if ( !player->InFirstPersonView() ) + player->ResetLatched(); +#endif +} + //----------------------------------------------------------------------------- // Purpose: Use for ease-in, ease-out style interpolation (accel/decel) Used by ducking code. // Input : value - @@ -4133,9 +4145,7 @@ void CGameMovement::FinishUnDuck( void ) mv->SetAbsOrigin( newOrigin ); -#ifdef CLIENT_DLL - player->ResetLatched(); -#endif // CLIENT_DLL + ResetDuckLatched(); // Recategorize position since ducking can change origin CategorizePosition(); @@ -4232,9 +4242,7 @@ void CGameMovement::FinishDuck( void ) VectorAdd( mv->GetAbsOrigin(), viewDelta, out ); mv->SetAbsOrigin( out ); -#ifdef CLIENT_DLL - player->ResetLatched(); -#endif // CLIENT_DLL + ResetDuckLatched(); } // See if we are stuck? diff --git a/game/shared/gamemovement.h b/game/shared/gamemovement.h index 1cb3fa52..8c9b7d9a 100644 --- a/game/shared/gamemovement.h +++ b/game/shared/gamemovement.h @@ -227,6 +227,7 @@ protected: void FinishUnDuckJump( trace_t &trace ); void SetDuckedEyeOffset( float duckFraction ); void FixPlayerCrouchStuck( bool moveup ); + void ResetDuckLatched(); float SplineFraction( float value, float scale ); diff --git a/game/shared/gamestats.h b/game/shared/gamestats.h new file mode 100644 index 00000000..fae1e417 --- /dev/null +++ b/game/shared/gamestats.h @@ -0,0 +1,456 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef GAMESTATS_H +#define GAMESTATS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utldict.h" +#include "tier1/utlbuffer.h" +#include "igamesystem.h" +//#include "steamworks_gamestats.h" + +const int GAMESTATS_VERSION = 1; + +enum StatSendType_t +{ + STATSEND_LEVELSHUTDOWN, + STATSEND_APPSHUTDOWN, + STATSEND_NOTENOUGHPLAYERS, +}; + +struct StatsBufferRecord_t +{ + float m_flFrameRate; // fps + float m_flServerPing; // client ping to server + +}; + +#define STATS_WINDOW_SIZE ( 60 * 10 ) // # of records to hold +#define STATS_RECORD_INTERVAL 1 // # of seconds between data grabs. 2 * 300 = every 10 minutes + +class CGameStats; + +void UpdatePerfStats( void ); +void SetGameStatsHandler( CGameStats *pGameStats ); + +class CBasePlayer; +class CPropVehicleDriveable; +class CTakeDamageInfo; + +#ifdef GAME_DLL + +#define GAMESTATS_STANDARD_NOT_SAVED 0xFEEDBEEF + +enum GameStatsVersions_t +{ + GAMESTATS_FILE_VERSION_OLD = 001, + GAMESTATS_FILE_VERSION_OLD2, + GAMESTATS_FILE_VERSION_OLD3, + GAMESTATS_FILE_VERSION_OLD4, + GAMESTATS_FILE_VERSION_OLD5, + GAMESTATS_FILE_VERSION +}; + +struct BasicGameStatsRecord_t +{ +public: + BasicGameStatsRecord_t() : + m_nCount( 0 ), + m_nSeconds( 0 ), + m_nCommentary( 0 ), + m_nHDR( 0 ), + m_nCaptions( 0 ), + m_bSteam( true ), + m_bCyberCafe( false ), + m_nDeaths( 0 ) + { + Q_memset( m_nSkill, 0, sizeof( m_nSkill ) ); + } + + void Clear(); + + void SaveToBuffer( CUtlBuffer& buf ); + bool ParseFromBuffer( CUtlBuffer& buf, int iBufferStatsVersion ); + + // Data +public: + int m_nCount; + int m_nSeconds; + + int m_nCommentary; + int m_nHDR; + int m_nCaptions; + int m_nSkill[ 3 ]; + bool m_bSteam; + bool m_bCyberCafe; + int m_nDeaths; +}; + +struct BasicGameStats_t +{ +public: + BasicGameStats_t() : + m_nSecondsToCompleteGame( 0 ), + m_nHL2ChaptureUnlocked( 0 ), + m_bSteam( true ), + m_bCyberCafe( false ), + m_nDXLevel( 0 ) + { + } + + void Clear(); + + void SaveToBuffer( CUtlBuffer& buf ); + bool ParseFromBuffer( CUtlBuffer& buf, int iBufferStatsVersion ); + + BasicGameStatsRecord_t *FindOrAddRecordForMap( char const *mapname ); + + // Data +public: + int m_nSecondsToCompleteGame; // 0 means they haven't finished playing yet + + BasicGameStatsRecord_t m_Summary; // Summary record + CUtlDict< BasicGameStatsRecord_t, unsigned short > m_MapTotals; + bool m_bSteam; + bool m_bCyberCafe; + int m_nHL2ChaptureUnlocked; + int m_nDXLevel; +}; +#endif // GAME_DLL + +class CBaseGameStats +{ +public: + CBaseGameStats(); + + // override this to declare what format you want to send. New products should use new format. + virtual bool UseOldFormat() + { +#ifdef GAME_DLL + return true; // servers by default send old format for backward compat +#else + return false; // clients never used old format so no backward compat issues, they use new format by default +#endif + } + + // Implement this if you support new format gamestats. + // Return true if you added data to KeyValues, false if you have no data to report + virtual bool AddDataForSend( KeyValues *pKV, StatSendType_t sendType ) { return false; } + + // These methods used for new format gamestats only and control when data gets sent. + virtual bool ShouldSendDataOnLevelShutdown() + { + // by default, servers send data at every level change and clients don't +#ifdef GAME_DLL + return true; +#else + return false; +#endif + } + virtual bool ShouldSendDataOnAppShutdown() + { + // by default, clients send data at app shutdown and servers don't +#ifdef GAME_DLL + return false; +#else + return true; +#endif + } + + virtual void Event_Init( void ); + virtual void Event_Shutdown( void ); + virtual void Event_MapChange( const char *szOldMapName, const char *szNewMapName ); + virtual void Event_LevelInit( void ); + virtual void Event_LevelShutdown( float flElapsed ); + virtual void Event_SaveGame( void ); + virtual void Event_LoadGame( void ); + + void CollectData( StatSendType_t sendType ); + void SendData(); + + void StatsLog( PRINTF_FORMAT_STRING char const *fmt, ... ); + + // This is the first call made, so that we can "subclass" the CBaseGameStats based on gamedir as needed (e.g., ep2 vs. episodic) + virtual CBaseGameStats *OnInit( CBaseGameStats *pCurrentGameStats, char const *gamedir ) { return pCurrentGameStats; } + + // Frees up data from gamestats and resets it to a clean state. + virtual void Clear( void ); + + virtual bool StatTrackingEnabledForMod( void ) { return false; } //Override this to turn on the system. Stat tracking is disabled by default and will always be disabled at the user's request + static bool StatTrackingAllowed( void ); //query whether stat tracking is possible and warranted by the user + virtual bool HaveValidData( void ) { return true; } // whether we currently have an interesting enough data set to upload. Called at upload time; if false, data is not uploaded. + + virtual bool ShouldTrackStandardStats( void ) { return true; } //exactly what was tracked for EP1 release + + //Get mod specific strings used for tracking, defaults should work fine for most cases + virtual const char *GetStatSaveFileName( void ); + virtual const char *GetStatUploadRegistryKeyName( void ); + const char *GetUserPseudoUniqueID( void ); + + virtual bool UserPlayedAllTheMaps( void ) { return false; } //be sure to override this to determine user completion time + +#ifdef CLIENT_DLL + virtual void Event_AchievementProgress( int achievementID, const char* achievementName ) {} +#endif + +#ifdef GAME_DLL + virtual void Event_PlayerKilled( CBasePlayer *pPlayer, const CTakeDamageInfo &info ); + virtual void Event_PlayerConnected( CBasePlayer *pBasePlayer ); + virtual void Event_PlayerDisconnected( CBasePlayer *pBasePlayer ); + virtual void Event_PlayerDamage( CBasePlayer *pBasePlayer, const CTakeDamageInfo &info ); + virtual void Event_PlayerKilledOther( CBasePlayer *pAttacker, CBaseEntity *pVictim, const CTakeDamageInfo &info ); + virtual void Event_PlayerSuicide( CBasePlayer* pPlayer ) {} + virtual void Event_Credits(); + virtual void Event_Commentary(); + virtual void Event_CrateSmashed(); + virtual void Event_Punted( CBaseEntity *pObject ); + virtual void Event_PlayerTraveled( CBasePlayer *pBasePlayer, float distanceInInches, bool bInVehicle, bool bSprinting ); + virtual void Event_WeaponFired( CBasePlayer *pShooter, bool bPrimary, char const *pchWeaponName ); + virtual void Event_WeaponHit( CBasePlayer *pShooter, bool bPrimary, char const *pchWeaponName, const CTakeDamageInfo &info ); + virtual void Event_FlippedVehicle( CBasePlayer *pDriver, CPropVehicleDriveable *pVehicle ); + virtual void Event_PreSaveGameLoaded( char const *pSaveName, bool bInGame ); + virtual void Event_PlayerEnteredGodMode( CBasePlayer *pBasePlayer ); + virtual void Event_PlayerEnteredNoClip( CBasePlayer *pBasePlayer ); + virtual void Event_DecrementPlayerEnteredNoClip( CBasePlayer *pBasePlayer ); + virtual void Event_IncrementCountedStatistic( const Vector& vecAbsOrigin, char const *pchStatisticName, float flIncrementAmount ); + + //============================================================================= + // HPE_BEGIN + // [dwenger] Functions necessary for cs-specific stats + //============================================================================= + virtual void Event_WindowShattered( CBasePlayer *pPlayer ); + //============================================================================= + // HPE_END + //============================================================================= + + //custom data to tack onto existing stats if you're not doing a complete overhaul + virtual void AppendCustomDataToSaveBuffer( CUtlBuffer &SaveBuffer ) { } //custom data you want thrown into the default save and upload path + virtual void LoadCustomDataFromBuffer( CUtlBuffer &LoadBuffer ) { }; //when loading the saved stats file, this will point to where you started saving data to the save buffer + + virtual void LoadingEvent_PlayerIDDifferentThanLoadedStats( void ); //Only called if you use the base SaveToFileNOW() and LoadFromFile() functions. Used in case you want to keep/invalidate data that was just loaded. + + virtual bool LoadFromFile( void ); //called just before Event_Init() + virtual bool SaveToFileNOW( bool bForceSyncWrite = false ); //saves buffers to their respective files now, returns success or failure + virtual bool UploadStatsFileNOW( void ); //uploads data to the CSER now, returns success or failure + + static bool AppendLump( int nMaxLumpCount, CUtlBuffer &SaveBuffer, unsigned short iLump, unsigned short iLumpCount, size_t nSize, void *pData ); + static bool GetLumpHeader( int nMaxLumpCount, CUtlBuffer &LoadBuffer, unsigned short &iLump, unsigned short &iLumpCount, bool bPermissive = false ); + static void LoadLump( CUtlBuffer &LoadBuffer, unsigned short iLumpCount, size_t nSize, void *pData ); + + //default save behavior is to save on level shutdown, and game shutdown + virtual bool AutoSave_OnInit( void ) { return false; } + virtual bool AutoSave_OnShutdown( void ) { return true; } + virtual bool AutoSave_OnMapChange( void ) { return false; } + virtual bool AutoSave_OnLevelInit( void ) { return false; } + virtual bool AutoSave_OnLevelShutdown( void ) { return true; } + + //default upload behavior is to upload on game shutdown + virtual bool AutoUpload_OnInit( void ) { return false; } + virtual bool AutoUpload_OnShutdown( void ) { return true; } + virtual bool AutoUpload_OnMapChange( void ) { return false; } + virtual bool AutoUpload_OnLevelInit( void ) { return false; } + virtual bool AutoUpload_OnLevelShutdown( void ) { return false; } + + // Helper for builtin stuff + void SetSteamStatistic( bool bUsingSteam ); + void SetCyberCafeStatistic( bool bIsCyberCafeUser ); + void SetHDRStatistic( bool bHDREnabled ); + void SetCaptionsStatistic( bool bClosedCaptionsEnabled ); + void SetSkillStatistic( int iSkillSetting ); + void SetDXLevelStatistic( int iDXLevel ); + void SetHL2UnlockedChapterStatistic( void ); +#endif // GAMEDLL +public: +#ifdef GAME_DLL + BasicGameStats_t m_BasicStats; //exposed in case you do a complete overhaul and still want to save it +#endif + bool m_bLogging : 1; + bool m_bLoggingToFile : 1; +}; + +#ifdef GAME_DLL + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &SaveBuffer - +// iLump - +// iLumpCount - +//----------------------------------------------------------------------------- +inline bool CBaseGameStats::AppendLump( int nMaxLumpCount, CUtlBuffer &SaveBuffer, unsigned short iLump, unsigned short iLumpCount, size_t nSize, void *pData ) +{ + // Verify the lump index. + Assert( ( iLump > 0 ) && ( iLump < nMaxLumpCount ) ); + + if ( !( ( iLump > 0 ) && ( iLump < nMaxLumpCount ) ) ) + return false; + + // Check to see if we have any elements to save. + if ( iLumpCount <= 0 ) + return false; + + // Write the lump id and element count. + SaveBuffer.PutUnsignedShort( iLump ); + SaveBuffer.PutUnsignedShort( iLumpCount ); + + size_t nTotalSize = iLumpCount * nSize; + SaveBuffer.Put( pData, nTotalSize ); + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &LoadBuffer - +// &iLump - +// &iLumpCount - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +inline bool CBaseGameStats::GetLumpHeader( int nMaxLumpCount, CUtlBuffer &LoadBuffer, unsigned short &iLump, unsigned short &iLumpCount, bool bPermissive /*= false*/ ) +{ + // Get the lump id and element count. + iLump = LoadBuffer.GetUnsignedShort(); + if ( !LoadBuffer.IsValid() ) + { + // check for EOF + return false; + } + iLumpCount = LoadBuffer.GetUnsignedShort(); + + if ( bPermissive ) + return true; + + // Verify the lump index. + Assert( ( iLump > 0 ) && ( iLump < nMaxLumpCount ) ); + if ( !( ( iLump > 0 ) && ( iLump < nMaxLumpCount ) ) ) + { + return false; + } + + // Check to see if we have any elements to save. + if ( iLumpCount <= 0 ) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Loads 1 or more lumps of raw data +// Input : &LoadBuffer - buffer to be read from +// iLumpCount - # of lumps to read +// nSize - size of each lump +// pData - where to store the data +//----------------------------------------------------------------------------- +inline void CBaseGameStats::LoadLump( CUtlBuffer &LoadBuffer, unsigned short iLumpCount, size_t nSize, void *pData ) +{ + LoadBuffer.Get( pData, iLumpCount * nSize ); +} + +#endif // GAME_DLL + +// Moving the extern out of the GAME_DLL block so that the client can access it +extern CBaseGameStats *gamestats; //starts out pointing at a singleton of the class above, overriding this in any constructor should work for replacing it + +//used to drive most of the game stat event handlers as well as track basic stats under the hood of CBaseGameStats +class CBaseGameStats_Driver : public CAutoGameSystemPerFrame +{ +public: + CBaseGameStats_Driver( void ); + + typedef CAutoGameSystemPerFrame BaseClass; + + // IGameSystem overloads + virtual bool Init(); + virtual void Shutdown(); + + // Level init, shutdown + virtual void LevelInitPreEntity(); + virtual void LevelShutdownPreEntity(); + virtual void LevelShutdownPreClearSteamAPIContext(); + virtual void LevelShutdown(); + // Called during game save + virtual void OnSave(); + // Called during game restore, after the local player has connected and entities have been fully restored + virtual void OnRestore(); + + virtual void FrameUpdatePostEntityThink(); + + void PossibleMapChange( void ); + + void CollectData( StatSendType_t sendType ); + void SendData(); + void ResetData(); + bool AddBaseDataForSend( KeyValues *pKV, StatSendType_t sendType ); + + StatsBufferRecord_t m_StatsBuffer[STATS_WINDOW_SIZE]; + bool m_bBufferFull; + int m_nWriteIndex; + float m_flLastRealTime; + float m_flLastSampleTime; + float m_flTotalTimeInLevels; + int m_iNumLevels; + bool m_bDidVoiceChat; // Did the player use voice chat at ALL this map? + + template T AverageStat( T StatsBufferRecord_t::*field ) const + { + T sum = 0; + for( int i = 0; i < STATS_WINDOW_SIZE; i++ ) + sum += m_StatsBuffer[i].*field; + return sum / STATS_WINDOW_SIZE; + } + + template T MaxStat( T StatsBufferRecord_t::*field ) const + { + T maxsofar = -16000000; + for( int i = 0; i < STATS_WINDOW_SIZE; i++ ) + maxsofar = MAX( maxsofar, m_StatsBuffer[i].*field ); + return maxsofar; + } + + template T MinStat( T StatsBufferRecord_t::*field ) const + { + T minsofar = 16000000; + for( int i = 0; i < STATS_WINDOW_SIZE; i++ ) + minsofar = MIN( minsofar, m_StatsBuffer[i].*field ); + return minsofar; + } + + inline void AdvanceIndex( void ) + { + m_nWriteIndex++; + if ( m_nWriteIndex == STATS_WINDOW_SIZE ) + { + m_nWriteIndex = 0; + m_bBufferFull = true; + } + } + + void UpdatePerfStats( void ); + + CUtlString m_PrevMapName; //used to track "OnMapChange" events + int m_iLoadedVersion; + char m_szLoadedUserID[ 17 ]; // GUID + + bool m_bEnabled; //false if incapable of uploading or the user doesn't want to enable stat tracking + bool m_bShuttingDown; + bool m_bInLevel; + bool m_bFirstLevel; + time_t m_tLastUpload; + + float m_flLevelStartTime; + + bool m_bStationary; + float m_flLastMovementTime; + CUserCmd m_LastUserCmd; + bool m_bGamePaused; + float m_flPauseStartTime; + + CGamestatsData *m_pGamestatsData; +}; + +#endif // GAMESTATS_H diff --git a/game/shared/hl2mp/weapon_357.cpp b/game/shared/hl2mp/weapon_357.cpp index d943f278..5dd38906 100644 --- a/game/shared/hl2mp/weapon_357.cpp +++ b/game/shared/hl2mp/weapon_357.cpp @@ -11,6 +11,7 @@ #ifdef CLIENT_DLL #include "c_hl2mp_player.h" + #include #else #include "hl2mp_player.h" #endif @@ -133,16 +134,18 @@ void CWeapon357::PrimaryAttack( void ) // Fire the bullets, and force the first shot to be perfectly accuracy pPlayer->FireBullets( info ); +#ifdef CLIENT_DLL //Disorient the player - QAngle angles = pPlayer->GetLocalAngles(); - - angles.x += random->RandomInt( -1, 1 ); - angles.y += random->RandomInt( -1, 1 ); - angles.z = 0; - -#ifndef CLIENT_DLL - pPlayer->SnapEyeAngles( angles ); -#endif + if ( prediction->IsFirstTimePredicted() ) + { + QAngle angles; + engine->GetViewAngles( angles ); + angles.x += random->RandomInt( -1, 1 ); + angles.y += random->RandomInt( -1, 1 ); + angles.z += 0.0f; + engine->SetViewAngles( angles ); + } +#endif // CLIENT_DLL pPlayer->ViewPunch( QAngle( -8, random->RandomFloat( -2, 2 ), 0 ) ); diff --git a/game/shared/particle_parse.cpp b/game/shared/particle_parse.cpp index 73cdb253..1e3abad4 100644 --- a/game/shared/particle_parse.cpp +++ b/game/shared/particle_parse.cpp @@ -186,7 +186,7 @@ void ParseParticleEffectsMap( const char *pMapName, bool bLoadSheets ) V_snprintf( szMapManifestFilename, sizeof( szMapManifestFilename ), "maps/%s_particles.txt", pMapName ); } - KeyValues *manifest = new KeyValues( szMapManifestFilename ); + KeyValuesAD manifest( szMapManifestFilename ); // In order: // - particles.txt within the map BSP diff --git a/game/shared/saverestore.cpp b/game/shared/saverestore.cpp index cc8abfcf..b78ca614 100644 --- a/game/shared/saverestore.cpp +++ b/game/shared/saverestore.cpp @@ -325,6 +325,7 @@ void CSave::Log( const char *pName, fieldtype_t fieldType, void *value, int coun char chValue = pValue[iCount]; Q_snprintf( szTempBuf, sizeof( szTempBuf ), "%c", chValue ); Q_strncat( szBuf, szTempBuf, sizeof( szTempBuf ), COPY_ALL_CHARACTERS ); + break; } case FIELD_COLOR32: { @@ -332,6 +333,7 @@ void CSave::Log( const char *pName, fieldtype_t fieldType, void *value, int coun byte *pColor = &pValue[iCount*4]; Q_snprintf( szTempBuf, sizeof( szTempBuf ), "(%d %d %d %d)", ( int )pColor[0], ( int )pColor[1], ( int )pColor[2], ( int )pColor[3] ); Q_strncat( szBuf, szTempBuf, sizeof( szTempBuf ), COPY_ALL_CHARACTERS ); + break; } case FIELD_EMBEDDED: case FIELD_CUSTOM: diff --git a/game/shared/tf/halloween/tf_weapon_spellbook.cpp b/game/shared/tf/halloween/tf_weapon_spellbook.cpp index fbfb75d5..f987d913 100644 --- a/game/shared/tf/halloween/tf_weapon_spellbook.cpp +++ b/game/shared/tf/halloween/tf_weapon_spellbook.cpp @@ -939,14 +939,14 @@ void CTFSpellBook::TossJarThink( void ) Vector vecForward, vecRight, vecUp; AngleVectors( pPlayer->EyeAngles(), &vecForward, &vecRight, &vecUp ); - float fRight = 8.f; + float fRight = 7.f; if ( IsViewModelFlipped() ) { fRight *= -1; } Vector vecSrc = pPlayer->Weapon_ShootPosition(); // Make spell toss position at the hand - vecSrc = vecSrc + (vecUp * -9.0f) + (vecRight * 7.0f) + (vecForward * 3.0f); + vecSrc = vecSrc + ( vecUp * -9.0f ) + ( vecRight * fRight ) + ( vecForward * 3.0f ); Vector vecVelocity = GetVelocityVector( vecForward, vecRight, vecUp ) * pSpellData->m_flSpeedScale; QAngle angForward = pPlayer->EyeAngles(); diff --git a/game/shared/tf/tf_dropped_weapon.cpp b/game/shared/tf/tf_dropped_weapon.cpp index 2479acbb..bc362f9f 100644 --- a/game/shared/tf/tf_dropped_weapon.cpp +++ b/game/shared/tf/tf_dropped_weapon.cpp @@ -286,6 +286,16 @@ bool CTFDroppedWeapon::OnInternalDrawModel( ClientModelRenderInfo_t *pInfo ) if ( !BaseClass::OnInternalDrawModel( pInfo ) ) return false; + // This flag says we should turn off the material overrides for attachments. + IMaterial* pMaterialOverride = NULL; + OverrideType_t nMaterialOverrideType = OVERRIDE_NORMAL; + + if ((pInfo->flags & STUDIO_NO_OVERRIDE_FOR_ATTACH) != 0) + { + modelrender->GetMaterialOverride(&pMaterialOverride, &nMaterialOverrideType); + modelrender->ForcedMaterialOverride(NULL, nMaterialOverrideType); + } + // Draw Attached Models // Draw our attached models as well for ( int i = 0; i < m_vecAttachedModels.Size(); i++ ) @@ -313,6 +323,9 @@ bool CTFDroppedWeapon::OnInternalDrawModel( ClientModelRenderInfo_t *pInfo ) } } + if (pMaterialOverride != NULL) + modelrender->ForcedMaterialOverride(pMaterialOverride, nMaterialOverrideType); + return true; } //----------------------------------------------------------------------------- diff --git a/game/shared/tf/tf_gamemovement.cpp b/game/shared/tf/tf_gamemovement.cpp index 56a36c66..47660163 100644 --- a/game/shared/tf/tf_gamemovement.cpp +++ b/game/shared/tf/tf_gamemovement.cpp @@ -53,7 +53,7 @@ ConVar tf_max_charge_speed( "tf_max_charge_speed", "750", FCVAR_NOTIFY | FCVAR_R ConVar tf_parachute_gravity( "tf_parachute_gravity", "0.2f", FCVAR_DEVELOPMENTONLY | FCVAR_REPLICATED, "Gravity while parachute is deployed" ); ConVar tf_parachute_maxspeed_xy( "tf_parachute_maxspeed_xy", "300.0f", FCVAR_DEVELOPMENTONLY | FCVAR_REPLICATED, "Max XY Speed while Parachute is deployed" ); ConVar tf_parachute_maxspeed_z( "tf_parachute_maxspeed_z", "-100.0f", FCVAR_DEVELOPMENTONLY | FCVAR_REPLICATED, "Max Z Speed while Parachute is deployed" ); -ConVar tf_parachute_maxspeed_onfire_z( "tf_parachute_maxspeed_onfire_z", "10.0f", FCVAR_DEVELOPMENTONLY | FCVAR_REPLICATED, "Max Z Speed when on Fire and Parachute is deployed" ); +ConVar tf_parachute_maxspeed_onfire_z( "tf_parachute_maxspeed_onfire_z", "-100.0f", FCVAR_DEVELOPMENTONLY | FCVAR_REPLICATED, "Max Z Speed when on Fire and Parachute is deployed" ); ConVar tf_parachute_aircontrol( "tf_parachute_aircontrol", "2.5f", FCVAR_DEVELOPMENTONLY | FCVAR_REPLICATED, "Multiplier for how much air control players have when Parachute is deployed" ); ConVar tf_parachute_deploy_toggle_allowed( "tf_parachute_deploy_toggle_allowed", "0", FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY ); @@ -1116,12 +1116,6 @@ void CTFGameMovement::PreventBunnyJumping() //----------------------------------------------------------------------------- void CTFGameMovement::ToggleParachute() { - if ( ( m_pTFPlayer->GetFlags() & FL_ONGROUND ) ) - { - m_pTFPlayer->m_Shared.RemoveCond( TF_COND_PARACHUTE_DEPLOYED ); - return; - } - if ( mv->m_nOldButtons & IN_JUMP ) return; @@ -1148,9 +1142,10 @@ void CTFGameMovement::ToggleParachute() } else { + bool bOnGround = ( m_pTFPlayer->GetFlags() & FL_ONGROUND ); int iParachuteDisabled = 0; CALL_ATTRIB_HOOK_INT_ON_OTHER( m_pTFPlayer, iParachuteDisabled, parachute_disabled ); - if ( !iParachuteDisabled && ( tf_parachute_deploy_toggle_allowed.GetBool() || !m_pTFPlayer->m_Shared.InCond( TF_COND_PARACHUTE_DEPLOYED ) ) ) + if ( !bOnGround && !iParachuteDisabled && ( tf_parachute_deploy_toggle_allowed.GetBool() || !m_pTFPlayer->m_Shared.InCond( TF_COND_PARACHUTE_DEPLOYED ) ) ) { m_pTFPlayer->m_Shared.AddCond( TF_COND_PARACHUTE_ACTIVE ); m_pTFPlayer->m_Shared.AddCond( TF_COND_PARACHUTE_DEPLOYED ); @@ -1382,7 +1377,7 @@ int CTFGameMovement::CheckStuck( void ) m_pTFPlayer->GetTeam()->GetName(), m_pTFPlayer->GetAbsOrigin().x, m_pTFPlayer->GetAbsOrigin().y, m_pTFPlayer->GetAbsOrigin().z ); - m_pTFPlayer->TakeDamage( CTakeDamageInfo( m_pTFPlayer, m_pTFPlayer, vec3_origin, m_pTFPlayer->WorldSpaceCenter(), 999999.9f, DMG_CRUSH ) ); + m_pTFPlayer->CommitSuicide( false, true ); } else { @@ -2630,8 +2625,8 @@ void CTFGameMovement::FullWalkMove() { if ( m_pTFPlayer->m_Shared.InCond( TF_COND_PARACHUTE_ACTIVE ) && mv->m_vecVelocity[2] < 0 ) { - mv->m_vecVelocity[2] = Max( mv->m_vecVelocity[2], tf_parachute_maxspeed_z.GetFloat() ); - + mv->m_vecVelocity[2] = Max( mv->m_vecVelocity[2], m_pTFPlayer->m_Shared.InCond( TF_COND_BURNING ) ? tf_parachute_maxspeed_onfire_z.GetFloat() : tf_parachute_maxspeed_z.GetFloat() ); + float flDrag = tf_parachute_maxspeed_xy.GetFloat(); // Instead of clamping, we'll dampen float flSpeedX = abs( mv->m_vecVelocity[0] ); @@ -2957,9 +2952,9 @@ void CTFGameMovement::SetGroundEntity( trace_t *pm ) { m_pTFPlayer->SpeakConceptIfAllowed( MP_CONCEPT_DOUBLE_JUMP, "started_jumping:0" ); } - m_pTFPlayer->m_Shared.SetWeaponKnockbackID( -1 ); - m_pTFPlayer->m_bScattergunJump = false; #endif // GAME_DLL + m_pTFPlayer->m_Shared.SetWeaponKnockbackID( -1 ); + m_pTFPlayer->m_Shared.m_bScattergunJump = false; m_pTFPlayer->m_Shared.SetAirDash( 0 ); m_pTFPlayer->m_Shared.SetAirDucked( 0 ); diff --git a/game/shared/tf/tf_gamerules.cpp b/game/shared/tf/tf_gamerules.cpp index 0a009162..01640475 100644 --- a/game/shared/tf/tf_gamerules.cpp +++ b/game/shared/tf/tf_gamerules.cpp @@ -417,7 +417,22 @@ static MapInfo_t s_CommunityMaps[] = { { "ctf_penguin_peak", "Penguin Peak", "#Gametype_CTF" }, { "pl_patagonia", "Patagonia", "#Gametype_Escort" }, { "plr_cutter", "Cutter", "#Gametype_EscortRace" }, - { "vsh_maul", " Maul", "#GameType_VSH" }, + { "vsh_maul", "Maul", "#GameType_VSH" }, + { "pl_citadel", "Citadel", "#Gametype_Escort" }, + { "pl_aquarius", "Aquarius", "#Gametype_Escort" }, + { "cp_fulgur", "Fulgur", "#TF_AttackDefend" }, + { "cp_cargo", "Cargo", "#TF_AttackDefend" }, + { "cp_conifer", "Conifer", "#TF_AttackDefend" }, + { "koth_boardwalk", "Boardwalk", "#Gametype_Koth" }, + { "koth_blowout", "Blowout", "#Gametype_Koth" }, + { "koth_mannhole", "Mannhole", "#Gametype_Koth" }, + { "koth_demolition", "Demolition", "#Gametype_Koth" }, + { "ctf_pressure", "Pressure", "#Gametype_CTF" }, + { "cp_cowerhouse", "Cowerhouse", "#Gametype_CP" }, + { "koth_dusker", "Dusker", "#Gametype_Koth" }, + { "arena_afterlife", "Afterlife", "#Gametype_Arena" }, + { "ctf_doublecross_event", "Devilcross", "#Gametype_CTF" }, + { "sd_marshlands", "Marshlands", "#GameType_HTF" }, }; /* @@ -597,6 +612,25 @@ static FeaturedWorkshopMap_t s_FeaturedWorkshopMaps[] = { { "pl_patagonia", 3236427113 }, { "plr_cutter", 3363801747 }, { "vsh_maul", 3069796653 }, + + // Summer 2025 + { "pl_citadel", 3474587494 }, + { "pl_aquarius", 3478583193 }, + { "cp_fulgur", 2068252300 }, + { "cp_cargo", 3488669143 }, + { "cp_conifer", 1419048064 }, + { "koth_boardwalk", 3475789229 }, + { "koth_blowout", 3473248257 }, + { "koth_mannhole", 3478225408 }, + { "koth_demolition", 3473618662 }, + { "ctf_pressure", 3480634190 }, + + // Halloween 2025 + { "cp_cowerhouse", 3028277335 }, + { "koth_dusker", 3562630084 }, + { "arena_afterlife", 3557320996 }, + { "ctf_doublecross_event", 3024700002 }, + { "sd_marshlands", 3565681202 }, }; */ @@ -705,7 +739,7 @@ ConVar tf_test_special_ducks( "tf_test_special_ducks", "1", FCVAR_DEVELOPMENTONL ConVar tf_mm_abandoned_players_per_team_max( "tf_mm_abandoned_players_per_team_max", "1", FCVAR_DEVELOPMENTONLY ); #endif // GAME_DLL -ConVar tf_mm_next_map_vote_time( "tf_mm_next_map_vote_time", "30", FCVAR_REPLICATED ); +ConVar tf_mm_next_map_vote_time( "tf_mm_next_map_vote_time", "15", FCVAR_REPLICATED ); static float g_fEternaweenAutodisableTime = 0.0f; @@ -875,6 +909,7 @@ ConVar tf_raid_allow_overtime( "tf_raid_allow_overtime", "0"/*, FCVAR_CHEAT*/ ); ConVar tf_mvm_defenders_team_size( "tf_mvm_defenders_team_size", "6", FCVAR_REPLICATED | FCVAR_NOTIFY, "Maximum number of defenders in MvM" ); ConVar tf_mvm_max_connected_players( "tf_mvm_max_connected_players", "10", FCVAR_GAMEDLL, "Maximum number of connected real players in MvM" ); +ConVar tf_mvm_max_invaders( "tf_mvm_max_invaders", "22", FCVAR_GAMEDLL, "Maximum number of invaders in MvM" ); ConVar tf_mvm_min_players_to_start( "tf_mvm_min_players_to_start", "3", FCVAR_REPLICATED | FCVAR_NOTIFY, "Minimum number of players connected to start a countdown timer" ); ConVar tf_mvm_respec_enabled( "tf_mvm_respec_enabled", "1", FCVAR_CHEAT | FCVAR_REPLICATED, "Allow players to refund credits spent on player and item upgrades." ); @@ -979,7 +1014,7 @@ static bool BIsCvarIndicatingHolidayIsActive( int iCvarValue, /*EHoliday*/ int e #ifdef GAME_DLL bool IsCustomGameMode( const char *pszMapName ) { - return ( StringHasPrefix( pszMapName, "vsh_" ) || StringHasPrefix( pszMapName, "zi_" ) ); + return ( MapHasPrefix( pszMapName, "vsh_" ) || MapHasPrefix( pszMapName, "zi_" ) ); } bool IsCustomGameMode() @@ -1106,7 +1141,13 @@ ConVar tf_competitive_required_late_join_confirm_timeout( "tf_competitive_requir ConVar tf_gamemode_community ( "tf_gamemode_community", "0", FCVAR_REPLICATED | FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY ); +ConVar tf_voice_command_suspension_mode( "tf_voice_command_suspension_mode", "2", FCVAR_REPLICATED, "0 = None | 1 = No Voice Commands | 2 = Rate Limited" ); + #ifdef GAME_DLL + +ConVar tf_voice_command_suspension_rate_limit_bucket_count( "tf_voice_command_suspension_rate_limit_bucket_count", "5" ); // Bucket size of 5. +ConVar tf_voice_command_suspension_rate_limit_bucket_refill_rate( "tf_voice_command_suspension_rate_limit_bucket_refill_rate", "6" ); // 6s + void cc_powerup_mode( IConVar *pConVar, const char *pOldString, float flOldValue ) { ConVarRef var( pConVar ); @@ -1128,11 +1169,11 @@ void cc_powerup_mode( IConVar *pConVar, const char *pOldString, float flOldValue } ConVar tf_powerup_mode( "tf_powerup_mode", "0", FCVAR_NOTIFY, "Enable/disable powerup mode. Not compatible with Mann Vs Machine mode", cc_powerup_mode ); -ConVar tf_powerup_mode_imbalance_delta( "tf_powerup_mode_imbalance_delta", "24", FCVAR_CHEAT, "Powerup kill score lead one team must have before imbalance measures are initiated" ); -ConVar tf_powerup_mode_imbalance_consecutive_min_players( "tf_powerup_mode_imbalance_consecutive_min_players", "10", FCVAR_CHEAT, "Minimum number of players on the server before consecutive imbalance measures trigger team balancing" ); -ConVar tf_powerup_mode_imbalance_consecutive_time( "tf_powerup_mode_imbalance_consecutive_time", "1200", FCVAR_CHEAT, "Teams are balanced if consecutive imbalance measures for the same team are triggered in less time (seconds)" ); -ConVar tf_powerup_mode_dominant_multiplier( "tf_powerup_mode_dominant_multiplier", "3", FCVAR_CHEAT, "The multiple by which a player must exceed the median kills by in order to be considered dominant" ); -ConVar tf_powerup_mode_killcount_timer_length( "tf_powerup_mode_killcount_timer_length", "300", FCVAR_CHEAT, "How long to wait between kill count tests that determine if a player is dominating" ); //should be a multiple of 60 because we use this to calculate an integer +ConVar tf_powerup_mode_imbalance_delta( "tf_powerup_mode_imbalance_delta", "24", FCVAR_REPLICATED, "Powerup kill score lead one team must have before imbalance measures are initiated" ); +ConVar tf_powerup_mode_imbalance_consecutive_min_players( "tf_powerup_mode_imbalance_consecutive_min_players", "10", FCVAR_REPLICATED, "Minimum number of players on the server before consecutive imbalance measures trigger team balancing" ); +ConVar tf_powerup_mode_imbalance_consecutive_time( "tf_powerup_mode_imbalance_consecutive_time", "1200", FCVAR_REPLICATED, "Teams are balanced if consecutive imbalance measures for the same team are triggered in less time (seconds)" ); +ConVar tf_powerup_mode_dominant_multiplier( "tf_powerup_mode_dominant_multiplier", "3", FCVAR_REPLICATED, "The multiple by which a player must exceed the median kills by in order to be considered dominant" ); +ConVar tf_powerup_mode_killcount_timer_length( "tf_powerup_mode_killcount_timer_length", "300", FCVAR_REPLICATED, "How long to wait between kill count tests that determine if a player is dominating" ); //should be a multiple of 60 because we use this to calculate an integer ConVar tf_skillrating_update_interval( "tf_skillrating_update_interval", "180", FCVAR_ARCHIVE, "How often to update the GC and OGS." ); @@ -3509,7 +3550,7 @@ void CTFGameRules::Precache( void ) CMerasmus::PrecacheMerasmus(); } - if ( StringHasPrefix( STRING( gpGlobals->mapname ), "mvm_" ) ) + if ( MapHasPrefix( STRING( gpGlobals->mapname ), "mvm_" ) ) { CTFPlayer::PrecacheMvM(); } @@ -4296,7 +4337,7 @@ void CTFGameRules::Activate() tf_gamemode_mvm.SetValue( 1 ); m_nGameType.Set( TF_GAMETYPE_MVM ); } - else if ( StringHasPrefix( STRING( gpGlobals->mapname ), "sd_" ) ) + else if ( MapHasPrefix( STRING( gpGlobals->mapname ), "sd_" ) ) { m_bPlayingSpecialDeliveryMode.Set( true ); tf_gamemode_sd.SetValue( 1 ); @@ -5872,7 +5913,7 @@ void CTFGameRules::RadiusDamage( const CTakeDamageInfo &info, const Vector &vecS //----------------------------------------------------------------------------- bool CTFGameRules::ApplyOnDamageModifyRules( CTakeDamageInfo &info, CBaseEntity *pVictimBaseEntity, bool bAllowDamage ) { - info.SetDamageForForceCalc( info.GetDamage() ); + if (!info.GetDamageForForceCalc()) info.SetDamageForForceCalc( info.GetDamage() ); bool bDebug = tf_debug_damage.GetBool(); CTFPlayer *pVictim = ToTFPlayer( pVictimBaseEntity ); @@ -7405,8 +7446,10 @@ float CTFGameRules::ApplyOnDamageAliveModifyRules( const CTakeDamageInfo &info, } } - if ( pAttacker == pVictimBaseEntity && (info.GetDamageType() & DMG_BLAST) && - info.GetDamagedOtherPlayers() == 0 && (info.GetDamageCustom() != TF_DMG_CUSTOM_TAUNTATK_GRENADE) ) + if ( ( pAttacker == pVictimBaseEntity ) && + ( ( info.GetDamageType() & DMG_BLAST ) || ( info.GetDamageCustom() == TF_DMG_CUSTOM_FLARE_EXPLOSION ) ) && + ( info.GetDamagedOtherPlayers() == 0 ) && + ( info.GetDamageCustom() != TF_DMG_CUSTOM_TAUNTATK_GRENADE ) ) { // If we attacked ourselves, hurt no other players, and it is a blast, // check the attribute that reduces rocket jump damage. @@ -10126,7 +10169,12 @@ VoiceCommandMenuItem_t *CTFGameRules::VoiceCommand( CBaseMultiplayerPlayer *pPla if ( pTFPlayer ) { if ( pTFPlayer->BHaveChatSuspensionInCurrentMatch() ) - return NULL; + { + if ( tf_voice_command_suspension_mode.GetInt() == 1 ) + { + return NULL; + } + } if ( pTFPlayer->m_Shared.InCond( TF_COND_HALLOWEEN_GHOST_MODE ) ) { @@ -10230,7 +10278,7 @@ void CTFGameRules::ClientSettingsChanged( CBasePlayer *pPlayer ) pTFPlayer->SetDefaultFOV( iFov ); - pTFPlayer->m_bFlipViewModels = Q_strcmp( engine->GetClientConVarValue( pPlayer->entindex(), "cl_flipviewmodels" ), "1" ) == 0; + pTFPlayer->m_bFlipViewModels = Q_atoi( engine->GetClientConVarValue( pPlayer->entindex(), "cl_flipviewmodels" ) ) > 0; } //----------------------------------------------------------------------------- @@ -12389,6 +12437,10 @@ const char *CTFGameRules::GetKillingWeaponName( const CTakeDamageInfo &info, CTF killer_weapon_name = "megaton"; } } + else if ( info.GetDamageCustom() == TF_DMG_CUSTOM_TAUNTATK_TRICKSHOT ) + { + killer_weapon_name = "tf_weapon_taunt_trickshot"; + } else if ( pScorer && pInflictor && ( pInflictor == pScorer ) ) { // If this is not a suicide @@ -16966,7 +17018,7 @@ int CTFGameRules::CalcPlayerScore( RoundStats_t *pRoundStats, CTFPlayer *pPlayer ( pRoundStats->m_iStat[TFSTAT_TELEPORTS] / TF_SCORE_TELEPORTS_PER_POINT ) + ( pRoundStats->m_iStat[TFSTAT_INVULNS] / TF_SCORE_INVULN ) + ( pRoundStats->m_iStat[TFSTAT_REVENGE] / TF_SCORE_REVENGE ) + - ( pRoundStats->m_iStat[TFSTAT_BONUS_POINTS] / TF_SCORE_BONUS_POINT_DIVISOR ); + ( pRoundStats->m_iStat[TFSTAT_BONUS_POINTS] / TF_SCORE_BONUS_POINT_DIVISOR ) + ( pRoundStats->m_iStat[TFSTAT_CURRENCY_COLLECTED] / TF_SCORE_CURRENCY_COLLECTED ); if ( pPlayer ) diff --git a/game/shared/tf/tf_gamerules.h b/game/shared/tf/tf_gamerules.h index 1394fa91..56bd58ba 100644 --- a/game/shared/tf/tf_gamerules.h +++ b/game/shared/tf/tf_gamerules.h @@ -97,6 +97,7 @@ class CMannVsMachineUpgrades; //extern ConVar tf_populator_damage_multiplier; extern ConVar tf_mvm_defenders_team_size; +extern ConVar tf_mvm_max_invaders; const int kLadder_TeamSize_6v6 = 6; const int kLadder_TeamSize_9v9 = 9; diff --git a/game/shared/tf/tf_item_constants.h b/game/shared/tf/tf_item_constants.h index 7f028bf8..98ad30a9 100644 --- a/game/shared/tf/tf_item_constants.h +++ b/game/shared/tf/tf_item_constants.h @@ -31,6 +31,7 @@ enum TF_WPN_TYPE_PRIMARY2, TF_WPN_TYPE_ITEM3, TF_WPN_TYPE_ITEM4, + TF_WPM_TYPE_PASSTIME_BALL, // diff --git a/game/shared/tf/tf_item_powerup_bottle.cpp b/game/shared/tf/tf_item_powerup_bottle.cpp index 0453cfab..9402131a 100644 --- a/game/shared/tf/tf_item_powerup_bottle.cpp +++ b/game/shared/tf/tf_item_powerup_bottle.cpp @@ -279,7 +279,7 @@ void CTFPowerupBottle::ReapplyProvision( void ) // Refill weapon clips for ( int i = 0; i < MAX_WEAPONS; i++ ) { - CBaseCombatWeapon *pWeapon = pTFPlayer->GetWeapon(i); + CTFWeaponBase *pWeapon = dynamic_cast( pTFPlayer->GetWeapon( i ) ); if ( !pWeapon ) continue; @@ -287,7 +287,8 @@ void CTFPowerupBottle::ReapplyProvision( void ) if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() ) { if ( ( pWeapon->UsesPrimaryAmmo() && !pWeapon->HasPrimaryAmmo() ) || - ( pWeapon->UsesSecondaryAmmo() && !pWeapon->HasSecondaryAmmo() ) ) + ( pWeapon->UsesSecondaryAmmo() && !pWeapon->HasSecondaryAmmo() ) || + ( pWeapon->IsEnergyWeapon() && !pWeapon->Energy_HasEnergy() ) ) { pTFPlayer->AwardAchievement( ACHIEVEMENT_TF_MVM_USE_AMMO_BOTTLE ); } @@ -297,7 +298,7 @@ void CTFPowerupBottle::ReapplyProvision( void ) if ( iShareBottle && pHealTarget ) { - CBaseCombatWeapon *pPatientWeapon = pHealTarget->GetWeapon(i); + CTFWeaponBase *pPatientWeapon = dynamic_cast( pHealTarget->GetWeapon( i ) ); if ( !pPatientWeapon ) continue; diff --git a/game/shared/tf/tf_item_schema.cpp b/game/shared/tf/tf_item_schema.cpp index 433f017f..282ce03d 100644 --- a/game/shared/tf/tf_item_schema.cpp +++ b/game/shared/tf/tf_item_schema.cpp @@ -1605,7 +1605,8 @@ const char *g_szWeaponTypeSubstrings[] = "SECONDARY2", "PRIMARY2", "ITEM3", - "ITEM4" + "ITEM4", + "PASSTIME_BALL" }; COMPILE_TIME_ASSERT( ARRAYSIZE( g_szWeaponTypeSubstrings ) == TF_WPN_TYPE_COUNT ); diff --git a/game/shared/tf/tf_item_wearable.cpp b/game/shared/tf/tf_item_wearable.cpp index db20eb12..dcf7db00 100644 --- a/game/shared/tf/tf_item_wearable.cpp +++ b/game/shared/tf/tf_item_wearable.cpp @@ -10,6 +10,7 @@ #include "tf_gamerules.h" #include "animation.h" #include "basecombatweapon_shared.h" +#include "tf_weapon_mechanical_arm.h" #ifdef CLIENT_DLL #include "c_tf_player.h" #include "model_types.h" @@ -516,6 +517,32 @@ void CTFWearable::ValidateModelIndex( void ) #endif +//----------------------------------------------------------------------------- +// Purpose: Helper to apply bodygroups from an item to a disguise target. +//----------------------------------------------------------------------------- +void CTFWearable::UpdateDisguiseBodygroups( CTFPlayer *pTFOwner, CTFPlayer *pDisguiseTarget, CEconItemView *pItem, int iTeam, int iState ) +{ + if ( !pTFOwner || !pDisguiseTarget || !pItem ) + return; + + int iDisguiseBody = pTFOwner->m_Shared.GetDisguiseBody(); + int iNumBodyGroups = pItem->GetStaticData()->GetNumModifiedBodyGroups( iTeam ); + + for ( int i = 0; i < iNumBodyGroups; ++i ) + { + int iBody = 0; + const char *pszBodyGroup = pItem->GetStaticData()->GetModifiedBodyGroup( iTeam, i, iBody ); + int iBodyGroup = pDisguiseTarget->FindBodygroupByName( pszBodyGroup ); + + if ( iBodyGroup == -1 ) + continue; + + ::SetBodygroup( pDisguiseTarget->GetModelPtr(), iDisguiseBody, iBodyGroup, iState ); + } + + pTFOwner->m_Shared.SetDisguiseBody( iDisguiseBody ); +} + //----------------------------------------------------------------------------- // Purpose: Hides or shows masked bodygroups associated with this item. //----------------------------------------------------------------------------- @@ -529,28 +556,43 @@ bool CTFWearable::UpdateBodygroups( CBaseCombatCharacter* pOwner, int iState ) if ( bBaseUpdate && m_bDisguiseWearable ) { CEconItemView *pItem = GetAttributeContainer()->GetItem(); // Safe. Checked in base class call. - CTFPlayer *pDisguiseTarget = pTFOwner->m_Shared.GetDisguiseTarget(); if ( !pDisguiseTarget ) return false; - // Update our disguise bodygroup. - int iDisguiseBody = pTFOwner->m_Shared.GetDisguiseBody(); int iTeam = pTFOwner->m_Shared.GetDisguiseTeam(); - int iNumBodyGroups = pItem->GetStaticData()->GetNumModifiedBodyGroups( iTeam ); - for ( int i=0; im_Shared.GetDisguiseWeapon(); + if ( pDisguiseWeapon ) + { + CAttributeContainer *pCont = pDisguiseWeapon->GetAttributeContainer(); + CEconItemView *pItem = pCont ? pCont->GetItem() : NULL; + CTFPlayer *pDisguiseTarget = pTFOwner->m_Shared.GetDisguiseTarget(); + + if ( pItem && pDisguiseTarget ) { - int iBody = 0; - const char *pszBodyGroup = pItem->GetStaticData()->GetModifiedBodyGroup( iTeam, i, iBody ); - int iBodyGroup = pDisguiseTarget->FindBodygroupByName( pszBodyGroup ); + // We must use team 0 for disguise weapons. + UpdateDisguiseBodygroups( pTFOwner, pDisguiseTarget, pItem, 0, iState ); - if ( iBodyGroup == -1 ) - continue; - - ::SetBodygroup( pDisguiseTarget->GetModelPtr(), iDisguiseBody, iBodyGroup, iState ); + CTFMechanicalArm* pMechArm = dynamic_cast(pDisguiseWeapon); + if (pMechArm) { + // Hack, Short circuit is special case and should be off if it is the disguise weapon. + // Directly set the bodygroup since UpdateDisguiseBodygroups doesn't work for this weapon + int iDisguiseBody = pTFOwner->m_Shared.GetDisguiseBody(); + int iBodyGroup = pDisguiseTarget->FindBodygroupByName("rightarm"); + if (iBodyGroup != -1) + { + ::SetBodygroup(pDisguiseTarget->GetModelPtr(), iDisguiseBody, iBodyGroup, 2); + pTFOwner->m_Shared.SetDisguiseBody(iDisguiseBody); + } + } } - - pTFOwner->m_Shared.SetDisguiseBody( iDisguiseBody ); } CEconItemView *pItem = GetAttributeContainer() ? GetAttributeContainer()->GetItem() : NULL; diff --git a/game/shared/tf/tf_item_wearable.h b/game/shared/tf/tf_item_wearable.h index f89c0c95..d5efa156 100644 --- a/game/shared/tf/tf_item_wearable.h +++ b/game/shared/tf/tf_item_wearable.h @@ -18,6 +18,10 @@ #if defined( CLIENT_DLL ) #define CTFWearable C_TFWearable #define CTFWearableVM C_TFWearableVM +class C_TFPlayer; +#define CTFPlayer C_TFPlayer +#else +class CTFPlayer; #endif @@ -74,8 +78,8 @@ public: protected: virtual void InternalSetPlayerDisplayModel( void ); - private: + void UpdateDisguiseBodygroups( CTFPlayer *pTFOwner, CTFPlayer *pDisguiseTarget, CEconItemView *pItem, int iTeam, int iState ); CNetworkVar( bool, m_bDisguiseWearable ); CNetworkHandle( CBaseEntity, m_hWeaponAssociatedWith ); diff --git a/game/shared/tf/tf_player_shared.cpp b/game/shared/tf/tf_player_shared.cpp index 4da5c3df..42d0b829 100644 --- a/game/shared/tf/tf_player_shared.cpp +++ b/game/shared/tf/tf_player_shared.cpp @@ -31,10 +31,12 @@ #include "tf_mapinfo.h" #include "tf_dropped_weapon.h" #include "tf_weapon_passtime_gun.h" +#include "tf_weapon_rocketpack.h" #include // Client specific. #ifdef CLIENT_DLL +#include "c_baseviewmodel.h" #include "c_tf_player.h" #include "c_te_effect_dispatch.h" #include "c_tf_fx.h" @@ -454,6 +456,8 @@ BEGIN_PREDICTION_DATA_NO_BASE( CTFPlayerShared ) DEFINE_PRED_FIELD( m_nAirDucked, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), DEFINE_PRED_FIELD( m_flDuckTimer, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), DEFINE_PRED_FIELD( m_flInvisChangeCompleteTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_flLastStealthExposeTime, FIELD_FLOAT, 0 ), + DEFINE_PRED_FIELD( m_flStealthNextChangeTime, FIELD_INTEGER, 0 ), DEFINE_PRED_FIELD( m_nDisguiseTeam, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), DEFINE_PRED_FIELD( m_nDisguiseClass, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), DEFINE_PRED_FIELD( m_nDisguiseSkinOverride, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), @@ -471,7 +475,10 @@ BEGIN_PREDICTION_DATA_NO_BASE( CTFPlayerShared ) DEFINE_PRED_FIELD( m_bHasPasstimeBall, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), DEFINE_PRED_FIELD( m_bIsTargetedForPasstimePass, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), // does this belong here? DEFINE_PRED_FIELD( m_askForBallTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_flHolsterAnimTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), DEFINE_PRED_ARRAY( m_flItemChargeMeter, FIELD_FLOAT, LAST_LOADOUT_SLOT_WITH_CHARGE_METER, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_iStunIndex, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_bScattergunJump, FIELD_BOOLEAN, 0 ), END_PREDICTION_DATA() // Server specific. @@ -784,6 +791,8 @@ CTFPlayerShared::CTFPlayerShared() m_flPrevInvisibility = 0.f; m_flTmpDamageBonusAmount = 1.0f; + m_bScattergunJump = false; + m_bFeignDeathReady = false; m_fCloakConsumeRate = tf_spy_cloak_consume_rate.GetFloat(); @@ -1005,7 +1014,6 @@ void CTFPlayerShared::Spawn( void ) SetRevengeCrits( 0 ); m_PlayerStuns.RemoveAll(); - m_iStunIndex = -1; m_iPasstimeThrowAnimState = PASSTIME_THROW_ANIM_NONE; m_bHasPasstimeBall = false; @@ -1014,6 +1022,7 @@ void CTFPlayerShared::Spawn( void ) #else m_bSyncingConditions = false; #endif + m_iStunIndex = -1; m_bKingRuneBuffActive = false; // Reset our assist here incase something happens before we get killed @@ -1024,46 +1033,55 @@ void CTFPlayerShared::Spawn( void ) //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -template < typename tIntType > +template < typename tType > class CConditionVars { public: - CConditionVars( tIntType& nPlayerCond, tIntType& nPlayerCondEx, tIntType& nPlayerCondEx2, tIntType& nPlayerCondEx3, tIntType& nPlayerCondEx4, ETFCond eCond ) + template < typename t0, typename t1, typename t2, typename t3, typename t4 > + CConditionVars( CTFPlayer* pOuter, ETFCond eCond, t0& nPlayerCond, t1& nPlayerCondEx, t2& nPlayerCondEx2, t3& nPlayerCondEx3, t4& nPlayerCondEx4 ) { + m_pOuter = pOuter; + if ( eCond >= 128 ) { Assert( eCond < 128 + 32 ); - m_pnCondVar = &nPlayerCondEx4; - m_nCondBit = eCond - 128; + m_pnCondVar = ( tType* )&nPlayerCondEx4; + m_nCondBit = eCond - 128; } else if ( eCond >= 96 ) { Assert( eCond < 96 + 32 ); - m_pnCondVar = &nPlayerCondEx3; + m_pnCondVar = ( tType* )&nPlayerCondEx3; m_nCondBit = eCond - 96; } - else if( eCond >= 64 ) + else if ( eCond >= 64 ) { - Assert( eCond < (64 + 32) ); - m_pnCondVar = &nPlayerCondEx2; + Assert( eCond < ( 64 + 32 ) ); + m_pnCondVar = ( tType* )&nPlayerCondEx2; m_nCondBit = eCond - 64; } else if ( eCond >= 32 ) { - Assert( eCond < (32 + 32) ); - m_pnCondVar = &nPlayerCondEx; + Assert( eCond < ( 32 + 32 ) ); + m_pnCondVar = ( tType* )&nPlayerCondEx; m_nCondBit = eCond - 32; } else { - m_pnCondVar = &nPlayerCond; + m_pnCondVar = ( tType* )&nPlayerCond; m_nCondBit = eCond; } } - tIntType& CondVar() const + const int& CondVar() const { - return *m_pnCondVar; + return m_pnCondVar->m_Value; + } + + int& CondVarForModify() + { + m_pOuter->NetworkStateChanged( m_pnCondVar ); + return m_pnCondVar->m_Value; } int CondBit() const @@ -1072,10 +1090,14 @@ public: } private: - tIntType *m_pnCondVar; + CTFPlayer* m_pOuter; + tType* m_pnCondVar; int m_nCondBit; }; +#define CONDITION_VARS( name, cond ) \ +CConditionVars< decltype( m_nPlayerCond ) > name( m_pOuter, cond, m_nPlayerCond, m_nPlayerCondEx, m_nPlayerCondEx2, m_nPlayerCondEx3, m_nPlayerCondEx4 ) + //----------------------------------------------------------------------------- // Purpose: Add a condition and duration // duration of PERMANENT_CONDITION means infinite duration @@ -1107,14 +1129,14 @@ void CTFPlayerShared::AddCond( ETFCond eCond, float flDuration /* = PERMANENT_CO // Which bitfield are we tracking this condition variable in? Which bit within // that variable will we track it as? - CConditionVars cPlayerCond( m_nPlayerCond.m_Value, m_nPlayerCondEx.m_Value, m_nPlayerCondEx2.m_Value, m_nPlayerCondEx3.m_Value, m_nPlayerCondEx4.m_Value, eCond ); + CONDITION_VARS( cPlayerCond, eCond ); // See if there is an object representation of the condition. bool bAddedToExternalConditionList = m_ConditionList.Add( eCond, flDuration, m_pOuter, pProvider ); if ( !bAddedToExternalConditionList ) { // Set the condition bit for this condition. - cPlayerCond.CondVar() |= cPlayerCond.CondBit(); + cPlayerCond.CondVarForModify() |= cPlayerCond.CondBit(); // Flag for gamecode to query m_ConditionData[eCond].m_bPrevActive = ( m_ConditionData[eCond].m_flExpireTime != 0.f ) ? true : false; @@ -1149,14 +1171,14 @@ void CTFPlayerShared::RemoveCond( ETFCond eCond, bool ignore_duration ) if ( !InCond( eCond ) ) return; - CConditionVars cPlayerCond( m_nPlayerCond.m_Value, m_nPlayerCondEx.m_Value, m_nPlayerCondEx2.m_Value, m_nPlayerCondEx3.m_Value, m_nPlayerCondEx4.m_Value, eCond ); + CONDITION_VARS( cPlayerCond, eCond ); // If this variable is handled by the condition list, abort before doing the // work for the condition flags. if ( m_ConditionList.Remove( eCond, ignore_duration ) ) return; - cPlayerCond.CondVar() &= ~cPlayerCond.CondBit(); + cPlayerCond.CondVarForModify() &= ~cPlayerCond.CondBit(); OnConditionRemoved( eCond ); if ( m_ConditionData[ eCond ].m_nPreventedDamageFromCondition ) @@ -1192,7 +1214,7 @@ bool CTFPlayerShared::InCond( ETFCond eCond ) const if ( eCond < 32 && m_ConditionList.InCond( eCond ) ) return true; - CConditionVars cPlayerCond( m_nPlayerCond.m_Value, m_nPlayerCondEx.m_Value, m_nPlayerCondEx2.m_Value, m_nPlayerCondEx3.m_Value, m_nPlayerCondEx4.m_Value, eCond ); + CONDITION_VARS( cPlayerCond, eCond ); return (cPlayerCond.CondVar() & cPlayerCond.CondBit()) != 0; } @@ -1206,7 +1228,7 @@ bool CTFPlayerShared::WasInCond( ETFCond eCond ) const // assert. And this comment). Assert( eCond >= 32 && eCond < TF_COND_LAST ); - CConditionVars cPlayerCond( m_nOldConditions, m_nOldConditionsEx, m_nOldConditionsEx2, m_nOldConditionsEx3, m_nOldConditionsEx4, eCond ); + CONDITION_VARS( cPlayerCond, eCond ); return (cPlayerCond.CondVar() & cPlayerCond.CondBit()) != 0; } @@ -1219,8 +1241,8 @@ void CTFPlayerShared::ForceRecondNextSync( ETFCond eCond ) // Please check if you hit the assert. (And then remove the assert. And this comment). Assert(eCond >= 32 && eCond < TF_COND_LAST); - CConditionVars playerCond( m_nForceConditions, m_nForceConditionsEx, m_nForceConditionsEx2, m_nForceConditionsEx3, m_nForceConditionsEx4, eCond ); - playerCond.CondVar() |= playerCond.CondBit(); + CONDITION_VARS( cPlayerCond, eCond ); + cPlayerCond.CondVarForModify() |= cPlayerCond.CondBit(); } //----------------------------------------------------------------------------- @@ -1401,7 +1423,11 @@ void CTFPlayerShared::OnPreDataChanged( void ) m_nOldDisguiseTeam = GetDisguiseTeam(); m_iOldMovementStunParity = m_iMovementStunParity; - SharedThink(); + // Local player will run this in PreThink + if ( !prediction->InPrediction() ) + { + SharedThink(); + } } //----------------------------------------------------------------------------- @@ -1453,6 +1479,7 @@ void CTFPlayerShared::OnDataChanged( void ) { m_hDisguiseWeapon->UpdateVisibility(); m_hDisguiseWeapon->UpdateParticleSystems(); + m_hDisguiseWeapon->UpdateAttachmentModels(); } // XXX(JohnS): This is not the right place to do these things, SetWeaponVisible on the *client* is just stomping @@ -1464,7 +1491,11 @@ void CTFPlayerShared::OnDataChanged( void ) GetActiveTFWeapon()->SetWeaponVisible( false ); } - InvisibilityThink(); + // Local player will run this in PreThink + if ( !prediction->InPrediction() ) + { + InvisibilityThink(); + } } //----------------------------------------------------------------------------- @@ -3090,9 +3121,46 @@ void CTFPlayerShared::ConditionThink( void ) VehicleThink(); - if ( m_pOuter->GetFlags() & FL_ONGROUND && InCond( TF_COND_PARACHUTE_ACTIVE ) ) + if ( m_pOuter->GetFlags() & FL_ONGROUND ) { + // Airborne conditions end on ground contact + RemoveCond( TF_COND_KNOCKED_INTO_AIR ); + RemoveCond( TF_COND_AIR_CURRENT ); + RemoveCond( TF_COND_PARACHUTE_ACTIVE ); + RemoveCond( TF_COND_PARACHUTE_DEPLOYED ); + + if ( InCond( TF_COND_ROCKETPACK ) ) + { + // Make sure we're still not dealing with launch, where it's possible + // to hit your head and fall to the ground before the second stage. + CTFWeaponBase *pRocketPack = m_pOuter->Weapon_OwnsThisID( TF_WEAPON_ROCKETPACK ); + if ( pRocketPack ) + { + if ( gpGlobals->curtime > ( static_cast< CTFRocketPack* >( pRocketPack )->GetRefireTime() ) ) + { +#ifdef CLIENT_DLL + if ( prediction->IsFirstTimePredicted() ) +#endif + { + CPASAttenuationFilter filter( m_pOuter ); + filter.UsePredictionRules(); + m_pOuter->EmitSound( filter, m_pOuter->entindex(), "Weapon_RocketPack.BoostersShutdown" ); + m_pOuter->EmitSound( filter, m_pOuter->entindex(), "Weapon_RocketPack.Land" ); + } + RemoveCond( TF_COND_ROCKETPACK ); + +#ifdef GAME_DLL + IGameEvent *pEvent = gameeventmanager->CreateEvent( "rocketpack_landed" ); + if ( pEvent ) + { + pEvent->SetInt( "userid", m_pOuter->GetUserID() ); + gameeventmanager->FireEvent( pEvent ); + } +#endif + } + } + } } // See if we should be pulsing our radius heal @@ -4725,14 +4793,8 @@ static void RemoveResistParticle( CTFPlayer* pPlayer, medigun_resist_types_t nRe if ( bKeep ) return; - if ( pPlayer->m_Shared.GetDisplayedTeam() == TF_TEAM_RED ) - { - pPlayer->RemoveOverheadEffect( s_pszRedResistOverheadEffectName[ nResistType ], true ); - } - else - { - pPlayer->RemoveOverheadEffect( s_pszBlueResistOverheadEffectName[ nResistType ], true ); - } + pPlayer->RemoveOverheadEffect( s_pszRedResistOverheadEffectName[ nResistType ], true ); + pPlayer->RemoveOverheadEffect( s_pszBlueResistOverheadEffectName[ nResistType ], true ); } //----------------------------------------------------------------------------- @@ -6890,19 +6952,23 @@ void CTFPlayerShared::OnRemoveTmpDamageBonus( void ) void CTFPlayerShared::OnAddStealthed( void ) { #ifdef CLIENT_DLL - if ( m_pOuter->GetPredictable() && ( !prediction->IsFirstTimePredicted() || m_bSyncingConditions ) ) - return; + // Local player wants to predict the offhand weapon, but not the fancy effects multiple times! + // Other players always run everything + bool bFirstPrediction = !m_pOuter->GetPredictable() || ( prediction->IsFirstTimePredicted() && !m_bSyncingConditions ); - if ( !InCond( TF_COND_FEIGN_DEATH ) ) + if ( bFirstPrediction ) { - m_pOuter->EmitSound( "Player.Spy_Cloak" ); - } - m_pOuter->RemoveAllDecals(); - UpdateCritBoostEffect(); + if ( !InCond( TF_COND_FEIGN_DEATH ) ) + { + m_pOuter->EmitSound( "Player.Spy_Cloak" ); + } + m_pOuter->RemoveAllDecals(); + UpdateCritBoostEffect(); - if ( m_pOuter->m_pTempShield && GetCarryingRuneType() == RUNE_RESIST ) - { - RemoveResistShield( &m_pOuter->m_pTempShield, m_pOuter ); + if ( m_pOuter->m_pTempShield && GetCarryingRuneType() == RUNE_RESIST ) + { + RemoveResistShield( &m_pOuter->m_pTempShield, m_pOuter ); + } } #endif @@ -6914,7 +6980,7 @@ void CTFPlayerShared::OnAddStealthed( void ) bSetInvisChangeTime = false; } - if ( InCond( TF_COND_STEALTHED_USER_BUFF ) && m_pOuter->IsLocalPlayer() ) + if ( bFirstPrediction && InCond( TF_COND_STEALTHED_USER_BUFF ) && m_pOuter->IsLocalPlayer() ) { IMaterial *pMaterial = materials->FindMaterial( TF_SCREEN_OVERLAY_MATERIAL_STEALTH, TEXTURE_GROUP_CLIENT_EFFECTS, false ); if ( !IsErrorMaterial( pMaterial ) ) @@ -6961,11 +7027,14 @@ void CTFPlayerShared::OnAddStealthed( void ) m_pOuter->TeamFortress_SetSpeed(); #ifdef CLIENT_DLL - // Remove water balloon effect if it on player - m_pOuter->ParticleProp()->StopParticlesNamed( "balloontoss_drip", true ); + if ( bFirstPrediction ) + { + // Remove water balloon effect if it on player + m_pOuter->ParticleProp()->StopParticlesNamed( "balloontoss_drip", true ); - m_pOuter->UpdateSpyStateChange(); - m_pOuter->UpdateKillStreakEffects( GetStreak( kTFStreak_Kills ) ); + m_pOuter->UpdateSpyStateChange(); + m_pOuter->UpdateKillStreakEffects( GetStreak( kTFStreak_Kills ) ); + } #endif #ifdef GAME_DLL @@ -6979,39 +7048,43 @@ void CTFPlayerShared::OnAddStealthed( void ) void CTFPlayerShared::OnRemoveStealthed( void ) { #ifdef CLIENT_DLL - if ( !m_bSyncingConditions ) - return; + // Local player wants to predict the offhand weapon, but not the fancy effects multiple times! + // Other players always run everything + bool bFirstPrediction = !m_pOuter->GetPredictable() || ( prediction->IsFirstTimePredicted() && !m_bSyncingConditions ); - CTFWeaponInvis *pWpn = (CTFWeaponInvis *) m_pOuter->Weapon_OwnsThisID( TF_WEAPON_INVIS ); + if ( bFirstPrediction ) + { + CTFWeaponInvis* pWpn = (CTFWeaponInvis*)m_pOuter->Weapon_OwnsThisID( TF_WEAPON_INVIS ); - int iReducedCloak = 0; - CALL_ATTRIB_HOOK_INT_ON_OTHER( m_pOuter, iReducedCloak, set_quiet_unstealth ); - if ( iReducedCloak == 1 ) - { - m_pOuter->EmitSound( "Player.Spy_UnCloakReduced" ); - } - else if ( pWpn && pWpn->HasFeignDeath() ) - { - m_pOuter->EmitSound( "Player.Spy_UnCloakFeignDeath" ); - } - else - { - m_pOuter->EmitSound( "Player.Spy_UnCloak" ); - } - UpdateCritBoostEffect( kCritBoost_ForceRefresh ); - - if ( m_pOuter->IsLocalPlayer() && !InCond( TF_COND_STEALTHED_USER_BUFF_FADING ) ) - { - IMaterial *pMaterial = view->GetScreenOverlayMaterial(); - if ( pMaterial && FStrEq( pMaterial->GetName(), TF_SCREEN_OVERLAY_MATERIAL_STEALTH ) ) + int iReducedCloak = 0; + CALL_ATTRIB_HOOK_INT_ON_OTHER( m_pOuter, iReducedCloak, set_quiet_unstealth ); + if ( iReducedCloak == 1 ) { - view->SetScreenOverlayMaterial( NULL ); + m_pOuter->EmitSound( "Player.Spy_UnCloakReduced" ); } - } + else if ( pWpn && pWpn->HasFeignDeath() ) + { + m_pOuter->EmitSound( "Player.Spy_UnCloakFeignDeath" ); + } + else + { + m_pOuter->EmitSound( "Player.Spy_UnCloak" ); + } + UpdateCritBoostEffect( kCritBoost_ForceRefresh ); - if ( !m_pOuter->m_pTempShield && GetCarryingRuneType() == RUNE_RESIST ) - { - AddResistShield( &m_pOuter->m_pTempShield, m_pOuter, TF_COND_RUNE_RESIST ); + if ( m_pOuter->IsLocalPlayer() && !InCond( TF_COND_STEALTHED_USER_BUFF_FADING ) ) + { + IMaterial* pMaterial = view->GetScreenOverlayMaterial(); + if ( pMaterial && FStrEq( pMaterial->GetName(), TF_SCREEN_OVERLAY_MATERIAL_STEALTH ) ) + { + view->SetScreenOverlayMaterial( NULL ); + } + } + + if ( !m_pOuter->m_pTempShield && GetCarryingRuneType() == RUNE_RESIST ) + { + AddResistShield( &m_pOuter->m_pTempShield, m_pOuter, TF_COND_RUNE_RESIST ); + } } #else if ( m_flCloakStartTime > 0 ) @@ -7045,8 +7118,11 @@ void CTFPlayerShared::OnRemoveStealthed( void ) m_bMotionCloak = false; #ifdef CLIENT_DLL - m_pOuter->UpdateSpyStateChange(); - m_pOuter->UpdateKillStreakEffects( GetStreak( kTFStreak_Kills ) ); + if ( bFirstPrediction ) + { + m_pOuter->UpdateSpyStateChange(); + m_pOuter->UpdateKillStreakEffects( GetStreak( kTFStreak_Kills ) ); + } #endif } @@ -7154,6 +7230,8 @@ void CTFPlayerShared::OnRemoveDisguising( void ) void CTFPlayerShared::OnRemoveDisguised( void ) { #ifdef CLIENT_DLL + // Save the disguise target before clearing it, so we can mark bodygroups dirty. + CTFPlayer *pOldDisguiseTarget = ToTFPlayer( m_hDisguiseTarget.Get() ); if ( m_pOuter->GetPredictable() && ( !prediction->IsFirstTimePredicted() || m_bSyncingConditions ) ) return; @@ -7178,7 +7256,14 @@ void CTFPlayerShared::OnRemoveDisguised( void ) UpdateCritBoostEffect( kCritBoost_ForceRefresh ); m_pOuter->UpdateSpyStateChange(); + // Mark the old disguise target's bodygroups as dirty so they'll be recalculated. + if ( pOldDisguiseTarget ) + { + pOldDisguiseTarget->SetBodygroupsDirty(); + } + #else + m_nDisguiseTeam = TF_SPY_UNDEFINED; m_nDisguiseClass.Set( TF_CLASS_UNDEFINED ); m_nDisguiseSkinOverride = 0; @@ -7301,6 +7386,8 @@ void CTFPlayerShared::OnRemoveStunned( void ) m_iStunFlags = 0; m_hStunner = NULL; + m_iStunIndex = -1; + #ifdef CLIENT_DLL if ( m_pOuter->m_pStunnedEffect ) { @@ -7310,7 +7397,6 @@ void CTFPlayerShared::OnRemoveStunned( void ) m_pOuter->m_pStunnedEffect = NULL; } #else - m_iStunIndex = -1; m_PlayerStuns.RemoveAll(); #endif @@ -8147,6 +8233,15 @@ void CTFPlayerShared::Disguise( int nTeam, int nClass, CTFPlayer* pDesiredTarget } } +#ifdef CLIENT_DLL + // Save the old disguise target before changing disguise, so we can clean up bodygroups. + CTFPlayer *pOldDisguiseTarget = ToTFPlayer( m_hDisguiseTarget.Get() ); + if ( pOldDisguiseTarget ) + { + pOldDisguiseTarget->SetBodygroupsDirty(); + } +#endif + m_hDesiredDisguiseTarget.Set( pDesiredTarget ); m_nDesiredDisguiseClass = nClass; m_nDesiredDisguiseTeam = nTeam; @@ -8326,6 +8421,7 @@ void CTFPlayerShared::DetermineDisguiseWeapon( bool bForcePrimary ) { CTFWeaponBase *pLastDisguiseWeapon = m_hDisguiseWeapon; CTFWeaponBase *pFirstValidWeapon = NULL; + // Cycle through the target's weapons and see if we have a match. // Note that it's possible the disguise target doesn't have a weapon in the slot we want, // for example if they have replaced it with an unlockable that isn't a weapon (wearable). @@ -8429,6 +8525,7 @@ void CTFPlayerShared::DetermineDisguiseWeapon( bool bForcePrimary ) m_hDisguiseWeapon->m_bDisguiseWeapon = true; m_hDisguiseWeapon->SetContextThink( &CTFWeaponBase::DisguiseWeaponThink, gpGlobals->curtime + 0.5, "DisguiseWeaponThink" ); + m_hDisguiseWeapon->UpdateExtraWearables(); // Ammo/clip state is displayed to attached medics m_iDisguiseAmmo = 0; @@ -8463,14 +8560,31 @@ void CTFPlayerShared::DetermineDisguiseWeapon( bool bForcePrimary ) void CTFPlayerShared::DetermineDisguiseWearables() { CTFPlayer *pDisguiseTarget = ToTFPlayer( m_hDisguiseTarget.Get() ); - if ( !pDisguiseTarget ) - return; // Remove any existing disguise wearables. RemoveDisguiseWearables(); - if ( GetDisguiseClass() != pDisguiseTarget->GetPlayerClass()->GetClassIndex() ) + if ( !pDisguiseTarget ) + { + // No target exists, reset disguise body to default state. + SetDisguiseBody( 0 ); return; + } + + if ( GetDisguiseClass() != pDisguiseTarget->GetPlayerClass()->GetClassIndex() ) + { + // Class mismatch, reset disguise body to default. + SetDisguiseBody( 0 ); +#ifdef CLIENT_DLL + // Mark bodygroups dirty even when not copying wearables (class mismatch). + pDisguiseTarget->SetBodygroupsDirty(); +#endif + return; + } + + // Reset disguise body to default before applying new wearables. + // This ensures old bodygroup modifications don't carry over. + SetDisguiseBody( 0 ); // Equip us with copies of our disguise target's wearables. int iPlayerSkinOverride = 0; @@ -8516,6 +8630,11 @@ void CTFPlayerShared::DetermineDisguiseWearables() } m_nDisguiseSkinOverride = iPlayerSkinOverride; + +#ifdef CLIENT_DLL + // Mark bodygroups dirty after creating disguise wearables. + pDisguiseTarget->SetBodygroupsDirty(); +#endif } void CTFPlayerShared::RemoveDisguiseWearables() @@ -9624,15 +9743,16 @@ bool CTFPlayerShared::AddToSpyCloakMeter( float val, bool bForce ) #endif -#ifdef GAME_DLL //----------------------------------------------------------------------------- // Purpose: Stun & Snare Application //----------------------------------------------------------------------------- void CTFPlayerShared::StunPlayer( float flTime, float flReductionAmount, int iStunFlags, CTFPlayer* pAttacker ) { +#ifdef GAME_DLL // Insanity prevention if ( ( m_PlayerStuns.Count() + 1 ) >= 250 ) return; +#endif if ( InCond( TF_COND_PHASE ) || InCond( TF_COND_PASSTIME_INTERCEPTION ) ) return; @@ -9643,15 +9763,19 @@ void CTFPlayerShared::StunPlayer( float flTime, float flReductionAmount, int iSt if ( InCond( TF_COND_INVULNERABLE_HIDE_UNLESS_DAMAGED ) && !InCond( TF_COND_MVM_BOT_STUN_RADIOWAVE ) ) return; +#ifdef GAME_DLL if ( pAttacker && TFGameRules() && TFGameRules()->IsTruceActive() && pAttacker->IsTruceValidForEnt() ) { if ( ( pAttacker->GetTeamNumber() == TF_TEAM_RED ) || ( pAttacker->GetTeamNumber() == TF_TEAM_BLUE ) ) return; } +#endif float flRemapAmount = RemapValClamped( flReductionAmount, 0.0, 1.0, 0, 255 ); +#ifdef GAME_DLL int iOldStunFlags = GetStunFlags(); +#endif // Already stunned bool bStomp = false; @@ -9674,10 +9798,13 @@ void CTFPlayerShared::StunPlayer( float flTime, float flReductionAmount, int iSt } else if ( GetActiveStunInfo() ) { +#ifdef GAME_DLL // Something yanked our TF_COND_STUNNED in an unexpected way if ( !HushAsserts() ) Assert( !"Something yanked out TF_COND_STUNNED." ); m_PlayerStuns.RemoveAll(); +#endif + m_iStunIndex = -1; return; } @@ -9699,7 +9826,16 @@ void CTFPlayerShared::StunPlayer( float flTime, float flReductionAmount, int iSt // This can happen when stuns use TF_STUN_CONTROLS or TF_STUN_LOSER_STATE. float flOldStun = GetActiveStunInfo() ? GetActiveStunInfo()->flStunAmount : 0.f; +#ifdef GAME_DLL m_iStunIndex = m_PlayerStuns.AddToTail( stunEvent ); +#else + m_iStunIndex = 0; + + if ( prediction->IsFirstTimePredicted() ) + { + m_ActiveStunInfo = stunEvent; + } +#endif if ( flOldStun > flRemapAmount ) { @@ -9709,10 +9845,18 @@ void CTFPlayerShared::StunPlayer( float flTime, float flReductionAmount, int iSt else { // Done for now +#ifdef GAME_DLL m_PlayerStuns.AddToTail( stunEvent ); +#else + if ( prediction->IsFirstTimePredicted() ) + { + m_ActiveStunInfo = stunEvent; + } +#endif return; } +#ifdef GAME_DLL // Add in extra time when TF_STUN_CONTROLS if ( GetActiveStunInfo()->iStunFlags & TF_STUN_CONTROLS ) { @@ -9766,10 +9910,10 @@ void CTFPlayerShared::StunPlayer( float flTime, float flReductionAmount, int iSt m_pOuter->ClearExpression(); m_pOuter->ClearWeaponFireScene(); } +#endif AddCond( TF_COND_STUNNED, -1.f, pAttacker ); } -#endif // GAME_DLL //----------------------------------------------------------------------------- // Purpose: Returns the intensity of the current stun effect, if we have the type of stun indicated. @@ -9986,6 +10130,14 @@ void CTFPlayer::GetHorriblyHackedRailgunPosition( const Vector& vStart, Vector * Vector vForward, vRight, vUp; AngleVectors( EyeAngles(), &vForward, &vRight, &vUp ); +#ifdef CLIENT_DLL + // Flips the horizontal position. + if ( TeamFortress_ShouldFlipClientViewModel() ) + { + vRight *= -1; + } +#endif // CLIENT_DLL + *out_pvStartPos = vStart + (vForward * 60.9f) + (vRight * 13.1f) @@ -12110,6 +12262,13 @@ bool CTFPlayer::CanJump() const if ( m_Shared.InCond( TF_COND_TAUNTING ) ) return false; + CTFWeaponBase *pActiveWeapon = m_Shared.GetActiveTFWeapon(); + if ( pActiveWeapon ) + { + if ( !pActiveWeapon->OwnerCanJump() ) + return false; + } + int iNoJump = 0; CALL_ATTRIB_HOOK_INT( iNoJump, no_jump ); @@ -12263,6 +12422,9 @@ bool CTFPlayer::CanPickupBuilding( CBaseObject *pPickupObject ) if ( pPickupObject->GetUpgradeLevel() != pPickupObject->GetHighestUpgradeLevel() ) return false; + if ( !IsAlive() ) + return false; + if ( m_Shared.IsCarryingObject() ) return false; @@ -12644,6 +12806,16 @@ bool CTFPlayer::Weapon_CanSwitchTo( CBaseCombatWeapon *pWeapon ) return bCanSwitch; } +void CTFPlayer::PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool force ) +{ +#ifdef CLIENT_DLL + // Don't make predicted footstep sounds in third person, animevents will take care of that. + if ( prediction->InPrediction() && C_BasePlayer::ShouldDrawLocalPlayer() ) + return; +#endif + + BaseClass::PlayStepSound( vecOrigin, psurface, fvol, force ); +} //----------------------------------------------------------------------------- // Purpose: Gives the player an opportunity to abort a double jump. diff --git a/game/shared/tf/tf_player_shared.h b/game/shared/tf/tf_player_shared.h index a4cbfca1..fdaef921 100644 --- a/game/shared/tf/tf_player_shared.h +++ b/game/shared/tf/tf_player_shared.h @@ -560,9 +560,7 @@ public: // Stuns stun_struct_t *GetActiveStunInfo( void ) const; -#ifdef GAME_DLL void StunPlayer( float flTime, float flReductionAmount, int iStunFlags = TF_STUN_MOVEMENT, CTFPlayer* pAttacker = NULL ); -#endif // GAME_DLL float GetAmountStunned( int iStunFlags ); bool IsLoserStateStunned( void ) const; bool IsControlStunned( void ); @@ -1218,6 +1216,8 @@ private: #endif public: + bool m_bScattergunJump; + float m_flStunFade; float m_flStunEnd; float m_flStunMid; diff --git a/game/shared/tf/tf_point_manager.cpp b/game/shared/tf/tf_point_manager.cpp index daec23b0..3da86448 100644 --- a/game/shared/tf/tf_point_manager.cpp +++ b/game/shared/tf/tf_point_manager.cpp @@ -319,19 +319,6 @@ bool CTFPointManager::UpdatePoint( tf_point_t *pPoint, int nIndex, float flDT, V Vector vecNewVelocity = pPoint->m_vecVelocity + vecGravity + GetAdditionalVelocity( pPoint ); Vector vecNewPos = pPoint->m_vecPosition + flDT * vecNewVelocity; - if ( pVecMins ) - { - *pVecMins = vecMins; - } - if ( pVecMaxs ) - { - *pVecMaxs = vecMaxs; - } - if ( pVecNewPos ) - { - *pVecNewPos = vecNewPos; - } - // Create a ray for point to trace Ray_t rayWorld; rayWorld.Init( pPoint->m_vecPosition, vecNewPos, vecMins, vecMaxs ); @@ -391,6 +378,19 @@ bool CTFPointManager::UpdatePoint( tf_point_t *pPoint, int nIndex, float flDT, V pPoint->m_vecPosition = vecNewPos; + if ( pVecMins ) + { + *pVecMins = vecMins; + } + if ( pVecMaxs ) + { + *pVecMaxs = vecMaxs; + } + if ( pVecNewPos ) + { + *pVecNewPos = vecNewPos; + } + return true; } diff --git a/game/shared/tf/tf_quest_restriction.cpp b/game/shared/tf/tf_quest_restriction.cpp index a4d5d298..4fe768e5 100644 --- a/game/shared/tf/tf_quest_restriction.cpp +++ b/game/shared/tf/tf_quest_restriction.cpp @@ -1144,7 +1144,7 @@ protected: int nNumJumps = pNonConstPlayer->GetGroundEntity() == NULL ? 1 : 0; nNumJumps += pPlayer->m_Shared.GetAirDash(); - nNumJumps += pPlayer->m_bScattergunJump; + nNumJumps += pPlayer->m_Shared.m_bScattergunJump; if ( m_eJumpingState == JUMPING_STATE_IS_NOT_JUMPING ) { @@ -3027,7 +3027,7 @@ bool CTFJumpStateQuestModifier::BPassesModifier( const CTFPlayer *pOwner, Invali #else int nNumJumps = const_cast< CTFPlayer* >( pOwner )->GetGroundEntity() == NULL ? 1 : 0; nNumJumps += pOwner->m_Shared.GetAirDash(); - nNumJumps += pOwner->m_bScattergunJump; + nNumJumps += pOwner->m_Shared.m_bScattergunJump; // If we want them on the ground, make sure they're on the ground if ( m_nJumpCount == 0 ) diff --git a/game/shared/tf/tf_shareddefs.cpp b/game/shared/tf/tf_shareddefs.cpp index d47d8985..bd54279b 100644 --- a/game/shared/tf/tf_shareddefs.cpp +++ b/game/shared/tf/tf_shareddefs.cpp @@ -915,6 +915,7 @@ const char *g_szSpecialDamageNames[] = "TF_DMG_CUSTOM_AXTINGUISHER_BOOSTED", "TF_DMG_CUSTOM_KRAMPUS_MELEE", "TF_DMG_CUSTOM_KRAMPUS_RANGED", + "TF_DMG_CUSTOM_TAUNTATK_TRICKSHOT", }; COMPILE_TIME_ASSERT( ARRAYSIZE( g_szSpecialDamageNames ) == TF_DMG_CUSTOM_END ); @@ -1053,6 +1054,7 @@ static const char* taunt_attack_name[] = "TAUNTATK_ALLCLASS_GUITAR_RIFF", "TAUNTATK_MEDIC_HEROIC_TAUNT", "TAUNTATK_PYRO_GASBLAST", + "TAUNTATK_ENGINEER_TRICKSHOT", // // INSERT NEW ITEMS HERE TO AVOID BREAKING DEMOS diff --git a/game/shared/tf/tf_shareddefs.h b/game/shared/tf/tf_shareddefs.h index 628cb8dc..f3b5a91a 100644 --- a/game/shared/tf/tf_shareddefs.h +++ b/game/shared/tf/tf_shareddefs.h @@ -966,6 +966,7 @@ enum taunt_attack_t TAUNTATK_ALLCLASS_GUITAR_RIFF, TAUNTATK_MEDIC_HEROIC_TAUNT, TAUNTATK_PYRO_GASBLAST, + TAUNTATK_ENGINEER_TRICKSHOT, // // INSERT NEW ITEMS HERE TO AVOID BREAKING DEMOS @@ -1263,6 +1264,7 @@ enum ETFDmgCustom TF_DMG_CUSTOM_AXTINGUISHER_BOOSTED, TF_DMG_CUSTOM_KRAMPUS_MELEE, TF_DMG_CUSTOM_KRAMPUS_RANGED, + TF_DMG_CUSTOM_TAUNTATK_TRICKSHOT, // // INSERT NEW ITEMS HERE TO AVOID BREAKING DEMOS // @@ -1287,7 +1289,8 @@ inline bool IsTauntDmg( int iType ) iType == TF_DMG_CUSTOM_TAUNTATK_ARMAGEDDON || iType == TF_DMG_CUSTOM_TAUNTATK_ALLCLASS_GUITAR_RIFF || iType == TF_DMG_CUSTOM_TAUNTATK_ENGINEER_ARM_KILL || - iType == TF_DMG_CUSTOM_TAUNTATK_GASBLAST ); + iType == TF_DMG_CUSTOM_TAUNTATK_GASBLAST || + iType == TF_DMG_CUSTOM_TAUNTATK_TRICKSHOT ); } inline bool IsDOTDmg( int iType ) { diff --git a/game/shared/tf/tf_weapon_bottle.cpp b/game/shared/tf/tf_weapon_bottle.cpp index a0040745..ff74cff1 100644 --- a/game/shared/tf/tf_weapon_bottle.cpp +++ b/game/shared/tf/tf_weapon_bottle.cpp @@ -254,12 +254,19 @@ void CTFStickBomb::Smack( void ) TE_TFExplosion( filter, 0.0f, explosion, Vector(0,0,1), TF_WEAPON_GRENADELAUNCHER, pTFPlayer->entindex(), -1, SPECIAL1, iCustomParticleIndex ); - int dmgType = DMG_BLAST | DMG_USEDISTANCEMOD; + int dmgType = DMG_BLAST | DMG_USEDISTANCEMOD | DMG_MELEE; if ( IsCurrentAttackACrit() ) dmgType |= DMG_CRITICAL; - CTakeDamageInfo info( pTFPlayer, pTFPlayer, this, explosion, explosion, 75.0f, dmgType, TF_DMG_CUSTOM_STICKBOMB_EXPLOSION, &explosion ); - CTFRadiusDamageInfo radiusinfo( &info, explosion, 100.f ); + float flDamage = 75.0f; + CALL_ATTRIB_HOOK_FLOAT( flDamage, mult_dmg ); + + CTakeDamageInfo info( pTFPlayer, pTFPlayer, this, explosion, explosion, flDamage, dmgType, TF_DMG_CUSTOM_STICKBOMB_EXPLOSION, &explosion ); + + float flRadius = 100.f; + CALL_ATTRIB_HOOK_FLOAT( flRadius, mult_explosion_radius ); + + CTFRadiusDamageInfo radiusinfo( &info, explosion, flRadius ); TFGameRules()->RadiusDamage( radiusinfo ); } #endif diff --git a/game/shared/tf/tf_weapon_compound_bow.cpp b/game/shared/tf/tf_weapon_compound_bow.cpp index 449329c7..768ae084 100644 --- a/game/shared/tf/tf_weapon_compound_bow.cpp +++ b/game/shared/tf/tf_weapon_compound_bow.cpp @@ -654,19 +654,7 @@ void CTFCompoundBow::SetArrowAlight( bool bAlight ) //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -void CTFCompoundBow::SetInternalChargeBeginTime( float flChargeBeginTime ) +bool CTFCompoundBow::OwnerCanJump( void ) { -#ifdef GAME_DLL - float flCurrentChargeBeginTime = GetInternalChargeBeginTime(); - if ( flCurrentChargeBeginTime == 0.f && flChargeBeginTime > 0.f ) - { - DisableJump(); - } - else if ( flCurrentChargeBeginTime > 0.f && flChargeBeginTime == 0.f ) - { - EnableJump(); - } -#endif // GAME_DLL - - BaseClass::SetInternalChargeBeginTime( flChargeBeginTime ); + return GetInternalChargeBeginTime() == 0.f; } diff --git a/game/shared/tf/tf_weapon_compound_bow.h b/game/shared/tf/tf_weapon_compound_bow.h index cbbbb9c7..a192166d 100644 --- a/game/shared/tf/tf_weapon_compound_bow.h +++ b/game/shared/tf/tf_weapon_compound_bow.h @@ -89,8 +89,7 @@ public: void SetArrowAlight( bool bAlight ); -protected: - virtual void SetInternalChargeBeginTime( float flChargeBeginTime ) OVERRIDE; + bool OwnerCanJump( void ); private: #ifdef CLIENT_DLL diff --git a/game/shared/tf/tf_weapon_dragons_fury.cpp b/game/shared/tf/tf_weapon_dragons_fury.cpp index c5d50367..f8976a33 100644 --- a/game/shared/tf/tf_weapon_dragons_fury.cpp +++ b/game/shared/tf/tf_weapon_dragons_fury.cpp @@ -21,7 +21,7 @@ #endif extern ConVar tf_flamethrower_burstammo; - +extern ConVar tf_fireball_distance; //============================================================================= // @@ -144,24 +144,19 @@ CBaseEntity* CTFWeaponFlameBall::FireProjectile( CTFPlayer *pPlayer ) RemoveProjectileAmmo( pPlayer ); #ifdef GAME_DLL - Vector vecForward, vecRight, vecUp; - AngleVectors( pPlayer->EyeAngles(), &vecForward, &vecRight, &vecUp ); + QAngle angForward = pPlayer->EyeAngles(); - float fRight = 8.f; + Vector vecForward, vecRight, vecUp; + AngleVectors( angForward, &vecForward, &vecRight, &vecUp ); + + float fRight = 7.0f; if ( IsViewModelFlipped() ) { fRight *= -1; } - Vector vecSrc = pPlayer->Weapon_ShootPosition(); + Vector vecShootPos = pPlayer->Weapon_ShootPosition(); // Shoot from the right location - vecSrc = vecSrc + (vecUp * -9.0f) + (vecRight * 7.0f) + (vecForward * 3.0f); - - QAngle angForward = pPlayer->EyeAngles(); - - trace_t trace; - Vector vecEye = pPlayer->EyePosition(); - CTraceFilterSimple traceFilter( this, COLLISION_GROUP_NONE ); - UTIL_TraceHull( vecEye, vecSrc, -Vector(8,8,8), Vector(8,8,8), MASK_SOLID_BRUSHONLY, &traceFilter, &trace ); + Vector vecSrc = vecShootPos + ( vecUp * -9.0f ) + ( vecRight * fRight ) + ( vecForward * 3.0f ); CTFProjectile_Rocket *pRocket = static_cast( CBaseEntity::CreateNoSpawn( "tf_projectile_balloffire", vecSrc, angForward, pPlayer ) ); if ( pRocket ) @@ -171,12 +166,14 @@ CBaseEntity* CTFWeaponFlameBall::FireProjectile( CTFPlayer *pPlayer ) DoFireEffects(); pRocket->SetOwnerEntity( pPlayer ); - pRocket->SetLauncher( this ); + pRocket->SetLauncher( this ); - Vector vForward; - AngleVectors( angForward, &vForward, NULL, NULL ); + float flEndDist = tf_fireball_distance.GetFloat(); - pRocket->SetAbsVelocity( vForward * 600 ); + Vector vecProjForward = ( vecShootPos + vecForward * flEndDist ) - vecSrc; + VectorNormalize( vecProjForward ); + + pRocket->SetAbsVelocity( vecProjForward * 600 ); pRocket->SetDamage( 20 ); pRocket->ChangeTeam( pPlayer->GetTeamNumber() ); diff --git a/game/shared/tf/tf_weapon_flamethrower.cpp b/game/shared/tf/tf_weapon_flamethrower.cpp index 28e51555..65810b22 100644 --- a/game/shared/tf/tf_weapon_flamethrower.cpp +++ b/game/shared/tf/tf_weapon_flamethrower.cpp @@ -2110,7 +2110,7 @@ bool CTFFlameThrower::EffectMeterShouldFlash( void ) //----------------------------------------------------------------------------- Vector CTFFlameThrower::GetMuzzlePosHelper( bool bVisualPos ) { - Vector vecMuzzlePos; + Vector vecMuzzlePos = vec3_origin; CTFPlayer *pOwner = GetTFPlayerOwner(); if ( pOwner ) { diff --git a/game/shared/tf/tf_weapon_invis.cpp b/game/shared/tf/tf_weapon_invis.cpp index 4663ea7c..3333739f 100644 --- a/game/shared/tf/tf_weapon_invis.cpp +++ b/game/shared/tf/tf_weapon_invis.cpp @@ -28,8 +28,11 @@ IMPLEMENT_NETWORKCLASS_ALIASED( TFWeaponInvis, DT_TFWeaponInvis ) BEGIN_NETWORK_TABLE( CTFWeaponInvis, DT_TFWeaponInvis ) END_NETWORK_TABLE() +#if defined( CLIENT_DLL ) BEGIN_PREDICTION_DATA( CTFWeaponInvis ) + DEFINE_PRED_FIELD( m_flHideTime, FIELD_FLOAT, 0 ) END_PREDICTION_DATA() +#endif LINK_ENTITY_TO_CLASS( tf_weapon_invis, CTFWeaponInvis ); PRECACHE_WEAPON_REGISTER( tf_weapon_invis ); @@ -69,7 +72,20 @@ void CTFWeaponInvis::OnActiveStateChanged( int iOldState ) //----------------------------------------------------------------------------- void CTFWeaponInvis::HideThink( void ) { - SetWeaponVisible( false ); + // This is now done in ItemPostFrame/ItemBusyFrame + // HideThink uses a context think, which is evaluated with predicted clock on client + // but relative to server (not the player's!) clock on the server + // SetWeaponVisible( false ); +} + +//----------------------------------------------------------------------------- +void CTFWeaponInvis::CheckHideTime( void ) +{ + if ( m_flHideTime && m_flHideTime < gpGlobals->curtime ) + { + SetWeaponVisible( false ); + m_flHideTime = 0; + } } //----------------------------------------------------------------------------- @@ -131,11 +147,15 @@ void CTFWeaponInvis::SetWeaponVisible( bool visible ) //----------------------------------------------------------------------------- bool CTFWeaponInvis::Deploy( void ) { - bool b = BaseClass::Deploy(); + bool bDeploy = BaseClass::Deploy(); - SetWeaponIdleTime( gpGlobals->curtime + 1.5 ); + if ( bDeploy ) + { + SetWeaponIdleTime( gpGlobals->curtime + 1.5 ); + m_flHideTime = 0; + } - return b; + return bDeploy; } //----------------------------------------------------------------------------- @@ -143,8 +163,12 @@ bool CTFWeaponInvis::Holster( CBaseCombatWeapon *pSwitchingTo ) { bool bHolster = BaseClass::Holster( pSwitchingTo ); - // far in the future - SetWeaponIdleTime( gpGlobals->curtime + 10 ); + if ( bHolster ) + { + // far in the future + SetWeaponIdleTime( gpGlobals->curtime + 10 ); + m_flHideTime = gpGlobals->curtime + SequenceDuration(); + } return bHolster; } @@ -161,10 +185,18 @@ void CTFWeaponInvis::SecondaryAttack( void ) // do nothing } +//----------------------------------------------------------------------------- +void CTFWeaponInvis::ItemPostFrame( void ) +{ + CheckHideTime(); + BaseClass::ItemPostFrame(); +} + //----------------------------------------------------------------------------- void CTFWeaponInvis::ItemBusyFrame( void ) { - // do nothing + CheckHideTime(); + // intentionally don't call base } //----------------------------------------------------------------------------- diff --git a/game/shared/tf/tf_weapon_invis.h b/game/shared/tf/tf_weapon_invis.h index 3791aafb..23468ebe 100644 --- a/game/shared/tf/tf_weapon_invis.h +++ b/game/shared/tf/tf_weapon_invis.h @@ -46,6 +46,7 @@ public: virtual bool Deploy( void ); virtual void HideThink( void ); + void CheckHideTime(); virtual bool Holster( CBaseCombatWeapon *pSwitchingTo ); virtual int GetWeaponID( void ) const { return TF_WEAPON_INVIS; } @@ -59,6 +60,7 @@ public: virtual void SetWeaponVisible( bool visible ); + virtual void ItemPostFrame( void ); virtual void ItemBusyFrame( void ); int GetInvisType( void ) { int iMode = 0; CALL_ATTRIB_HOOK_INT( iMode, set_weapon_mode ); return iMode; }; @@ -81,6 +83,7 @@ public: #endif private: + float m_flHideTime; CTFWeaponInvis( const CTFWeaponInvis & ) {} }; diff --git a/game/shared/tf/tf_weapon_jar.cpp b/game/shared/tf/tf_weapon_jar.cpp index 31227daa..ba54bf9a 100644 --- a/game/shared/tf/tf_weapon_jar.cpp +++ b/game/shared/tf/tf_weapon_jar.cpp @@ -206,6 +206,17 @@ void CTFJar::TossJarThink( void ) pPlayer->SpeakWeaponFire( MP_CONCEPT_JARATE_LAUNCH ); } + if ( pProjectile->ExplodesOnHit() ) + { + Vector vecEnd = pProjectile->GetAbsOrigin() + ( vecVelocity.Normalized() * 32.0f ); + UTIL_TraceHull( pProjectile->GetAbsOrigin(), vecEnd, -Vector( 8, 8, 8 ), Vector( 8, 8, 8 ), MASK_SOLID_BRUSHONLY, &traceFilter, &trace ); + + if ( trace.fraction < 1.0 ) + { + pProjectile->Explode( &trace, pProjectile->GetDamageType() ); + } + } + #endif } //----------------------------------------------------------------------------- diff --git a/game/shared/tf/tf_weapon_knife.cpp b/game/shared/tf/tf_weapon_knife.cpp index 11cb96a9..2eb67776 100644 --- a/game/shared/tf/tf_weapon_knife.cpp +++ b/game/shared/tf/tf_weapon_knife.cpp @@ -240,7 +240,7 @@ void CTFKnife::PrimaryAttack( void ) C_CTF_GameStats.Event_PlayerFiredWeapon( pPlayer, IsCurrentAttackACrit() ); #endif - bool bSuccessfulBackstab = IsBackstab() && !m_hBackstabVictim->IsAlive(); + bool bSuccessfulBackstab = IsBackstab() && ( !m_hBackstabVictim->IsAlive() || m_hBackstabVictim->m_Shared.InCond( TF_COND_HALLOWEEN_GHOST_MODE ) ); ETFFlagType ignoreTypes[] = { TF_FLAGTYPE_PLAYER_DESTRUCTION }; if ( ShouldDisguiseOnBackstab() && bSuccessfulBackstab && !pPlayer->HasTheFlag( ignoreTypes, ARRAYSIZE( ignoreTypes ) ) ) diff --git a/game/shared/tf/tf_weapon_mechanical_arm.cpp b/game/shared/tf/tf_weapon_mechanical_arm.cpp index 7861249a..0f1a4f4f 100644 --- a/game/shared/tf/tf_weapon_mechanical_arm.cpp +++ b/game/shared/tf/tf_weapon_mechanical_arm.cpp @@ -250,17 +250,14 @@ void CTFMechanicalArm::SecondaryAttack( void ) Vector vecForward, vecRight, vecUp; AngleVectors( pOwner->EyeAngles(), &vecForward, &vecRight, &vecUp ); - float fRight = 8.f; + float fRight = 15.f; if ( IsViewModelFlipped() ) { fRight *= -1; } // Vector vecSrc = pOwner->Weapon_ShootPosition(); // vecSrc = vecSrc + ( vecUp * -9.0f ) + ( vecRight * 7.0f ) + ( vecForward * 3.0f ); - Vector vecSrc = pOwner->EyePosition() - + ( vecForward * 40.f ) - + ( vecRight * 15.f ) - + ( vecUp * -10.f ); + Vector vecSrc = pOwner->EyePosition() + ( vecForward * 40.f ) + ( vecRight * fRight ) + ( vecUp * -10.f ); QAngle angForward = pOwner->EyeAngles(); diff --git a/game/shared/tf/tf_weapon_medigun.cpp b/game/shared/tf/tf_weapon_medigun.cpp index ed55d29e..4caa1858 100644 --- a/game/shared/tf/tf_weapon_medigun.cpp +++ b/game/shared/tf/tf_weapon_medigun.cpp @@ -458,6 +458,7 @@ bool CWeaponMedigun::Holster( CBaseCombatWeapon *pSwitchingTo ) //----------------------------------------------------------------------------- void CWeaponMedigun::UpdateOnRemove( void ) { + m_bHealing = false; RemoveHealingTarget( true ); m_bAttacking = false; m_bChargeRelease = false; @@ -681,7 +682,7 @@ void CWeaponMedigun::MaintainTargetInSlot() pOwner->EyeVectors( &vecAiming ); Vector vecEnd = vecSrc + vecAiming * GetTargetRange(); - UTIL_TraceLine( vecSrc, vecEnd, (MASK_SHOT & ~CONTENTS_HITBOX), pOwner, DMG_GENERIC, &tr ); + UTIL_TraceLine( vecSrc, vecEnd, (MASK_SHOT & ~CONTENTS_HITBOX), pOwner, COLLISION_GROUP_NONE, &tr ); // Still visible? if ( tr.m_pEnt == pTarget ) @@ -728,24 +729,39 @@ void CWeaponMedigun::FindNewTargetForSlot() // Find a player in range of this player, and make sure they're healable. Vector vecEnd = vecSrc + vecAiming * GetTargetRange(); trace_t tr; + // for leniency, trace for hull instead of hitboxes first + UTIL_TraceLine( vecSrc, vecEnd, (MASK_SHOT & ~CONTENTS_HITBOX), pOwner, COLLISION_GROUP_NONE, &tr ); - UTIL_TraceLine( vecSrc, vecEnd, (MASK_SHOT & ~CONTENTS_HITBOX), pOwner, DMG_GENERIC, &tr ); if ( tr.fraction != 1.0 && tr.m_pEnt ) { - if ( !HealingTarget( tr.m_pEnt ) && AllowedToHealTarget( tr.m_pEnt ) ) + CBaseEntity *pTarget = tr.m_pEnt; + + // trace again but for hitboxes to help with selecting targets that are clumped together + UTIL_TraceLine( vecSrc, vecEnd, MASK_SHOT, pOwner, COLLISION_GROUP_NONE, &tr ); + + if ( tr.fraction != 1.0 && tr.m_pEnt && tr.m_pEnt != pTarget && !HealingTarget( tr.m_pEnt ) && AllowedToHealTarget( tr.m_pEnt ) ) + { + pTarget = tr.m_pEnt; + } + else if ( HealingTarget( pTarget ) || !AllowedToHealTarget( pTarget ) ) + { + pTarget = NULL; + } + + if ( pTarget ) { #ifdef GAME_DLL pOwner->SpeakConceptIfAllowed( MP_CONCEPT_MEDIC_STARTEDHEALING ); - if ( tr.m_pEnt->IsPlayer() ) + if ( pTarget->IsPlayer() ) { - CTFPlayer *pTarget = ToTFPlayer( tr.m_pEnt ); - pTarget->SpeakConceptIfAllowed( MP_CONCEPT_HEALTARGET_STARTEDHEALING ); + CTFPlayer *pTFPlayer = ToTFPlayer( pTarget ); + pTFPlayer->SpeakConceptIfAllowed( MP_CONCEPT_HEALTARGET_STARTEDHEALING ); } // Start the heal target thinking. SetContextThink( &CWeaponMedigun::HealTargetThink, gpGlobals->curtime, s_pszMedigunHealTargetThink ); #endif - m_hHealingTarget.Set( tr.m_pEnt ); + m_hHealingTarget.Set( pTarget ); m_flNextTargetCheckTime = gpGlobals->curtime + 1.0f; } } @@ -1357,7 +1373,7 @@ bool CWeaponMedigun::FindAndHealTargets( void ) } #ifdef CLIENT_DLL - if ( GetMedigunType() == MEDIGUN_RESIST ) + if ( GetMedigunType() == MEDIGUN_RESIST && prediction->IsFirstTimePredicted() ) { // Play a sound when we tick over to a new charge level int nChargeLevel = int(floor(flNewLevel/flMinChargeAmount)); diff --git a/game/shared/tf/tf_weapon_minigun.cpp b/game/shared/tf/tf_weapon_minigun.cpp index 0ae602aa..1cae881c 100644 --- a/game/shared/tf/tf_weapon_minigun.cpp +++ b/game/shared/tf/tf_weapon_minigun.cpp @@ -1095,6 +1095,11 @@ void CTFMinigun::StandardBlendingRules( CStudioHdr *hdr, Vector pos[], Quaternio //----------------------------------------------------------------------------- void CTFMinigun::UpdateBarrelMovement() { + if ( prediction->InPrediction() && !prediction->IsFirstTimePredicted() ) + { + return; + } + if ( m_flBarrelCurrentVelocity != m_flBarrelTargetVelocity ) { float flBarrelAcceleration = CanHolsterWhileSpinning() ? 0.5f : 0.1f; diff --git a/game/shared/tf/tf_weapon_pda.cpp b/game/shared/tf/tf_weapon_pda.cpp index 257ebc0f..010aeb9a 100644 --- a/game/shared/tf/tf_weapon_pda.cpp +++ b/game/shared/tf/tf_weapon_pda.cpp @@ -317,7 +317,7 @@ bool CTFWeaponPDA_Spy::Deploy( void ) { bool bDeploy = BaseClass::Deploy(); - if ( bDeploy ) + if ( bDeploy && prediction->IsFirstTimePredicted() ) { // let the spy pda menu know to reset IGameEvent *event = gameeventmanager->CreateEvent( "spy_pda_reset" ); diff --git a/game/shared/tf/tf_weapon_rocketpack.cpp b/game/shared/tf/tf_weapon_rocketpack.cpp index b3202a37..b41cc88a 100644 --- a/game/shared/tf/tf_weapon_rocketpack.cpp +++ b/game/shared/tf/tf_weapon_rocketpack.cpp @@ -13,6 +13,7 @@ #ifdef CLIENT_DLL #include "c_tf_player.h" #include "c_rope.h" +#include "prediction.h" // Server specific. #else #include "tf_player.h" @@ -47,7 +48,10 @@ END_NETWORK_TABLE() #ifdef CLIENT_DLL BEGIN_PREDICTION_DATA( CTFRocketPack ) DEFINE_PRED_FIELD( m_flInitLaunchTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_flLaunchTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), DEFINE_PRED_FIELD( m_flToggleEndTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_flRefireTime, FIELD_FLOAT, 0 ), + DEFINE_PRED_FIELD( m_bLaunchedFromGround, FIELD_BOOLEAN, 0 ), END_PREDICTION_DATA() #endif // CLIENT_DLL @@ -66,7 +70,7 @@ ConVar tf_rocketpack_impact_push_min( "tf_rocketpack_impact_push_min", "100", FC ConVar tf_rocketpack_impact_push_max( "tf_rocketpack_impact_push_max", "300", FCVAR_REPLICATED | FCVAR_CHEAT | FCVAR_HIDDEN ); ConVar tf_rocketpack_launch_push( "tf_rocketpack_launch_push", "250", FCVAR_REPLICATED | FCVAR_CHEAT | FCVAR_HIDDEN ); -#ifdef GAME_DLL +#if defined( GAME_DLL ) || defined( STAGING_ONLY ) #define TF_ROCKETPACK_PASSENGER_DELAY_LAUNCH 0.2f #endif // GAME_DLL @@ -211,10 +215,13 @@ bool CTFRocketPack::InitiateLaunch( void ) CTFPlayer *pOwner = GetTFPlayerOwner(); if ( !pOwner->m_Shared.IsRocketPackReady() ) { -#ifdef GAME_DLL - CPVSFilter filter( WorldSpaceCenter() ); - pOwner->EmitSound( filter, entindex(), "Weapon_RocketPack.BoostersNotReady" ); -#endif // GAME_DLL + // note: this is never reached +#ifdef CLIENT_DLL + if ( prediction->IsFirstTimePredicted() ) + { + pOwner->EmitSound( "Weapon_RocketPack.BoostersNotReady" ); + } +#endif return false; } @@ -224,16 +231,18 @@ bool CTFRocketPack::InitiateLaunch( void ) return false; } -#ifdef GAME_DLL - if ( pOwner->m_Shared.IsLoser() ) +#ifdef CLIENT_DLL + if ( prediction->IsFirstTimePredicted() ) +#endif { - pOwner->EmitSound( "Weapon_RocketPack.BoostersNotReady" ); + CPASAttenuationFilter filter( pOwner ); + filter.UsePredictionRules(); + pOwner->EmitSound( + filter, + entindex(), + pOwner->m_Shared.IsLoser() ? "Weapon_RocketPack.BoostersNotReady" : "Weapon_RocketPack.BoostersCharge" + ); } - else - { - pOwner->EmitSound( "Weapon_RocketPack.BoostersCharge" ); - } -#endif // GAME_DLL m_flInitLaunchTime = gpGlobals->curtime; @@ -369,7 +378,6 @@ bool CTFRocketPack::ShouldDraw() #endif // CLIENT_DLL -#ifdef GAME_DLL //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -384,7 +392,7 @@ Vector CTFRocketPack::CalcRocketForceFromPlayer( CTFPlayer *pPlayer ) const float flVertPushScale = ( bOnGround ) ? 0.7f : 0.25f; // Less vertical force while airborne Vector vecForward, vecRight; - QAngle angAim = ( bOnGround ) ? pPlayer->GetAbsAngles() : pPlayer->EyeAngles(); + QAngle angAim = pPlayer->EyeAngles(); AngleVectors( angAim, &vecForward, &vecRight, NULL ); bool bNone = !( pPlayer->m_nButtons & IN_FORWARD ) && !( pPlayer->m_nButtons & IN_BACK ) /* && @@ -468,7 +476,6 @@ void CTFRocketPack::RocketLaunchPlayer( CTFPlayer *pPlayer, const Vector& vecFor pPlayer->ApplyAbsVelocityImpulse( vecForce ); } -#endif // GAME_DLL //----------------------------------------------------------------------------- // Purpose: @@ -482,7 +489,6 @@ bool CTFRocketPack::PreLaunch( void ) pOwner->DoAnimationEvent( PLAYERANIMEVENT_CUSTOM, ACT_MP_ATTACK_STAND_PRIMARYFIRE ); SendWeaponAnim( ACT_VM_PRIMARYATTACK ); -#ifdef GAME_DLL // Negate any fall Vector vecVel = pOwner->GetAbsVelocity(); if ( vecVel.z < 0.f ) @@ -496,14 +502,15 @@ bool CTFRocketPack::PreLaunch( void ) pOwner->ApplyAbsVelocityImpulse( vForward ); pOwner->m_Shared.AddCond( TF_COND_PARACHUTE_ACTIVE ); +#ifdef GAME_DLL const Vector &vecOrigin = pOwner->GetAbsOrigin(); CPVSFilter filter( vecOrigin ); TE_TFParticleEffect( filter, 0.f, "heavy_ring_of_fire", vecOrigin, vec3_angle ); DispatchParticleEffect( "rocketjump_smoke", PATTACH_POINT_FOLLOW, pOwner, "foot_L" ); DispatchParticleEffect( "rocketjump_smoke", PATTACH_POINT_FOLLOW, pOwner, "foot_R" ); +#endif // GAME_DLL m_flLaunchTime = gpGlobals->curtime + tf_rocketpack_launch_delay.GetFloat(); -#endif // GAME_DLL return true; } @@ -519,16 +526,20 @@ bool CTFRocketPack::Launch( void ) pOwner->StopSound( "Weapon_LooseCannon.Charge" ); -#ifdef GAME_DLL m_flLaunchTime = 0.f; pOwner->m_Shared.RemoveCond( TF_COND_PARACHUTE_ACTIVE ); +#ifdef CLIENT_DLL + Vector m_vecLaunchDir; +#endif // Launch m_vecLaunchDir = CalcRocketForceFromPlayer( pOwner ); RocketLaunchPlayer( pOwner, m_vecLaunchDir, false ); - + +#ifdef GAME_DLL SetContextThink( &CTFRocketPack::PassengerDelayLaunchThink, gpGlobals->curtime + TF_ROCKETPACK_PASSENGER_DELAY_LAUNCH, "PassengerDelayLaunchThink" ); +#endif m_flRefireTime = gpGlobals->curtime + 0.5f; @@ -536,6 +547,7 @@ bool CTFRocketPack::Launch( void ) pOwner->m_Shared.SetRocketPackCharge( pOwner->m_Shared.GetRocketPackCharge() - tf_rocketpack_cost.GetFloat() ); } +#ifdef GAME_DLL // Knock-back nearby enemies float flRadius = 150.f; CUtlVector< CTFPlayer* > vecPushedPlayers; @@ -594,6 +606,7 @@ bool CTFRocketPack::Launch( void ) } CPASAttenuationFilter filter( pOwner ); + filter.UsePredictionRules(); pOwner->EmitSound( filter, pOwner->entindex(), "Weapon_RocketPack.BoostersFire" ); IGameEvent *pEvent = gameeventmanager->CreateEvent( "rocketpack_launch" ); @@ -610,7 +623,12 @@ bool CTFRocketPack::Launch( void ) DispatchParticleEffect( ROCKET_PACK_LAUNCH_EFFECT, PATTACH_POINT_FOLLOW, pWearable, "charge_LA" ); DispatchParticleEffect( ROCKET_PACK_LAUNCH_EFFECT, PATTACH_POINT_FOLLOW, pWearable, "charge_RA" ); } -#endif // GAME_DLL +#else + if ( prediction->IsFirstTimePredicted() ) + { + pOwner->EmitSound( "Weapon_RocketPack.BoostersFire" ); + } +#endif // CLIENT_DLL return true; } @@ -748,7 +766,7 @@ void CTFRocketPack::ItemPostFrame( void ) { ResetTransition(); #ifdef CLIENT_DLL - if ( pOwner == C_TFPlayer::GetLocalTFPlayer() ) + if ( pOwner == C_TFPlayer::GetLocalTFPlayer() && prediction->IsFirstTimePredicted() ) { pOwner->EmitSound( "Weapon_RocketPack.BoostersReady" ); } @@ -757,7 +775,7 @@ void CTFRocketPack::ItemPostFrame( void ) else if ( pOwner->m_afButtonPressed & IN_ATTACK2 ) { #ifdef CLIENT_DLL - if ( pOwner == C_TFPlayer::GetLocalTFPlayer() ) + if ( pOwner == C_TFPlayer::GetLocalTFPlayer() && prediction->IsFirstTimePredicted() ) { pOwner->EmitSound( "Player.DenyWeaponSelection" ); } @@ -841,14 +859,21 @@ const CEconItemView *CTFRocketPack::GetTauntItem() const //----------------------------------------------------------------------------- bool CTFRocketPack::Deploy( void ) { -#ifdef GAME_DLL CTFPlayer *pOwner = GetTFPlayerOwner(); if ( pOwner ) { - EmitSound( "Weapon_RocketPack.BoostersExtend" ); +#ifdef CLIENT_DLL + if ( prediction->IsFirstTimePredicted() ) +#endif + { + CPASAttenuationFilter filter( pOwner ); + filter.UsePredictionRules(); + EmitSound( filter, entindex(), "Weapon_RocketPack.BoostersExtend" ); + } +#ifdef GAME_DLL SetEnabled( true ); +#endif } -#endif // GAME_DLL return BaseClass::Deploy(); } @@ -861,14 +886,21 @@ void CTFRocketPack::StartHolsterAnim( void ) { BaseClass::StartHolsterAnim(); -#ifdef GAME_DLL CTFPlayer *pOwner = GetTFPlayerOwner(); if ( pOwner ) { - EmitSound( "Weapon_RocketPack.BoostersRetract" ); +#ifdef CLIENT_DLL + if ( prediction->IsFirstTimePredicted() ) +#endif + { + CPASAttenuationFilter filter( pOwner ); + filter.UsePredictionRules(); + EmitSound( filter, entindex(), "Weapon_RocketPack.BoostersRetract" ); + } +#ifdef GAME_DLL SetEnabled( false ); +#endif } -#endif // GAME_DLL } @@ -890,7 +922,7 @@ void CTFRocketPack::OnResourceMeterFilled() { #ifdef CLIENT_DLL CBasePlayer *pPlayer = GetPlayerOwner(); - if ( pPlayer->IsLocalPlayer() ) + if ( pPlayer->IsLocalPlayer() && prediction->IsFirstTimePredicted() ) { pPlayer->EmitSound( "TFPlayer.ReCharged" ); } diff --git a/game/shared/tf/tf_weapon_rocketpack.h b/game/shared/tf/tf_weapon_rocketpack.h index 9c1e6ec3..f2de5574 100644 --- a/game/shared/tf/tf_weapon_rocketpack.h +++ b/game/shared/tf/tf_weapon_rocketpack.h @@ -71,14 +71,14 @@ private: bool IsTransitionCompleted( void ) const; void WaitToLaunch( void ); + void RocketLaunchPlayer( CTFPlayer *pPlayer, const Vector& vecForce, bool bIsPassenger ); + Vector CalcRocketForceFromPlayer( CTFPlayer *pPlayer ); #ifdef GAME_DLL void SetEnabled( bool bEnabled ); void PassengerDelayLaunchThink( void ); - void RocketLaunchPlayer( CTFPlayer *pPlayer, const Vector& vecForce, bool bIsPassenger ); - Vector CalcRocketForceFromPlayer( CTFPlayer *pPlayer ); #else void CleanupParticles( void ); -#endif // GAME_DLL +#endif // CLIENT_DLL CNetworkVar( float, m_flInitLaunchTime ); CNetworkVar( float, m_flLaunchTime ); diff --git a/game/shared/tf/tf_weapon_shotgun.cpp b/game/shared/tf/tf_weapon_shotgun.cpp index 4b97dc47..666e0053 100644 --- a/game/shared/tf/tf_weapon_shotgun.cpp +++ b/game/shared/tf/tf_weapon_shotgun.cpp @@ -316,7 +316,6 @@ extern float AirBurstDamageForce( const Vector &size, float damage, float scale //----------------------------------------------------------------------------- void CTFScatterGun::FireBullet( CTFPlayer *pPlayer ) { -#ifndef CLIENT_DLL if ( HasKnockback() ) { // Perform some knock back. @@ -329,9 +328,9 @@ void CTFScatterGun::FireBullet( CTFPlayer *pPlayer ) return; // Knock the firer back! - if ( !(pOwner->GetFlags() & FL_ONGROUND) && !pPlayer->m_bScattergunJump ) + if ( !(pOwner->GetFlags() & FL_ONGROUND) && !pPlayer->m_Shared.m_bScattergunJump ) { - pPlayer->m_bScattergunJump = true; + pPlayer->m_Shared.m_bScattergunJump = true; pOwner->m_Shared.StunPlayer( 0.3f, 1.f, TF_STUN_MOVEMENT | TF_STUN_MOVEMENT_FORWARD_ONLY ); @@ -341,15 +340,15 @@ void CTFScatterGun::FireBullet( CTFPlayer *pPlayer ) AngleVectors( pOwner->EyeAngles(), &vecForward ); Vector vecForce = vecForward * -flForce; - EntityMatrix mtxPlayer; - mtxPlayer.InitFromEntity( pOwner ); + VMatrix mtxPlayer; + mtxPlayer.SetupMatrixOrgAngles( pOwner->GetAbsOrigin(), pOwner->EyeAngles() ); Vector vecAbsVelocity = pOwner->GetAbsVelocity(); Vector vecAbsVelocityAsPoint = vecAbsVelocity + pOwner->GetAbsOrigin(); - Vector vecLocalVelocity = mtxPlayer.WorldToLocal( vecAbsVelocityAsPoint ); + Vector vecLocalVelocity = mtxPlayer.VMul4x3Transpose( vecAbsVelocityAsPoint ); vecLocalVelocity.x = -300; - vecAbsVelocityAsPoint = mtxPlayer.LocalToWorld( vecLocalVelocity ); + vecAbsVelocityAsPoint = mtxPlayer.VMul4x3( vecLocalVelocity ); vecAbsVelocity = vecAbsVelocityAsPoint - pOwner->GetAbsOrigin(); pOwner->SetAbsVelocity( vecAbsVelocity ); @@ -360,7 +359,6 @@ void CTFScatterGun::FireBullet( CTFPlayer *pPlayer ) pOwner->RemoveFlag( FL_ONGROUND ); } } -#endif BaseClass::FireBullet( pPlayer ); } @@ -442,61 +440,6 @@ bool CTFScatterGun::HasKnockback( void ) return false; } -//----------------------------------------------------------------------------- -// Purpose: Play animation appropriate to ball status. -//----------------------------------------------------------------------------- -bool CTFScatterGun::SendWeaponAnim( int iActivity ) -{ - CTFPlayer *pPlayer = GetTFPlayerOwner(); - if ( !pPlayer ) - return BaseClass::SendWeaponAnim( iActivity ); - - if ( HasKnockback() ) - { - // Knockback version uses a different model and animation set. - switch ( iActivity ) - { - case ACT_VM_DRAW: - iActivity = ACT_ITEM2_VM_DRAW; - break; - case ACT_VM_HOLSTER: - iActivity = ACT_ITEM2_VM_HOLSTER; - break; - case ACT_VM_IDLE: - iActivity = ACT_ITEM2_VM_IDLE; - break; - case ACT_VM_PULLBACK: - iActivity = ACT_ITEM2_VM_PULLBACK; - break; - case ACT_VM_PRIMARYATTACK: - iActivity = ACT_ITEM2_VM_PRIMARYATTACK; - break; - case ACT_VM_SECONDARYATTACK: - iActivity = ACT_ITEM2_VM_SECONDARYATTACK; - break; - case ACT_VM_RELOAD: - iActivity = ACT_ITEM2_VM_RELOAD; - break; - case ACT_VM_DRYFIRE: - iActivity = ACT_ITEM2_VM_DRYFIRE; - break; - case ACT_VM_IDLE_TO_LOWERED: - iActivity = ACT_ITEM2_VM_IDLE_TO_LOWERED; - break; - case ACT_VM_IDLE_LOWERED: - iActivity = ACT_ITEM2_VM_IDLE_LOWERED; - break; - case ACT_VM_LOWERED_TO_IDLE: - iActivity = ACT_ITEM2_VM_LOWERED_TO_IDLE; - break; - default: - break; - } - } - - return BaseClass::SendWeaponAnim( iActivity ); -} - #ifdef GAME_DLL //----------------------------------------------------------------------------- void CTFScatterGun::Equip( CBaseCombatCharacter *pOwner ) diff --git a/game/shared/tf/tf_weapon_shotgun.h b/game/shared/tf/tf_weapon_shotgun.h index 56c5fb03..9cfaae23 100644 --- a/game/shared/tf/tf_weapon_shotgun.h +++ b/game/shared/tf/tf_weapon_shotgun.h @@ -114,7 +114,6 @@ public: virtual void ApplyPostHitEffects( const CTakeDamageInfo &inputInfo, CTFPlayer *pPlayer ); virtual void FinishReload( void ); virtual bool HasKnockback( void ); - virtual bool SendWeaponAnim( int iActivity ); #ifdef GAME_DLL virtual void Equip( CBaseCombatCharacter *pOwner ); diff --git a/game/shared/tf/tf_weapon_wrench.cpp b/game/shared/tf/tf_weapon_wrench.cpp index 9ca247bc..a1cf5ae3 100644 --- a/game/shared/tf/tf_weapon_wrench.cpp +++ b/game/shared/tf/tf_weapon_wrench.cpp @@ -121,17 +121,17 @@ void CTFWrench::OnFriendlyBuildingHit( CBaseObject *pObject, CTFPlayer *pPlayer, CDisablePredictionFiltering disabler; - if ( pObject->IsDisposableBuilding() ) + if ( bUsefulHit ) { - CSingleUserRecipientFilter singleFilter( pPlayer ); - EmitSound( singleFilter, pObject->entindex(), "Player.UseDeny" ); + // play success sound + WeaponSound( SPECIAL1 ); } else { - if ( bUsefulHit ) + if ( pObject->IsDisposableBuilding() ) { - // play success sound - WeaponSound( SPECIAL1 ); + CSingleUserRecipientFilter singleFilter( pPlayer ); + EmitSound( singleFilter, pObject->entindex(), "Player.UseDeny" ); } else { diff --git a/game/shared/tf/tf_weaponbase.cpp b/game/shared/tf/tf_weaponbase.cpp index 4a9ca46a..7385394f 100644 --- a/game/shared/tf/tf_weaponbase.cpp +++ b/game/shared/tf/tf_weaponbase.cpp @@ -48,6 +48,7 @@ // Client specific. #else #include "c_tf_player.h" +#include "c_baseviewmodel.h" #include "tf_viewmodel.h" #include "hud_crosshair.h" #include "c_tf_playerresource.h" @@ -91,7 +92,6 @@ extern ConVar tf_weapon_criticals_bucket_bottom; #ifdef CLIENT_DLL extern ConVar cl_crosshair_file; -extern ConVar cl_flipviewmodels; #endif //============================================================================= @@ -231,6 +231,8 @@ END_NETWORK_TABLE() BEGIN_PREDICTION_DATA( CTFWeaponBase ) #ifdef CLIENT_DLL DEFINE_PRED_FIELD( m_bLowered, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_bInAttack, FIELD_BOOLEAN, 0 ), + DEFINE_PRED_FIELD( m_bInAttack2, FIELD_BOOLEAN, 0 ), DEFINE_PRED_FIELD( m_iReloadMode, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), DEFINE_PRED_FIELD( m_bReloadedThroughAnimEvent, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), DEFINE_PRED_FIELD( m_bDisguiseWeapon, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), @@ -424,6 +426,19 @@ void CTFWeaponBase::Activate( void ) GiveDefaultAmmo(); } +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFWeaponBase::GiveDefaultAmmo( void ) +{ + BaseClass::GiveDefaultAmmo(); + + if ( IsEnergyWeapon() ) + { + m_flEnergy = Energy_GetMaxEnergy(); + } +} + // ----------------------------------------------------------------------------- // Purpose: // ----------------------------------------------------------------------------- @@ -967,7 +982,7 @@ void CTFWeaponBase::UpdateExtraWearables() // Precaching may be needed here, because we allow virtually everything to be loaded on demand now. pExtraWearableItem->PrecacheModel( pEconItemView->GetExtraWearableViewModel() ); } - + pExtraWearableItem->SetDisguiseWearable(m_bDisguiseWeapon); pExtraWearableItem->AddSpawnFlags( SF_NORESPAWN ); pExtraWearableItem->SetAlwaysAllow( true ); DispatchSpawn( pExtraWearableItem ); @@ -993,6 +1008,7 @@ void CTFWeaponBase::UpdateExtraWearables() pExtraWearableItem->PrecacheModel( pEconItemView->GetExtraWearableModel() ); } + pExtraWearableItem->SetDisguiseWearable(m_bDisguiseWeapon); pExtraWearableItem->AddSpawnFlags( SF_NORESPAWN ); pExtraWearableItem->SetAlwaysAllow( true ); DispatchSpawn( pExtraWearableItem ); @@ -2075,9 +2091,9 @@ void CTFWeaponBase::IncrementAmmo( void ) } else if ( !CheckReloadMisfire() ) { - if ( pPlayer && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) > 0 ) + if ( pPlayer && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) > 0 && ( m_iClip1 < GetMaxClip1() ) ) { - m_iClip1 = MIN( ( m_iClip1 + 1 ), GetMaxClip1() ); + m_iClip1++; pPlayer->RemoveAmmo( 1, m_iPrimaryAmmoType ); } } @@ -3285,6 +3301,87 @@ bool CTFWeaponBase::OnInternalDrawModel( ClientModelRenderInfo_t *pInfo ) return BaseClass::OnInternalDrawModel( pInfo ); } +//----------------------------------------------------------------------------- +// Purpose: Override for disguise weapons to use team 0 for attachment lookups +//----------------------------------------------------------------------------- +void CTFWeaponBase::UpdateAttachmentModels( void ) +{ +#ifdef CLIENT_DLL + // For disguise weapons, we need to use the disguise target's team when fetching attachment models + // because GetTeamNumber() returns the spy's team, not the disguised target's team. + if ( m_bDisguiseWeapon ) + { + C_TFPlayer *pOwner = ToTFPlayer( GetOwnerEntity() ); + if ( !pOwner ) + { + BaseClass::UpdateAttachmentModels(); + return; + } + + C_TFPlayer *pDisguiseTarget = pOwner->m_Shared.GetDisguiseTarget(); + int iTeamNumber = pDisguiseTarget ? pDisguiseTarget->GetTeamNumber() : 0; + + CEconItemView *pItem = GetAttributeContainer()->GetItem(); + GameItemDefinition_t *pItemDef = pItem && pItem->IsValid() ? pItem->GetStaticData() : NULL; + + // Update the state of additional model attachments + m_vecAttachedModels.Purge(); + if ( pItemDef && AttachmentModelsShouldBeVisible() ) + { + { + int iAttachedModels = pItemDef->GetNumAttachedModels( iTeamNumber ); + for ( int i = 0; i < iAttachedModels; i++ ) + { + attachedmodel_t *pModel = pItemDef->GetAttachedModelData( iTeamNumber, i ); + + int iModelIndex = modelinfo->GetModelIndex( pModel->m_pszModelName ); + if ( iModelIndex >= 0 ) + { + AttachedModelData_t attachedModelData; + attachedModelData.m_pModel = modelinfo->GetModel( iModelIndex ); + attachedModelData.m_iModelDisplayFlags = pModel->m_iModelDisplayFlags; + m_vecAttachedModels.AddToTail( attachedModelData ); + } + } + } + + // Check for Festive attachedmodels for festivized weapons + { + int iAttachedModels = pItemDef->GetNumAttachedModelsFestivized( iTeamNumber ); + if ( iAttachedModels ) + { + int iFestivized = 0; + CALL_ATTRIB_HOOK_INT( iFestivized, is_festivized ); + if ( iFestivized ) + { + for ( int i = 0; i < iAttachedModels; i++ ) + { + attachedmodel_t *pModel = pItemDef->GetAttachedModelDataFestivized( iTeamNumber, i ); + + int iModelIndex = modelinfo->GetModelIndex( pModel->m_pszModelName ); + if ( iModelIndex >= 0 ) + { + AttachedModelData_t attachedModelData; + attachedModelData.m_pModel = modelinfo->GetModel( iModelIndex ); + attachedModelData.m_iModelDisplayFlags = pModel->m_iModelDisplayFlags; + m_vecAttachedModels.AddToTail( attachedModelData ); + } + } + } + } + } + } + // Note: We skip the viewmodel attachment section (ShouldAttachToHands) because + // disguise weapons are world models only and don't need viewmodel attachments. + } + else + { + // Normal weapons use the base class implementation + BaseClass::UpdateAttachmentModels(); + } +#endif +} + void CTFWeaponBase::ProcessMuzzleFlashEvent( void ) { C_BaseAnimating *pAttachEnt = GetAppropriateWorldOrViewModel(); @@ -4956,6 +5053,7 @@ void CTFWeaponBase::ApplyOnHitAttributes( CBaseEntity *pVictimBaseEntity, CTFPla if ( pVictim && pVictim->IsPlayerClass( TF_CLASS_SPY ) && pVictim->m_Shared.InCond( TF_COND_DISGUISED ) && + ( pVictim->m_Shared.GetDisguiseTeam() != pVictim->GetTeamNumber() ) && !( pVictim->m_Shared.IsStealthed() || pVictim->m_Shared.InCond( TF_COND_STEALTHED_BLINK ) ) ) { flPercentage = 0.0f; @@ -5017,7 +5115,7 @@ void CTFWeaponBase::ApplyOnHitAttributes( CBaseEntity *pVictimBaseEntity, CTFPla } // On hit attributes don't work when you shoot disguised spies - if ( pVictim->m_Shared.InCond( TF_COND_DISGUISED ) ) + if ( pVictim->m_Shared.InCond( TF_COND_DISGUISED ) && ( pVictim->m_Shared.GetDisguiseTeam() != pVictim->GetTeamNumber() ) ) return; } @@ -5580,7 +5678,7 @@ bool CTFWeaponBase::IsViewModelFlipped( void ) return true; } #else - if ( m_bFlipViewModel != cl_flipviewmodels.GetBool() ) + if ( m_bFlipViewModel != TeamFortress_ShouldFlipClientViewModel() ) { return true; } @@ -6761,7 +6859,7 @@ void CTFWeaponBase::AddStatTrakModel( CEconItemView *pItem, int nStatTrakType, A pStatTrakEnt->m_nSkin = nSkin; m_viewmodelStatTrakAddon = pStatTrakEnt; - if ( cl_flipviewmodels.GetBool() ) + if ( TeamFortress_ShouldFlipClientViewModel() ) { pStatTrakEnt->SetBodygroup( 1, 1 ); // use a special mirror-image stattrak module that appears correct for lefties flScale *= -1.0f; // flip scale diff --git a/game/shared/tf/tf_weaponbase.h b/game/shared/tf/tf_weaponbase.h index bdf09634..22b82e8f 100644 --- a/game/shared/tf/tf_weaponbase.h +++ b/game/shared/tf/tf_weaponbase.h @@ -282,6 +282,7 @@ class CTFWeaponBase : public CBaseCombatWeapon, public IHasOwner, public IHasGen virtual void Spawn(); virtual void Activate( void ); + virtual void GiveDefaultAmmo( void ); virtual void Precache(); virtual bool IsPredicted() const { return true; } virtual void FallInit( void ); @@ -335,6 +336,7 @@ class CTFWeaponBase : public CBaseCombatWeapon, public IHasOwner, public IHasGen void EnableDuck(); void DisableDuck(); + virtual bool OwnerCanJump( void ) { return true; } virtual bool OwnerCanTaunt( void ) { return true; } virtual bool CanBeCritBoosted( void ); bool CanHaveRevengeCrits( void ); @@ -584,6 +586,7 @@ class CTFWeaponBase : public CBaseCombatWeapon, public IHasOwner, public IHasGen virtual float CalcViewmodelBob( void ); BobState_t *GetBobState(); virtual bool AttachmentModelsShouldBeVisible( void ) OVERRIDE { return (m_iState == WEAPON_IS_ACTIVE) && !IsBeingRepurposedForTaunt(); } + virtual void UpdateAttachmentModels( void ) OVERRIDE; virtual bool ShouldEjectBrass() { return true; } diff --git a/game/shared/util_shared.h b/game/shared/util_shared.h index e27ffc50..15dcfa18 100644 --- a/game/shared/util_shared.h +++ b/game/shared/util_shared.h @@ -693,4 +693,11 @@ const char *UTIL_GetActiveOperationString(); const char *GetCleanMapName( const char *pszUnCleanMapName, char (&pszTmp)[256] ); +inline bool MapHasPrefix( const char *pszUnCleanMapName, const char *prefix ) +{ + char maptmp[ 256 ]; + const char *pszCleanMapName = GetCleanMapName( pszUnCleanMapName, maptmp ); + + return StringHasPrefix( pszCleanMapName, prefix ); +} #endif // UTIL_SHARED_H diff --git a/game/shared/voice_status.cpp b/game/shared/voice_status.cpp index 0272c554..e31fc4b5 100644 --- a/game/shared/voice_status.cpp +++ b/game/shared/voice_status.cpp @@ -378,7 +378,7 @@ void CVoiceStatus::UpdateServerState(bool bForce) player_info_t pi; - if ( !engine->GetPlayerInfo( i+1, &pi ) ) + if ( !engine->GetPlayerInfo( playerIndex + 1, &pi ) ) continue; if ( m_BanMgr.GetPlayerBan( pi.guid ) ) diff --git a/launcher_main/launcher_main_mod_hl2mp.rc b/launcher_main/launcher_main_mod_hl2mp.rc index 3ed87cf9..c6cec134 100644 --- a/launcher_main/launcher_main_mod_hl2mp.rc +++ b/launcher_main/launcher_main_mod_hl2mp.rc @@ -7,7 +7,7 @@ // // Generated from the TEXTINCLUDE 2 resource. // -#include "afxres.h" +#include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS @@ -43,7 +43,7 @@ END 2 TEXTINCLUDE DISCARDABLE BEGIN - "#include ""afxres.h""\r\n" + "#include ""winres.h""\r\n" "\0" END diff --git a/launcher_main/launcher_main_mod_tf.rc b/launcher_main/launcher_main_mod_tf.rc index c9a67f64..ad8f1442 100644 --- a/launcher_main/launcher_main_mod_tf.rc +++ b/launcher_main/launcher_main_mod_tf.rc @@ -7,7 +7,7 @@ // // Generated from the TEXTINCLUDE 2 resource. // -#include "afxres.h" +#include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS @@ -43,7 +43,7 @@ END 2 TEXTINCLUDE DISCARDABLE BEGIN - "#include ""afxres.h""\r\n" + "#include ""winres.h""\r\n" "\0" END diff --git a/lib/common/x64/2015/release/bzip2.lib b/lib/common/x64/2015/release/bzip2.lib index f4dae722..8c23813f 100644 Binary files a/lib/common/x64/2015/release/bzip2.lib and b/lib/common/x64/2015/release/bzip2.lib differ diff --git a/lib/common/x64/2015/release/jpeglib.lib b/lib/common/x64/2015/release/jpeglib.lib index 90565dc7..f904fba8 100644 Binary files a/lib/common/x64/2015/release/jpeglib.lib and b/lib/common/x64/2015/release/jpeglib.lib differ diff --git a/lib/common/x64/2015/release/libspng.lib b/lib/common/x64/2015/release/libspng.lib index 5c0c0920..a3bd8b31 100644 Binary files a/lib/common/x64/2015/release/libspng.lib and b/lib/common/x64/2015/release/libspng.lib differ diff --git a/lib/common/x64/2015/release/lzma.lib b/lib/common/x64/2015/release/lzma.lib index 85fb39b6..c18cabc9 100644 Binary files a/lib/common/x64/2015/release/lzma.lib and b/lib/common/x64/2015/release/lzma.lib differ diff --git a/lib/common/x64/2015/release/replay_common.lib b/lib/common/x64/2015/release/replay_common.lib index 7e7bf217..dc02a858 100644 Binary files a/lib/common/x64/2015/release/replay_common.lib and b/lib/common/x64/2015/release/replay_common.lib differ diff --git a/lib/public/linux/tier1_i486.a b/lib/public/linux/tier1_i486.a index f98ae8ad..a3b03806 100644 Binary files a/lib/public/linux/tier1_i486.a and b/lib/public/linux/tier1_i486.a differ diff --git a/lib/public/linux64/appframework.a b/lib/public/linux64/appframework.a index 43bcf5c8..5bcc040e 100644 Binary files a/lib/public/linux64/appframework.a and b/lib/public/linux64/appframework.a differ diff --git a/lib/public/linux64/gcsdk_sdk.a b/lib/public/linux64/gcsdk_sdk.a index 5db1cf04..15247bcc 100644 Binary files a/lib/public/linux64/gcsdk_sdk.a and b/lib/public/linux64/gcsdk_sdk.a differ diff --git a/lib/public/linux64/libtier0.so b/lib/public/linux64/libtier0.so index cff47733..6f14651e 100644 Binary files a/lib/public/linux64/libtier0.so and b/lib/public/linux64/libtier0.so differ diff --git a/lib/public/linux64/particles.a b/lib/public/linux64/particles.a index 4e46ed8d..d12587ad 100644 Binary files a/lib/public/linux64/particles.a and b/lib/public/linux64/particles.a differ diff --git a/lib/public/linux64/tier1.a b/lib/public/linux64/tier1.a index afd65298..bec357f9 100644 Binary files a/lib/public/linux64/tier1.a and b/lib/public/linux64/tier1.a differ diff --git a/lib/public/linux64/tier3.a b/lib/public/linux64/tier3.a index bc5f0879..d00f17c4 100644 Binary files a/lib/public/linux64/tier3.a and b/lib/public/linux64/tier3.a differ diff --git a/lib/public/x64/appframework.lib b/lib/public/x64/appframework.lib index 3f21cbd3..1f8b535e 100644 Binary files a/lib/public/x64/appframework.lib and b/lib/public/x64/appframework.lib differ diff --git a/lib/public/x64/bitmap.lib b/lib/public/x64/bitmap.lib index 1534065c..238fd3a9 100644 Binary files a/lib/public/x64/bitmap.lib and b/lib/public/x64/bitmap.lib differ diff --git a/lib/public/x64/choreoobjects.lib b/lib/public/x64/choreoobjects.lib index 44a2cb42..eb962a53 100644 Binary files a/lib/public/x64/choreoobjects.lib and b/lib/public/x64/choreoobjects.lib differ diff --git a/lib/public/x64/datamodel.lib b/lib/public/x64/datamodel.lib index 17f4105c..18339b54 100644 Binary files a/lib/public/x64/datamodel.lib and b/lib/public/x64/datamodel.lib differ diff --git a/lib/public/x64/dmxloader.lib b/lib/public/x64/dmxloader.lib index 71c0c714..385d949b 100644 Binary files a/lib/public/x64/dmxloader.lib and b/lib/public/x64/dmxloader.lib differ diff --git a/lib/public/x64/gcsdk_sdk.lib b/lib/public/x64/gcsdk_sdk.lib index d886d0e8..e71666c8 100644 Binary files a/lib/public/x64/gcsdk_sdk.lib and b/lib/public/x64/gcsdk_sdk.lib differ diff --git a/lib/public/x64/libz.lib b/lib/public/x64/libz.lib index 126668a3..26327f81 100644 Binary files a/lib/public/x64/libz.lib and b/lib/public/x64/libz.lib differ diff --git a/lib/public/x64/particles.lib b/lib/public/x64/particles.lib index e85d3fca..d2315f4d 100644 Binary files a/lib/public/x64/particles.lib and b/lib/public/x64/particles.lib differ diff --git a/lib/public/x64/shaderlib.lib b/lib/public/x64/shaderlib.lib index 11c8edb2..d464f8a4 100644 Binary files a/lib/public/x64/shaderlib.lib and b/lib/public/x64/shaderlib.lib differ diff --git a/lib/public/x64/tier1.lib b/lib/public/x64/tier1.lib index 79ed01d6..84b9b933 100644 Binary files a/lib/public/x64/tier1.lib and b/lib/public/x64/tier1.lib differ diff --git a/lib/public/x64/tier2.lib b/lib/public/x64/tier2.lib index ca099d39..8e018063 100644 Binary files a/lib/public/x64/tier2.lib and b/lib/public/x64/tier2.lib differ diff --git a/lib/public/x64/tier3.lib b/lib/public/x64/tier3.lib index 5ead1878..8b9832f3 100644 Binary files a/lib/public/x64/tier3.lib and b/lib/public/x64/tier3.lib differ diff --git a/lib/public/x64/vpklib.lib b/lib/public/x64/vpklib.lib index 7eeff88e..471e7c25 100644 Binary files a/lib/public/x64/vpklib.lib and b/lib/public/x64/vpklib.lib differ diff --git a/lib/public/x64/vtf.lib b/lib/public/x64/vtf.lib index b797e77b..1230fb33 100644 Binary files a/lib/public/x64/vtf.lib and b/lib/public/x64/vtf.lib differ diff --git a/lib/public/x86/tier1.lib b/lib/public/x86/tier1.lib index 994c4014..359783e0 100644 Binary files a/lib/public/x86/tier1.lib and b/lib/public/x86/tier1.lib differ diff --git a/materialsystem/stdshaders/worldtwotextureblend_ps2x.fxc b/materialsystem/stdshaders/worldtwotextureblend_ps2x.fxc index 14ba7826..688517ec 100644 --- a/materialsystem/stdshaders/worldtwotextureblend_ps2x.fxc +++ b/materialsystem/stdshaders/worldtwotextureblend_ps2x.fxc @@ -155,7 +155,7 @@ float4 main( PS_INPUT i ) : COLOR if( bFlashlight ) { float3 worldSpaceNormal; - // Make the unbumped version not so fucking stupid and not need tangentSpaceTranspose you knob. + // Make the unbumped version not need tangentSpaceTranspose worldSpaceNormal = mul( normal, i.tangentSpaceTranspose ); int nShadowSampleLevel = 0; diff --git a/mathlib/mathlib_base.cpp b/mathlib/mathlib_base.cpp index 0c3c37e1..61d67797 100644 --- a/mathlib/mathlib_base.cpp +++ b/mathlib/mathlib_base.cpp @@ -2500,7 +2500,7 @@ float Hermite_Spline( } -void Hermite_SplineBasis( float t, float basis[] ) +void Hermite_SplineBasis( float t, float basis[4] ) { float tSqr = t*t; float tCube = t*tSqr; diff --git a/public/basehandle.h b/public/basehandle.h index 29337ce7..6cb9019f 100644 --- a/public/basehandle.h +++ b/public/basehandle.h @@ -33,8 +33,6 @@ friend class CBaseEntityList; public: - // HACK HACK FOR SOURCEMOD - CBaseHandle(int index); CBaseHandle(); CBaseHandle( INVALID_EHANDLE_tag ); CBaseHandle( const CBaseHandle &other ); @@ -85,11 +83,6 @@ protected: #include "ihandleentity.h" -// HACK HACK FOR SOURCEMOD -inline CBaseHandle::CBaseHandle(int index) -{ - m_Index = index; -} inline CBaseHandle::CBaseHandle() { diff --git a/public/bitmap/imageformat.h b/public/bitmap/imageformat.h index afb75e64..394e8bc6 100644 --- a/public/bitmap/imageformat.h +++ b/public/bitmap/imageformat.h @@ -376,7 +376,7 @@ namespace ImageLoader struct ResampleInfo_t { - ResampleInfo_t() : m_nSrcDepth(1), m_nDestDepth(1), m_flAlphaThreshhold(0.4f), m_flAlphaHiFreqThreshhold(0.4f), m_nFlags(0) + ResampleInfo_t() : m_nFlags(0), m_flAlphaThreshhold(0.4f), m_flAlphaHiFreqThreshhold(0.4f), m_nSrcDepth(1), m_nDestDepth(1) { m_flColorScale[0] = 1.0f, m_flColorScale[1] = 1.0f, m_flColorScale[2] = 1.0f, m_flColorScale[3] = 1.0f; m_flColorGoal[0] = 0.0f, m_flColorGoal[1] = 0.0f, m_flColorGoal[2] = 0.0f, m_flColorGoal[3] = 0.0f; diff --git a/public/bitvec.h b/public/bitvec.h index 6e4c7ba0..a1a984d0 100644 --- a/public/bitvec.h +++ b/public/bitvec.h @@ -448,7 +448,7 @@ typedef CBitVec<32> CDWordBitVec; template inline CVarBitVecBase::CVarBitVecBase() { - Plat_FastMemset( (void*)this, 0, sizeof( *this ) ); + Plat_FastMemset( this, 0, sizeof( *this ) ); } //----------------------------------------------------------------------------- @@ -479,7 +479,7 @@ inline CVarBitVecBase::CVarBitVecBase( const CVarBitVecBase::Detach( uint32 **ppBits, int *pNumBits free( m_pInt ); } - memset( (void *)this, 0, sizeof( *this ) ); + memset( this, 0, sizeof( *this ) ); return true; } diff --git a/public/bspfile.h b/public/bspfile.h index 9fcc8884..e39ec4a6 100644 --- a/public/bspfile.h +++ b/public/bspfile.h @@ -786,6 +786,7 @@ struct dfaceid_t }; + // NOTE: Only 7-bits stored!!! #define LEAF_FLAGS_SKY 0x01 // This leaf has 3D sky in its PVS #define LEAF_FLAGS_RADIAL 0x02 // This leaf culled away some portals due to radial vis diff --git a/public/const.h b/public/const.h index 256dff2d..84f28527 100644 --- a/public/const.h +++ b/public/const.h @@ -121,7 +121,7 @@ #define FL_INWATER (1<<9) // In water // NOTE if you move things up, make sure to change this value -#define PLAYER_FLAG_BITS 10 +#define PLAYER_FLAG_BITS 32 #define FL_FLY (1<<10) // Changes the SV_Movestep() behavior to not need to be on ground #define FL_SWIM (1<<11) // Changes the SV_Movestep() behavior to not need to be on ground (but stay in water) @@ -163,7 +163,7 @@ #define FL_INWATER (1<<10) // In water // NOTE if you move things up, make sure to change this value -#define PLAYER_FLAG_BITS 11 +#define PLAYER_FLAG_BITS 32 #define FL_FLY (1<<11) // Changes the SV_Movestep() behavior to not need to be on ground #define FL_SWIM (1<<12) // Changes the SV_Movestep() behavior to not need to be on ground (but stay in water) diff --git a/public/eifacev21.h b/public/eifacev21.h new file mode 100644 index 00000000..7bb36cc5 --- /dev/null +++ b/public/eifacev21.h @@ -0,0 +1,614 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Defines entity interface between engine and DLLs. +// This header file included by engine files and DLL files. +// +// Before including this header, DLLs must: +// include edict.h +// This is conveniently done for them in extdll.h +// +// $NoKeywords: $ +// +//============================================================================= + +#ifndef EIFACEV21_H +#define EIFACEV21_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "convar.h" +#include "icvar.h" +#include "edict.h" +#include "iserverentity.h" +#include "engine/ivmodelinfo.h" +#include "soundflags.h" +#include "bitvec.h" + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +class SendTable; +class ServerClass; +class IMoveHelper; +struct Ray_t; +class CGameTrace; +typedef CGameTrace trace_t; +struct typedescription_t; +class CSaveRestoreData; +struct datamap_t; +class SendTable; +class ServerClass; +class IMoveHelper; +struct Ray_t; +struct studiohdr_t; +class CBaseEntity; +class CRestore; +class CSave; +class variant_t; +struct vcollide_t; +class bf_read; +class bf_write; +class IRecipientFilter; +class CBaseEntity; +class ITraceFilter; +struct client_textmessage_t; +class INetChannelInfo; +class ISpatialPartition; +class IScratchPad3D; +class CStandardSendProxiesV1; + + +// Terrain Modification Types +enum TerrainModType +{ + TMod_Sphere = 0, // sphere that pushes all vertices out along their normal. + TMod_Suck, + TMod_AABB +}; + +class CTerrainModParams +{ +public: + + // Flags for m_Flags. + enum + { + TMOD_SUCKTONORMAL = ( 1 << 0 ), // For TMod_Suck, suck into m_Normal rather than on +Z. + TMOD_STAYABOVEORIGINAL = ( 1 << 1 ) // For TMod_Suck, don't go below the original vert on Z. + }; + + CTerrainModParams() { m_Flags = 0; } // people always forget to init this + + Vector m_vCenter; + Vector m_vNormal; // If TMod_Suck and TMOD_SUCKTONORMAL is set. + int m_Flags; // Combination of TMOD_ flags. + float m_flRadius; + Vector m_vecMin; // Bounding box. + Vector m_vecMax; + float m_flStrength; // for TMod_Suck + float m_flMorphTime; // time over which the morph takes place +}; + +class CSpeculativeTerrainModVert +{ +public: + Vector m_vOriginal; // vertex position before any mods + Vector m_vCurrent; // current vertex position + Vector m_vNew; // vertex position if the mod were applied +}; + +//----------------------------------------------------------------------------- +// Terrain modification interface +//----------------------------------------------------------------------------- +class ITerrainMod +{ +public: + + //--------------------------------------------------------------------- + // Initialize the terrain modifier. + //--------------------------------------------------------------------- + virtual void Init( const CTerrainModParams ¶ms ) = 0; + + //--------------------------------------------------------------------- + // Apply the terrain modifier to the surface. The vertex should be + // moved from its original position to the target position. + // Return true if the position is modified. + //--------------------------------------------------------------------- + virtual bool ApplyMod( Vector &vecTargetPos, Vector const &vecOriginalPos ) = 0; + + //--------------------------------------------------------------------- + // Apply the terrain modifier to the surface. The vertex should from + // its original position toward the target position bassed on the + // morph time. + // Return true if the posistion is modified. + //--------------------------------------------------------------------- + virtual bool ApplyModAtMorphTime( Vector &vecTargetPos, const Vector&vecOriginalPos, + float flCurrentTime, float flMorphTime ) = 0; + + //--------------------------------------------------------------------- + // Get the bounding box for things that this mod can affect (note that + // it CAN move things outside of this bounding box). + //--------------------------------------------------------------------- + virtual void GetBBox( Vector &vecBBMin, Vector &vecBBMax ) = 0; +}; + + + +//----------------------------------------------------------------------------- +// Purpose: Interface the engine exposes to the game DLL +//----------------------------------------------------------------------------- +#define VENGINESERVER_INTERFACEVERSION_21 "VEngineServer021" + +namespace VEngineServerV21 +{ + +abstract_class IVEngineServer +{ +public: + // Tell engine to change level ( "changelevel s1\n" or "changelevel2 s1 s2\n" ) + virtual void ChangeLevel( const char *s1, const char *s2 ) = 0; + + // Ask engine whether the specified map is a valid map file (exists and has valid version number). + virtual int IsMapValid( const char *filename ) = 0; + + // Is this a dedicated server? + virtual bool IsDedicatedServer( void ) = 0; + + // Is in Hammer editing mode? + virtual int IsInEditMode( void ) = 0; + + // Add to the server/client lookup/precache table, the specified string is given a unique index + // NOTE: The indices for PrecacheModel are 1 based + // a 0 returned from those methods indicates the model or sound was not correctly precached + // However, generic and decal are 0 based + // If preload is specified, the file is loaded into the server/client's cache memory before level startup, otherwise + // it'll only load when actually used (which can cause a disk i/o hitch if it occurs during play of a level). + virtual int PrecacheModel( const char *s, bool preload = false ) = 0; + virtual int PrecacheSentenceFile( const char *s, bool preload = false ) = 0; + virtual int PrecacheDecal( const char *name, bool preload = false ) = 0; + virtual int PrecacheGeneric( const char *s, bool preload = false ) = 0; + + // Check's if the name is precached, but doesn't actually precache the name if not... + virtual bool IsModelPrecached( char const *s ) const = 0; + virtual bool IsDecalPrecached( char const *s ) const = 0; + virtual bool IsGenericPrecached( char const *s ) const = 0; + + // Note that sounds are precached using the IEngineSound interface + + // Special purpose PVS checking + // Get the cluster # for the specified position + virtual int GetClusterForOrigin( const Vector &org ) = 0; + // Get the PVS bits for a specified cluster and copy the bits into outputpvs. Returns the number of bytes needed to pack the PVS + virtual int GetPVSForCluster( int cluster, int outputpvslength, unsigned char *outputpvs ) = 0; + // Check whether the specified origin is inside the specified PVS + virtual bool CheckOriginInPVS( const Vector &org, const unsigned char *checkpvs, int checkpvssize ) = 0; + // Check whether the specified worldspace bounding box is inside the specified PVS + virtual bool CheckBoxInPVS( const Vector &mins, const Vector &maxs, const unsigned char *checkpvs, int checkpvssize ) = 0; + + // Returns the server assigned userid for this player. Useful for logging frags, etc. + // returns -1 if the edict couldn't be found in the list of players. + virtual int GetPlayerUserId( const edict_t *e ) = 0; + virtual const char *GetPlayerNetworkIDString( const edict_t *e ) = 0; + + // Return the current number of used edict slots + virtual int GetEntityCount( void ) = 0; + // Given an edict, returns the entity index + virtual int IndexOfEdict( const edict_t *pEdict ) = 0; + // Given and entity index, returns the corresponding edict pointer + virtual edict_t *PEntityOfEntIndex( int iEntIndex ) = 0; + + // Get stats info interface for a client netchannel + virtual INetChannelInfo* GetPlayerNetInfo( int playerIndex ) = 0; + + // Allocate space for string and return index/offset of string in global string list + // If iForceEdictIndex is not -1, then it will return the edict with that index. If that edict index + // is already used, it'll return null. + virtual edict_t *CreateEdict( int iForceEdictIndex = -1 ) = 0; + // Remove the specified edict and place back into the free edict list + virtual void RemoveEdict( edict_t *e ) = 0; + + // Memory allocation for entity class data + virtual void *PvAllocEntPrivateData( long cb ) = 0; + virtual void FreeEntPrivateData( void *pEntity ) = 0; + + // Save/restore uses a special memory allocator (which zeroes newly allocated memory, etc.) + virtual void *SaveAllocMemory( size_t num, size_t size ) = 0; + virtual void SaveFreeMemory( void *pSaveMem ) = 0; + + // Emit an ambient sound associated with the specified entity + virtual void EmitAmbientSound( int entindex, const Vector &pos, const char *samp, float vol, soundlevel_t soundlevel, int fFlags, int pitch, float delay = 0.0f ) = 0; + + // Fade out the client's volume level toward silence (or fadePercent) + virtual void FadeClientVolume( const edict_t *pEdict, float fadePercent, float fadeOutSeconds, float holdTime, float fadeInSeconds ) = 0; + + // Sentences / sentence groups + virtual int SentenceGroupPick( int groupIndex, char *name, int nameBufLen ) = 0; + virtual int SentenceGroupPickSequential( int groupIndex, char *name, int nameBufLen, int sentenceIndex, int reset ) = 0; + virtual int SentenceIndexFromName( const char *pSentenceName ) = 0; + virtual const char *SentenceNameFromIndex( int sentenceIndex ) = 0; + virtual int SentenceGroupIndexFromName( const char *pGroupName ) = 0; + virtual const char *SentenceGroupNameFromIndex( int groupIndex ) = 0; + virtual float SentenceLength( int sentenceIndex ) = 0; + + // Issue a command to the command parser as if it was typed at the server console. + virtual void ServerCommand( const char *str ) = 0; + // Execute any commands currently in the command parser immediately (instead of once per frame) + virtual void ServerExecute( void ) = 0; + // Issue the specified command to the specified client (mimics that client typing the command at the console). + virtual void ClientCommand( edict_t *pEdict, PRINTF_FORMAT_STRING const char *szFmt, ... ) = 0; + + // Set the lightstyle to the specified value and network the change to any connected clients. Note that val must not + // change place in memory (use MAKE_STRING) for anything that's not compiled into your mod. + virtual void LightStyle( int style, const char *val ) = 0; + + // Project a static decal onto the specified entity / model (for level placed decals in the .bsp) + virtual void StaticDecal( const Vector &originInEntitySpace, int decalIndex, int entityIndex, int modelIndex, bool lowpriority ) = 0; + + // Given the current PVS(or PAS) and origin, determine which players should hear/receive the message + virtual void Message_DetermineMulticastRecipients( bool usepas, const Vector& origin, CBitVec< ABSOLUTE_PLAYER_LIMIT >& playerbits ) = 0; + + // Begin a message from a server side entity to its client side counterpart (func_breakable glass, e.g.) + virtual bf_write *EntityMessageBegin( int ent_index, ServerClass * ent_class, bool reliable ) = 0; + // Begin a usermessage from the server to the client .dll + virtual bf_write *UserMessageBegin( IRecipientFilter *filter, int msg_type ) = 0; + // Finish the Entity or UserMessage and dispatch to network layer + virtual void MessageEnd( void ) = 0; + + // Print szMsg to the client console. + virtual void ClientPrintf( edict_t *pEdict, const char *szMsg ) = 0; + + // SINGLE PLAYER/LISTEN SERVER ONLY (just matching the client .dll api for this) + // Prints the formatted string to the notification area of the screen ( down the right hand edge + // numbered lines starting at position 0 + virtual void Con_NPrintf( int pos, PRINTF_FORMAT_STRING const char *fmt, ... ) = 0; + // SINGLE PLAYER/LISTEN SERVER ONLY(just matching the client .dll api for this) + // Similar to Con_NPrintf, but allows specifying custom text color and duration information + virtual void Con_NXPrintf( const struct con_nprint_s *info, PRINTF_FORMAT_STRING const char *fmt, ... ) = 0; + + // For ConCommand parsing or parsing client commands issued by players typing at their console + // Retrieves the raw command string (untokenized) + virtual const char *Cmd_Args( void ) = 0; + // Returns the number of tokens in the command string + virtual int Cmd_Argc( void ) = 0; + // Retrieves a specified token + virtual char *Cmd_Argv( int argc ) = 0; + + // Change a specified player's "view entity" (i.e., use the view entity position/orientation for rendering the client view) + virtual void SetView( const edict_t *pClient, const edict_t *pViewent ) = 0; + + // Get a high precision timer for doing profiling work + virtual float Time( void ) = 0; + + // Set the player's crosshair angle + virtual void CrosshairAngle( const edict_t *pClient, float pitch, float yaw ) = 0; + + // Get the current game directory (hl2, tf2, hl1, cstrike, etc.) + virtual void GetGameDir( char *szGetGameDir, int maxlength ) = 0; + + // Used by AI node graph code to determine if .bsp and .ain files are out of date + virtual int CompareFileTime( const char *filename1, const char *filename2, int *iCompare ) = 0; + + // Locks/unlocks the network string tables (.e.g, when adding bots to server, this needs to happen). + // Be sure to reset the lock after executing your code!!! + virtual bool LockNetworkStringTables( bool lock ) = 0; + + // Create a bot with the given name. Returns NULL if fake client can't be created + virtual edict_t *CreateFakeClient( const char *netname ) = 0; + + // Get a convar keyvalue for s specified client + virtual const char *GetClientConVarValue( int clientIndex, const char *name ) = 0; + + // Parse a token from a file + virtual const char *ParseFile( const char *data, char *token, int maxlen ) = 0; + // Copies a file + virtual bool CopyFile( const char *source, const char *destination ) = 0; + + // Reset the pvs, pvssize is the size in bytes of the buffer pointed to by pvs. + // This should be called right before any calls to AddOriginToPVS + virtual void ResetPVS( byte *pvs, int pvssize ) = 0; + // Merge the pvs bits into the current accumulated pvs based on the specified origin ( not that each pvs origin has an 8 world unit fudge factor ) + virtual void AddOriginToPVS( const Vector &origin ) = 0; + // Mark a specified area portal as open/closes + virtual void SetAreaPortalState( int portalNumber, int isOpen ) = 0; + // Queue a temp entity for transmission + virtual void PlaybackTempEntity( IRecipientFilter& filter, float delay, const void *pSender, const SendTable *pST, int classID ) = 0; + // Given a node number and the specified PVS, return with the node is in the PVS + virtual int CheckHeadnodeVisible( int nodenum, const byte *pvs, int vissize ) = 0; + // Using area bits, cheeck whether area1 flows into area2 and vice versa (depends on area portal state) + virtual int CheckAreasConnected( int area1, int area2 ) = 0; + // Given an origin, determine which area index the origin is within + virtual int GetArea( const Vector &origin ) = 0; + // Get area portal bit set + virtual void GetAreaBits( int area, unsigned char *bits, int buflen ) = 0; + // Given a view origin (which tells us the area to start looking in) and a portal key, + // fill in the plane that leads out of this area (it points into whatever area it leads to). + virtual bool GetAreaPortalPlane( Vector const &vViewOrigin, int portalKey, VPlane *pPlane ) = 0; + + // Apply a modification to the terrain. + virtual void ApplyTerrainMod( TerrainModType type, CTerrainModParams const ¶ms ) = 0; + + // Save/restore wrapper - FIXME: At some point we should move this to it's own interface + virtual bool LoadGameState( char const *pMapName, bool createPlayers ) = 0; + virtual void LoadAdjacentEnts( const char *pOldLevel, const char *pLandmarkName ) = 0; + virtual void ClearSaveDir() = 0; + + // Get the pristine map entity lump string. (e.g., used by CS to reload the map entities when restarting a round.) + virtual const char* GetMapEntitiesString() = 0; + + // Text message system -- lookup the text message of the specified name + virtual client_textmessage_t *TextMessageGet( const char *pName ) = 0; + + // Print a message to the server log file + virtual void LogPrint( const char *msg ) = 0; + + // Builds PVS information for an entity + virtual void BuildEntityClusterList( edict_t *pEdict, PVSInfo_t *pPVSInfo ) = 0; + + // A solid entity moved, update spatial partition + virtual void SolidMoved( edict_t *pSolidEnt, ICollideable *pSolidCollide, const Vector* pPrevAbsOrigin ) = 0; + // A trigger entity moved, update spatial partition + virtual void TriggerMoved( edict_t *pTriggerEnt ) = 0; + + // Create/destroy a custom spatial partition + virtual ISpatialPartition *CreateSpatialPartition( const Vector& worldmin, const Vector& worldmax ) = 0; + virtual void DestroySpatialPartition( ISpatialPartition * ) = 0; + + // Draw the brush geometry in the map into the scratch pad. + // Flags is currently unused. + virtual void DrawMapToScratchPad( IScratchPad3D *pPad, unsigned long iFlags ) = 0; + + // This returns which entities, to the best of the server's knowledge, the client currently knows about. + // This is really which entities were in the snapshot that this client last acked. + // This returns a bit vector with one bit for each entity. + // + // USE WITH CARE. Whatever tick the client is really currently on is subject to timing and + // ordering differences, so you should account for about a quarter-second discrepancy in here. + // Also, this will return NULL if the client doesn't exist or if this client hasn't acked any frames yet. + // + // iClientIndex is the CLIENT index, so if you use pPlayer->entindex(), subtract 1. + virtual const CBitVec* GetEntityTransmitBitsForClient( int iClientIndex ) = 0; + + // Is the game paused? + virtual bool IsPaused() = 0; + + // Marks the filename for consistency checking. This should be called after precaching the file. + virtual void ForceExactFile( const char *s ) = 0; + virtual void ForceModelBounds( const char *s, const Vector &mins, const Vector &maxs ) = 0; + virtual void ClearSaveDirAfterClientLoad() = 0; + + // Sets a USERINFO client ConVar for a fakeclient + virtual void SetFakeClientConVarValue( edict_t *pEntity, const char *cvar, const char *value ) = 0; + + virtual void InsertServerCommand( const char *str ) = 0; + + // Marks the material (vmt file) for consistency checking. If the client and server have different + // contents for the file, the client's vmt can only use the VertexLitGeneric shader, and can only + // contain $baseTexture and $bumpmap vars. + virtual void ForceSimpleMaterial( const char *s ) = 0; + + + // Is the engine in Commentary mode? + virtual int IsInCommentaryMode( void ) = 0; +}; + +} // end namespace + + +//----------------------------------------------------------------------------- +// Purpose: These are the interfaces that the game .dll exposes to the engine +//----------------------------------------------------------------------------- +#define SERVERGAMEDLL_INTERFACEVERSION_3 "ServerGameDLL003" + +namespace ServerGameDLLV3 +{ + +abstract_class IServerGameDLL +{ +public: + // Initialize the game (one-time call when the DLL is first loaded ) + // Return false if there is an error during startup. + virtual bool DLLInit( CreateInterfaceFn engineFactory, + CreateInterfaceFn physicsFactory, + CreateInterfaceFn fileSystemFactory, + CGlobalVars *pGlobals) = 0; + + // This is called when a new game is started. (restart, map) + virtual bool GameInit( void ) = 0; + + // Called any time a new level is started (after GameInit() also on level transitions within a game) + virtual bool LevelInit( char const *pMapName, + char const *pMapEntities, char const *pOldLevel, + char const *pLandmarkName, bool loadGame, bool background ) = 0; + + // The server is about to activate + virtual void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) = 0; + + // The server should run physics/think on all edicts + virtual void GameFrame( bool simulating ) = 0; + + // Called once per simulation frame on the final tick + virtual void PreClientUpdate( bool simulating ) = 0; + + // Called when a level is shutdown (including changing levels) + virtual void LevelShutdown( void ) = 0; + // This is called when a game ends (server disconnect, death, restart, load) + // NOT on level transitions within a game + virtual void GameShutdown( void ) = 0; + + // Called once during DLL shutdown + virtual void DLLShutdown( void ) = 0; + + // Get the simulation interval (must be compiled with identical values into both client and game .dll for MOD!!!) + // Right now this is only requested at server startup time so it can't be changed on the fly, etc. + virtual float GetTickInterval( void ) const = 0; + + // Give the list of datatable classes to the engine. The engine matches class names from here with + // edict_t::classname to figure out how to encode a class's data for networking + virtual ServerClass* GetAllServerClasses( void ) = 0; + + // Returns string describing current .dll. e.g., TeamFortress 2, Half-Life 2. + // Hey, it's more descriptive than just the name of the game directory + virtual const char *GetGameDescription( void ) = 0; + + // Let the game .dll allocate it's own network/shared string tables + virtual void CreateNetworkStringTables( void ) = 0; + + // Save/restore system hooks + virtual CSaveRestoreData *SaveInit( int size ) = 0; + virtual void SaveWriteFields( CSaveRestoreData *, const char *, void *, datamap_t *, typedescription_t *, int ) = 0; + virtual void SaveReadFields( CSaveRestoreData *, const char *, void *, datamap_t *, typedescription_t *, int ) = 0; + virtual void SaveGlobalState( CSaveRestoreData * ) = 0; + virtual void RestoreGlobalState( CSaveRestoreData * ) = 0; + virtual void PreSave( CSaveRestoreData * ) = 0; + virtual void Save( CSaveRestoreData * ) = 0; + virtual void GetSaveComment( char *comment, int maxlength ) = 0; + virtual void WriteSaveHeaders( CSaveRestoreData * ) = 0; + virtual void ReadRestoreHeaders( CSaveRestoreData * ) = 0; + virtual void Restore( CSaveRestoreData *, bool ) = 0; + virtual bool IsRestoring() = 0; + + // Returns the number of entities moved across the transition + virtual int CreateEntityTransitionList( CSaveRestoreData *, int ) = 0; + // Build the list of maps adjacent to the current map + virtual void BuildAdjacentMapList( void ) = 0; + + // Retrieve info needed for parsing the specified user message + virtual bool GetUserMessageInfo( int msg_type, char *name, int maxnamelength, int& size ) = 0; + + // Hand over the StandardSendProxies in the game DLL's module. + virtual CStandardSendProxiesV1* GetStandardSendProxies() = 0; +}; + +} // end namespace + + +//----------------------------------------------------------------------------- +// Just an interface version name for the random number interface +// See vstdlib/random.h for the interface definition +// NOTE: If you change this, also change VENGINE_CLIENT_RANDOM_INTERFACE_VERSION in cdll_int.h +//----------------------------------------------------------------------------- +#define VENGINE_SERVER_RANDOM_INTERFACE_VERSION_1 "VEngineRandom001" + +//----------------------------------------------------------------------------- +// Purpose: Interface to get at server entities +//----------------------------------------------------------------------------- +#define SERVERGAMEENTS_INTERFACEVERSION_1 "ServerGameEnts001" + +namespace ServerGameEntsV1 +{ + +abstract_class IServerGameEnts +{ +public: + virtual ~IServerGameEnts() {} + + // Only for debugging. Set the edict base so you can get an edict's index in the debugger while debugging the game .dll + virtual void SetDebugEdictBase(edict_t *base) = 0; + + // The engine wants to mark two entities as touching + virtual void MarkEntitiesAsTouching( edict_t *e1, edict_t *e2 ) = 0; + + // Frees the entity attached to this edict + virtual void FreeContainingEntity( edict_t * ) = 0; + + // This allows the engine to get at edicts in a CGameTrace. + virtual edict_t* BaseEntityToEdict( CBaseEntity *pEnt ) = 0; + virtual CBaseEntity* EdictToBaseEntity( edict_t *pEdict ) = 0; + + // This sets a bit in pInfo for each edict in the list that wants to be transmitted to the + // client specified in pInfo. + // + // This is also where an entity can force other entities to be transmitted if it refers to them + // with ehandles. + virtual void CheckTransmit( CCheckTransmitInfo *pInfo, const unsigned short *pEdictIndices, int nEdicts ) = 0; +}; + +} // end namespace ServerGameEntsV1 + + +//----------------------------------------------------------------------------- +// Purpose: Player / Client related functions +//----------------------------------------------------------------------------- +#define SERVERGAMECLIENTS_INTERFACEVERSION_3 "ServerGameClients003" + +namespace ServerGameClientsV3 +{ + +abstract_class IServerGameClients +{ +public: + // Get server maxplayers and lower bound for same + virtual void GetPlayerLimits( int& minplayers, int& maxplayers, int &defaultMaxPlayers ) const = 0; + + // Client is connecting to server ( return false to reject the connection ) + // You can specify a rejection message by writing it into reject + virtual bool ClientConnect( edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen ) = 0; + + // Client is going active + // If bLoadGame is true, don't spawn the player because its state is already setup. + virtual void ClientActive( edict_t *pEntity, bool bLoadGame ) = 0; + + // Client is disconnecting from server + virtual void ClientDisconnect( edict_t *pEntity ) = 0; + + // Client is connected and should be put in the game + virtual void ClientPutInServer( edict_t *pEntity, char const *playername ) = 0; + + // The client has typed a command at the console + virtual void ClientCommand( edict_t *pEntity ) = 0; + + // Sets the client index for the client who typed the command into his/her console + virtual void SetCommandClient( int index ) = 0; + + // A player changed one/several replicated cvars (name etc) + virtual void ClientSettingsChanged( edict_t *pEdict ) = 0; + + // Determine PVS origin and set PVS for the player/viewentity + virtual void ClientSetupVisibility( edict_t *pViewEntity, edict_t *pClient, unsigned char *pvs, int pvssize ) = 0; + + // A block of CUserCmds has arrived from the user, decode them and buffer for execution during player simulation + virtual float ProcessUsercmds( edict_t *player, bf_read *buf, int numcmds, int totalcmds, + int dropped_packets, bool ignore, bool paused ) = 0; + + // Let the game .dll do stuff after messages have been sent to all of the clients once the server frame is complete + virtual void PostClientMessagesSent_DEPRECIATED( void ) = 0; + + // For players, looks up the CPlayerState structure corresponding to the player + virtual CPlayerState *GetPlayerState( edict_t *player ) = 0; + + // Get the ear position for a specified client + virtual void ClientEarPosition( edict_t *pEntity, Vector *pEarOrigin ) = 0; + + // returns number of delay ticks if player is in Replay mode (0 = no delay) + virtual int GetReplayDelay( edict_t *player ) = 0; + + // Anything this game .dll wants to add to the bug reporter text (e.g., the entity/model under the picker crosshair) + // can be added here + virtual void GetBugReportInfo( char *buf, int buflen ) = 0; +}; + +} // end namespace ServerGameClientsV3 + + +#define UPLOADGAMESTATS_INTERFACEVERSION_1 "ServerUploadGameStats001" + +namespace UploadGameStatsV1 +{ + +abstract_class IUploadGameStats +{ +public: + // Note that this call will block the server until the upload is completed, so use only at levelshutdown if at all. + virtual bool UploadGameStats( + char const *mapname, // Game map name + unsigned int blobversion, // Version of the binary blob data + unsigned int blobsize, // Size in bytes of blob data + const void *pvBlobData ) = 0; // Pointer to the blob data. +}; + +} // end namespace UploadGameStatsV1 + + +#endif // EIFACEV21_H diff --git a/public/gcsdk/msgprotobuf.h b/public/gcsdk/msgprotobuf.h index 06a80699..21b8526b 100644 --- a/public/gcsdk/msgprotobuf.h +++ b/public/gcsdk/msgprotobuf.h @@ -101,6 +101,7 @@ public: virtual ~CProtoBufMsgBase(); + bool BIsInitialized() const; bool InitFromPacket( IMsgNetPacket * pNetPacket ); bool BAsyncSend( IProtoBufSendHandler & pSender ) const; bool BAsyncSendWithPreSerializedBody( IProtoBufSendHandler & pSender, const byte *pubBody, uint32 cubBody ) const; diff --git a/public/mathlib/mathlib.h b/public/mathlib/mathlib.h index 01107d19..baeb4ebc 100644 --- a/public/mathlib/mathlib.h +++ b/public/mathlib/mathlib.h @@ -1591,7 +1591,7 @@ float Hermite_Spline( float t ); -void Hermite_SplineBasis( float t, float basis[] ); +void Hermite_SplineBasis( float t, float basis[4] ); void Hermite_Spline( const Quaternion &q0, diff --git a/public/mathlib/ssemath.h b/public/mathlib/ssemath.h index 7a3ae978..afe35dd3 100644 --- a/public/mathlib/ssemath.h +++ b/public/mathlib/ssemath.h @@ -1735,7 +1735,6 @@ FORCEINLINE uint32 & SubInt( fltx4 & a, int idx ) // Intel/SSE implementation //--------------------------------------------------------------------- - FORCEINLINE void StoreAlignedSIMD( float * RESTRICT pSIMD, const fltx4 & a ) { _mm_store_ps( pSIMD, a ); @@ -1772,18 +1771,27 @@ FORCEINLINE void StoreAligned3SIMD( VectorAligned * RESTRICT pSIMD, const fltx4 StoreAlignedSIMD( pSIMD->Base(),a ); } -FORCEINLINE fltx4 LoadAlignedSIMD( const void *pSIMD ) +#define IS_FLOAT_TYPE(T) \ + ( sizeof( T ) == sizeof( float ) || sizeof ( T ) == sizeof( fltx4 ) ) + +template +FORCEINLINE fltx4 LoadAlignedSIMD( const T *pSIMD ) { + static_assert( IS_FLOAT_TYPE(T), "You are doing something wrong." ); return _mm_load_ps( reinterpret_cast< const float *> ( pSIMD ) ); } -FORCEINLINE shortx8 LoadAlignedShortSIMD( const void *pSIMD ) +template +FORCEINLINE shortx8 LoadAlignedShortSIMD( const T *pSIMD ) { + static_assert( IS_FLOAT_TYPE(T), "You are doing something wrong." ); return _mm_load_si128( reinterpret_cast< const shortx8 *> ( pSIMD ) ); } -FORCEINLINE shortx8 LoadUnalignedShortSIMD( const void *pSIMD ) +template +FORCEINLINE shortx8 LoadUnalignedShortSIMD( const T *pSIMD ) { + static_assert( IS_FLOAT_TYPE(T), "You are doing something wrong." ); return _mm_loadu_si128( reinterpret_cast< const shortx8 *> ( pSIMD ) ); } @@ -1820,13 +1828,17 @@ FORCEINLINE fltx4 LoadAlignedSIMD( const VectorAligned & pSIMD ) return SetWToZeroSIMD( LoadAlignedSIMD(pSIMD.Base()) ); } -NO_ASAN_FORCEINLINE fltx4 LoadUnalignedSIMD( const void *pSIMD ) +template +NO_ASAN_FORCEINLINE fltx4 LoadUnalignedSIMD( const T *pSIMD ) { + static_assert( IS_FLOAT_TYPE(T), "You are doing something wrong." ); return _mm_loadu_ps( reinterpret_cast( pSIMD ) ); } -NO_ASAN_FORCEINLINE fltx4 LoadUnaligned3SIMD( const void *pSIMD ) +template +NO_ASAN_FORCEINLINE fltx4 LoadUnaligned3SIMD( const T *pSIMD ) { + static_assert( IS_FLOAT_TYPE(T), "You are doing something wrong." ); return _mm_loadu_ps( reinterpret_cast( pSIMD ) ); } diff --git a/public/sentence.cpp b/public/sentence.cpp index fd640a16..044123ef 100644 --- a/public/sentence.cpp +++ b/public/sentence.cpp @@ -240,7 +240,7 @@ CBasePhonemeTag::CBasePhonemeTag() CBasePhonemeTag::CBasePhonemeTag( const CBasePhonemeTag& from ) { - memcpy( (void *)this, &from, sizeof(*this) ); + memcpy( this, &from, sizeof(*this) ); } diff --git a/public/sentence.h b/public/sentence.h index ec3ab881..de0f8d9a 100644 --- a/public/sentence.h +++ b/public/sentence.h @@ -48,7 +48,7 @@ public: CBasePhonemeTag(); CBasePhonemeTag( const CBasePhonemeTag& from ); - CBasePhonemeTag &operator=( const CBasePhonemeTag &from ) { memcpy( (void *)this, &from, sizeof(*this) ); return *this; } + CBasePhonemeTag &operator=( const CBasePhonemeTag &from ) { memcpy( this, &from, sizeof(*this) ); return *this; } float GetStartTime() const { return m_flStartTime; } void SetStartTime( float startTime ) { m_flStartTime = startTime; } diff --git a/public/steam/steamtypes.h b/public/steam/steamtypes.h index d5d4a5f3..4cff1fdc 100644 --- a/public/steam/steamtypes.h +++ b/public/steam/steamtypes.h @@ -18,7 +18,7 @@ typedef unsigned char uint8; #endif #if defined(__LP64__) || defined(__x86_64__) || defined(_WIN64) || defined(__aarch64__) || defined(__s390x__) -#ifndef X64BITS +#if !defined(X64BITS) #define X64BITS #endif #endif diff --git a/public/studio.h b/public/studio.h index cca4586b..9480d15d 100644 --- a/public/studio.h +++ b/public/studio.h @@ -2692,13 +2692,10 @@ public: // ctor CActivityToSequenceMapping( void ) - : m_pSequenceTuples(NULL), m_iSequenceTuplesCount(0) + : m_pSequenceTuples(NULL), m_iSequenceTuplesCount(0), m_ActToSeqHash(8,0,0), m_expectedPStudioHdr(NULL), m_expectedVModel(NULL) #if STUDIO_SEQUENCE_ACTIVITY_LAZY_INITIALIZE - , m_bIsInitialized(false) + , m_bIsInitialized(false) #endif - , m_ActToSeqHash(8,0,0) - , m_expectedPStudioHdr(NULL) - , m_expectedVModel(NULL) {}; // dtor -- not virtual because this class has no inheritors @@ -3319,7 +3316,7 @@ inline int Studio_LoadVertexes( const vertexFileHeader_t *pTempVvdHdr, vertexFil // copy vertexes memcpy( - (void *)((mstudiovertex_t *)((byte *)pNewVvdHdr+pNewVvdHdr->vertexDataStart) + target), + (mstudiovertex_t *)((byte *)pNewVvdHdr+pNewVvdHdr->vertexDataStart) + target, (mstudiovertex_t *)((byte *)pTempVvdHdr+pTempVvdHdr->vertexDataStart) + pFixupTable[i].sourceVertexID, pFixupTable[i].numVertexes*sizeof(mstudiovertex_t) ); @@ -3327,7 +3324,7 @@ inline int Studio_LoadVertexes( const vertexFileHeader_t *pTempVvdHdr, vertexFil { // copy tangents memcpy( - (void *)((Vector4D *)((byte *)pNewVvdHdr+pNewVvdHdr->tangentDataStart) + target), + (Vector4D *)((byte *)pNewVvdHdr+pNewVvdHdr->tangentDataStart) + target, (Vector4D *)((byte *)pTempVvdHdr+pTempVvdHdr->tangentDataStart) + pFixupTable[i].sourceVertexID, pFixupTable[i].numVertexes*sizeof(Vector4D) ); } diff --git a/public/tier0/platform.h b/public/tier0/platform.h index c60d5533..b0f9c18b 100644 --- a/public/tier0/platform.h +++ b/public/tier0/platform.h @@ -1274,7 +1274,7 @@ inline uint64 Plat_Rdtsc() public: \ _classname &operator=( const _classname &src ) \ { \ - memcpy( (void *)this, &src, sizeof(_classname) ); \ + memcpy( this, &src, sizeof(_classname) ); \ return *this; \ } diff --git a/public/tier1/KeyValues.h b/public/tier1/KeyValues.h index 838bf0b8..e7fa52f3 100644 --- a/public/tier1/KeyValues.h +++ b/public/tier1/KeyValues.h @@ -109,11 +109,14 @@ public: KeyValues( const char *setName, const char *firstKey, int firstValue ); KeyValues( const char *setName, const char *firstKey, const char *firstValue, const char *secondKey, const char *secondValue ); KeyValues( const char *setName, const char *firstKey, int firstValue, const char *secondKey, int secondValue ); + KeyValues( const char *setName, bool bUsesLocalStorage ); // Section name const char *GetName() const; void SetName( const char *setName); + bool IsUsingLocalStorage() const { return m_bIsUsingLocalStringTable != 0; } + // gets the name as a unique int int GetNameSymbol() const { return m_iKeyName; } @@ -330,12 +333,14 @@ private: char m_iDataType; char m_bHasEscapeSequences; // true, if while parsing this KeyValue, Escape Sequences are used (default false) char m_bEvaluateConditionals; // true, if while parsing this KeyValue, conditionals blocks are evaluated (default true) - char unused[1]; + char m_bIsUsingLocalStringTable; // true if this node uses a per-instance growable string table KeyValues *m_pPeer; // pointer to next key in list KeyValues *m_pSub; // pointer to Start of a new sub key list KeyValues *m_pChain;// Search here if it's not in our list + CKeyValuesGrowableStringTable *m_pLocalStringTable; + private: // Statics to implement the optional growable string table // Function pointers that will determine which mode we are in diff --git a/public/tier1/utlblockmemory.h b/public/tier1/utlblockmemory.h index 4782e235..317a4cf5 100644 --- a/public/tier1/utlblockmemory.h +++ b/public/tier1/utlblockmemory.h @@ -137,12 +137,14 @@ void CUtlBlockMemory::Swap( CUtlBlockMemory< T, I > &mem ) { V_swap( m_pMemory, mem.m_pMemory ); V_swap( m_nBlocks, mem.m_nBlocks ); - int tmp = m_nIndexMask; - m_nIndexMask = mem.m_nIndexMask; - mem.m_nIndexMask = tmp; - tmp = m_nIndexShift; - m_nIndexShift = mem.m_nIndexShift; - mem.m_nIndexShift = tmp; + + int tmp = mem.m_nIndexMask; + mem.m_nIndexMask = m_nIndexMask; + m_nIndexMask = tmp; + + tmp = mem.m_nIndexShift; + mem.m_nIndexShift = m_nIndexShift; + m_nIndexShift = tmp; } diff --git a/public/vgui_controls/MenuBar.h b/public/vgui_controls/MenuBar.h index 01ccc06a..8a698748 100644 --- a/public/vgui_controls/MenuBar.h +++ b/public/vgui_controls/MenuBar.h @@ -41,7 +41,11 @@ protected: virtual void PerformLayout(); virtual void Paint(); MESSAGE_FUNC( OnMenuClose, "MenuClose" ); - MESSAGE_FUNC_INT( OnCursorEnteredMenuButton, "CursorEnteredMenuButton", VPanel); +#ifdef PLATFORM_64BITS + MESSAGE_FUNC_PTR( OnCursorEnteredMenuButton, "CursorEnteredMenuButton", VPanel ); +#else + MESSAGE_FUNC_INT( OnCursorEnteredMenuButton, "CursorEnteredMenuButton", VPanel ); +#endif private: CUtlVector m_pMenuButtons; diff --git a/public/vgui_controls/Panel.h b/public/vgui_controls/Panel.h index 810d49e0..99c75aac 100644 --- a/public/vgui_controls/Panel.h +++ b/public/vgui_controls/Panel.h @@ -347,6 +347,8 @@ public: bool IsRightAligned(); // returns true if the settings are aligned to the right of the screen bool IsBottomAligned(); // returns true if the settings are aligned to the bottom of the screen + virtual bool CanAnimate() const { return true; } // If the panel can animate + // scheme access functions virtual HScheme GetScheme(); virtual void SetScheme(const char *tag); diff --git a/public/vphysics_interface.h b/public/vphysics_interface.h index 55e35180..00f00928 100644 --- a/public/vphysics_interface.h +++ b/public/vphysics_interface.h @@ -854,6 +854,7 @@ public: // dumps info about the object to Msg() virtual void OutputDebugInfo() const = 0; + virtual float GetBuoyancyRatio( void ) const = 0; }; diff --git a/public/vscript/variant.h b/public/vscript/variant.h index 351d7ea2..edacce39 100644 --- a/public/vscript/variant.h +++ b/public/vscript/variant.h @@ -129,8 +129,8 @@ public: operator char() const { Assert( m_type == FIELD_CHARACTER ); return m_char; } operator bool() const { Assert( m_type == FIELD_BOOLEAN ); return m_bool; } operator HSCRIPT() const { Assert( m_type == FIELD_HSCRIPT ); return m_hScript; } - operator CBaseHandle() const { Assert( m_type == FIELD_EHANDLE ); return CBaseHandle( m_hEntity ); } - operator CBaseEntity*() const { Assert( m_type == FIELD_EHANDLE ); return CHandle(CBaseHandle( m_hEntity )); } + operator CBaseHandle() const { Assert( m_type == FIELD_EHANDLE ); return CBaseHandle::UnsafeFromIndex( m_hEntity ); } + operator CBaseEntity*() const { Assert( m_type == FIELD_EHANDLE ); return CHandle::UnsafeFromIndex( m_hEntity ); } operator const Quaternion &() const { Assert( m_type == FIELD_QUATERNION ); return m_pData ? *(Quaternion*)m_pData : quat_identity; } // operator CUtlStringToken() const { Assert( m_type == FIELD_UTLSTRINGTOKEN ); CUtlStringToken t; t.m_nHashCode = m_utlStringToken; return t; } @@ -614,7 +614,7 @@ inline bool CVariantBase::AssignTo( CBaseHandle *pDest ) const { switch( m_type ) { - case FIELD_EHANDLE: *pDest = CHandle< CBaseEntity >(m_hEntity); return true; + case FIELD_EHANDLE: *pDest = CHandle< CBaseEntity >::UnsafeFromIndex( m_hEntity ); return true; default: Warning( "No free conversion of %s variant to EHANDLE right now\n", VariantFieldTypeName( m_type ) ); break; @@ -627,7 +627,7 @@ inline bool CVariantBase::AssignTo( CBaseEntity **pDest ) const { switch( m_type ) { - case FIELD_EHANDLE: *pDest = CHandle< CBaseEntity >(m_hEntity); return true; + case FIELD_EHANDLE: *pDest = CHandle< CBaseEntity >::UnsafeFromIndex( m_hEntity ); return true; default: Warning( "No free conversion of %s variant to CBaseEntity * right now\n", VariantFieldTypeName( m_type ) ); break; diff --git a/tier1/KeyValues.cpp b/tier1/KeyValues.cpp index f394bebe..f83f3b8e 100644 --- a/tier1/KeyValues.cpp +++ b/tier1/KeyValues.cpp @@ -229,7 +229,7 @@ static CLeakTrack track; class CKeyValuesGrowableStringTable { public: - // Constructor + // Constructor for global singleton string table CKeyValuesGrowableStringTable() : m_hashLookup( 2048, 0, 0, m_Functor, m_Functor ), #ifdef PLATFORM_64BITS @@ -241,6 +241,14 @@ public: m_vecStrings.AddToTail( '\0' ); } + // Constructor for per-instance string table + CKeyValuesGrowableStringTable( int nInitialStringCapacity ) : + m_hashLookup( 16, 0, 0, m_Functor, m_Functor ), + m_vecStrings( 0, nInitialStringCapacity ) + { + m_vecStrings.AddToTail( '\0' ); + } + // Translates a string to an index int GetSymbolForString( const char *name, bool bCreate = true ) { @@ -381,6 +389,22 @@ KeyValues::KeyValues( const char *setName ) SetName ( setName ); } +//----------------------------------------------------------------------------- +// Purpose: Constructor with optional per-instance string table +//----------------------------------------------------------------------------- +KeyValues::KeyValues( const char *setName, bool bUsesLocalStorage ) +{ + TRACK_KV_ADD( this, setName ); + + Init(); + if ( bUsesLocalStorage ) + { + m_pLocalStringTable = new CKeyValuesGrowableStringTable( 256 ); + m_bIsUsingLocalStringTable = true; + } + SetName( setName ); +} + //----------------------------------------------------------------------------- // Purpose: Constructor //----------------------------------------------------------------------------- @@ -461,9 +485,8 @@ void KeyValues::Init() m_bHasEscapeSequences = false; m_bEvaluateConditionals = true; - - // for future proof - memset( unused, 0, sizeof(unused) ); + m_bIsUsingLocalStringTable = false; + m_pLocalStringTable = NULL; } //----------------------------------------------------------------------------- @@ -501,6 +524,8 @@ void KeyValues::RemoveEverything() m_sValue = NULL; delete [] m_wsValue; m_wsValue = NULL; + delete m_pLocalStringTable; + m_pLocalStringTable = NULL; } //----------------------------------------------------------------------------- @@ -528,6 +553,11 @@ void KeyValues::ChainKeyValue( KeyValues* pChain ) //----------------------------------------------------------------------------- const char *KeyValues::GetName( void ) const { + if ( m_bIsUsingLocalStringTable ) + { + Assert( m_pLocalStringTable ); + return m_pLocalStringTable->GetStringForSymbol( m_iKeyName ); + } return s_pfGetStringForSymbol( m_iKeyName ); } diff --git a/tier1/memstack.cpp b/tier1/memstack.cpp index 295ad816..a6efcf31 100644 --- a/tier1/memstack.cpp +++ b/tier1/memstack.cpp @@ -31,7 +31,8 @@ MEMALLOC_DEFINE_EXTERNAL_TRACKING(CMemoryStack); //----------------------------------------------------------------------------- CMemoryStack::CMemoryStack() - : m_pNextAlloc( NULL ), + : + m_pNextAlloc( NULL ), m_pCommitLimit( NULL ), m_pAllocLimit( NULL ), m_pBase( NULL ), diff --git a/tier1/utlsymbol.cpp b/tier1/utlsymbol.cpp index d75eaa52..77dd76de 100644 --- a/tier1/utlsymbol.cpp +++ b/tier1/utlsymbol.cpp @@ -327,9 +327,7 @@ FileNameHandle_t CUtlFilenameSymbolTable::FindOrAddFileName( const char *pFileNa char fn[ MAX_PATH ]; Q_strncpy( fn, pFileName, sizeof( fn ) ); Q_RemoveDotSlashes( fn ); -#ifdef _WIN32 Q_strlower( fn ); -#endif // Split the filename into constituent parts char basepath[ MAX_PATH ]; @@ -370,9 +368,7 @@ FileNameHandle_t CUtlFilenameSymbolTable::FindFileName( const char *pFileName ) char fn[ MAX_PATH ]; Q_strncpy( fn, pFileName, sizeof( fn ) ); Q_RemoveDotSlashes( fn ); -#ifdef _WIN32 Q_strlower( fn ); -#endif // Split the filename into constituent parts char basepath[ MAX_PATH ]; diff --git a/utils/common/bsplib.cpp b/utils/common/bsplib.cpp index bcda4c50..607bb5ef 100644 --- a/utils/common/bsplib.cpp +++ b/utils/common/bsplib.cpp @@ -218,6 +218,7 @@ BEGIN_BYTESWAP_DATADESC( dfaceid_t ) DEFINE_FIELD( hammerfaceid, FIELD_SHORT ), END_BYTESWAP_DATADESC() + BEGIN_BYTESWAP_DATADESC( dbrush_t ) DEFINE_FIELD( firstside, FIELD_INTEGER ), DEFINE_FIELD( numsides, FIELD_INTEGER ), @@ -631,6 +632,7 @@ dface_t dfaces[MAX_MAP_FACES]; int numfaceids; CUtlVector dfaceids; + int numfaces_hdr; dface_t dfaces_hdr[MAX_MAP_FACES]; @@ -2235,6 +2237,7 @@ void LoadBSPFile( const char *filename ) CopyOptionalLump( LUMP_FACEIDS, dfaceids ); + g_numprimitives = CopyLump( LUMP_PRIMITIVES, g_primitives ); g_numprimverts = CopyLump( LUMP_PRIMVERTS, g_primverts ); g_numprimindices = CopyLump( FIELD_SHORT, LUMP_PRIMINDICES, g_primindices ); @@ -2365,6 +2368,7 @@ void UnloadBSPFile() dfaceids.Purge(); + g_numprimitives = 0; g_numprimverts = 0; g_numprimindices = 0; @@ -2669,6 +2673,7 @@ void WriteBSPFile( const char *filename, char *pUnused ) AddLump( LUMP_FACES_HDR, dfaces_hdr, numfaces_hdr, LUMP_FACES_VERSION ); AddLump ( LUMP_FACEIDS, dfaceids, numfaceids ); + AddLump( LUMP_ORIGINALFACES, dorigfaces, numorigfaces ); // original faces lump AddLump( LUMP_BRUSHES, dbrushes, numbrushes ); AddLump( LUMP_BRUSHSIDES, dbrushsides, numbrushsides ); diff --git a/utils/lzma/C/Util/7z/7z.dsp b/utils/lzma/C/Util/7z/7z.dsp index 92818667..73122f75 100644 --- a/utils/lzma/C/Util/7z/7z.dsp +++ b/utils/lzma/C/Util/7z/7z.dsp @@ -1,229 +1,229 @@ -# Microsoft Developer Studio Project File - Name="7z" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=7z - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "7z.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "7z.mak" CFG="7z - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "7z - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "7z - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "7z - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /MD /W4 /WX /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /FAs /Yu"Precomp.h" /FD /c -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x419 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\util\7zDec.exe" /opt:NOWIN98 -# SUBTRACT LINK32 /pdb:none - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_SZ_ALLOC_DEBUG2" /D "_SZ_NO_INT_64_A" /D "WIN32" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /Yu"Precomp.h" /FD /GZ /c -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x419 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\util\7zDec.exe" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "7z - Win32 Release" -# Name "7z - Win32 Debug" -# Begin Group "Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\7z.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zAlloc.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zAlloc.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zArcIn.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zBuf.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zBuf.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zCrc.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zCrc.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zCrcOpt.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zDec.c -# ADD CPP /D "_7ZIP_PPMD_SUPPPORT" -# End Source File -# Begin Source File - -SOURCE=..\..\7zFile.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zFile.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zStream.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\Bcj2.c -# End Source File -# Begin Source File - -SOURCE=..\..\Bcj2.h -# End Source File -# Begin Source File - -SOURCE=..\..\Bra.c -# End Source File -# Begin Source File - -SOURCE=..\..\Bra.h -# End Source File -# Begin Source File - -SOURCE=..\..\Bra86.c -# End Source File -# Begin Source File - -SOURCE=..\..\CpuArch.c -# End Source File -# Begin Source File - -SOURCE=..\..\CpuArch.h -# End Source File -# Begin Source File - -SOURCE=..\..\Lzma2Dec.c -# End Source File -# Begin Source File - -SOURCE=..\..\Lzma2Dec.h -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaDec.c -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaDec.h -# End Source File -# Begin Source File - -SOURCE=..\..\Ppmd.h -# End Source File -# Begin Source File - -SOURCE=..\..\Ppmd7.c -# End Source File -# Begin Source File - -SOURCE=..\..\Ppmd7.h -# End Source File -# Begin Source File - -SOURCE=..\..\Ppmd7Dec.c -# End Source File -# End Group -# Begin Group "Spec" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compiler.h -# End Source File -# Begin Source File - -SOURCE=.\Precomp.c -# ADD CPP /Yc"Precomp.h" -# End Source File -# Begin Source File - -SOURCE=.\Precomp.h -# End Source File -# End Group -# Begin Source File - -SOURCE=.\7zMain.c -# End Source File -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="7z" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=7z - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "7z.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "7z.mak" CFG="7z - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "7z - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "7z - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "7z - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W4 /WX /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /FAs /Yu"Precomp.h" /FD /c +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\util\7zDec.exe" /opt:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_SZ_ALLOC_DEBUG2" /D "_SZ_NO_INT_64_A" /D "WIN32" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /Yu"Precomp.h" /FD /GZ /c +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\util\7zDec.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "7z - Win32 Release" +# Name "7z - Win32 Debug" +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\7z.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zAlloc.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zAlloc.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zArcIn.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zBuf.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zBuf.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zCrc.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zCrc.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zCrcOpt.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zDec.c +# ADD CPP /D "_7ZIP_PPMD_SUPPPORT" +# End Source File +# Begin Source File + +SOURCE=..\..\7zFile.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zFile.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zStream.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\Bcj2.c +# End Source File +# Begin Source File + +SOURCE=..\..\Bcj2.h +# End Source File +# Begin Source File + +SOURCE=..\..\Bra.c +# End Source File +# Begin Source File + +SOURCE=..\..\Bra.h +# End Source File +# Begin Source File + +SOURCE=..\..\Bra86.c +# End Source File +# Begin Source File + +SOURCE=..\..\CpuArch.c +# End Source File +# Begin Source File + +SOURCE=..\..\CpuArch.h +# End Source File +# Begin Source File + +SOURCE=..\..\Lzma2Dec.c +# End Source File +# Begin Source File + +SOURCE=..\..\Lzma2Dec.h +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaDec.c +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaDec.h +# End Source File +# Begin Source File + +SOURCE=..\..\Ppmd.h +# End Source File +# Begin Source File + +SOURCE=..\..\Ppmd7.c +# End Source File +# Begin Source File + +SOURCE=..\..\Ppmd7.h +# End Source File +# Begin Source File + +SOURCE=..\..\Ppmd7Dec.c +# End Source File +# End Group +# Begin Group "Spec" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compiler.h +# End Source File +# Begin Source File + +SOURCE=.\Precomp.c +# ADD CPP /Yc"Precomp.h" +# End Source File +# Begin Source File + +SOURCE=.\Precomp.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\7zMain.c +# End Source File +# End Target +# End Project diff --git a/utils/lzma/C/Util/7z/7z.dsw b/utils/lzma/C/Util/7z/7z.dsw index 848d13cb..23089fb7 100644 --- a/utils/lzma/C/Util/7z/7z.dsw +++ b/utils/lzma/C/Util/7z/7z.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "7z"=.\7z.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "7z"=.\7z.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/utils/lzma/C/Util/7z/makefile b/utils/lzma/C/Util/7z/makefile index e0aa1e37..08e6f687 100644 --- a/utils/lzma/C/Util/7z/makefile +++ b/utils/lzma/C/Util/7z/makefile @@ -1,39 +1,39 @@ -# MY_STATIC_LINK=1 -CFLAGS = $(CFLAGS) -D_7ZIP_PPMD_SUPPPORT - -PROG = 7zDec.exe - -C_OBJS = \ - $O\7zAlloc.obj \ - $O\7zBuf.obj \ - $O\7zCrc.obj \ - $O\7zCrcOpt.obj \ - $O\7zFile.obj \ - $O\7zDec.obj \ - $O\7zArcIn.obj \ - $O\7zStream.obj \ - $O\Bcj2.obj \ - $O\Bra.obj \ - $O\Bra86.obj \ - $O\CpuArch.obj \ - $O\Lzma2Dec.obj \ - $O\LzmaDec.obj \ - $O\Ppmd7.obj \ - $O\Ppmd7Dec.obj \ - -7Z_OBJS = \ - $O\7zMain.obj \ - -OBJS = \ - $O\Precomp.obj \ - $(7Z_OBJS) \ - $(C_OBJS) \ - -!include "../../../CPP/Build.mak" - -$(7Z_OBJS): $(*B).c - $(CCOMPL_USE) -$(C_OBJS): ../../$(*B).c - $(CCOMPL_USE) -$O\Precomp.obj: Precomp.c - $(CCOMPL_PCH) +# MY_STATIC_LINK=1 +CFLAGS = $(CFLAGS) -D_7ZIP_PPMD_SUPPPORT + +PROG = 7zDec.exe + +C_OBJS = \ + $O\7zAlloc.obj \ + $O\7zBuf.obj \ + $O\7zCrc.obj \ + $O\7zCrcOpt.obj \ + $O\7zFile.obj \ + $O\7zDec.obj \ + $O\7zArcIn.obj \ + $O\7zStream.obj \ + $O\Bcj2.obj \ + $O\Bra.obj \ + $O\Bra86.obj \ + $O\CpuArch.obj \ + $O\Lzma2Dec.obj \ + $O\LzmaDec.obj \ + $O\Ppmd7.obj \ + $O\Ppmd7Dec.obj \ + +7Z_OBJS = \ + $O\7zMain.obj \ + +OBJS = \ + $O\Precomp.obj \ + $(7Z_OBJS) \ + $(C_OBJS) \ + +!include "../../../CPP/Build.mak" + +$(7Z_OBJS): $(*B).c + $(CCOMPL_USE) +$(C_OBJS): ../../$(*B).c + $(CCOMPL_USE) +$O\Precomp.obj: Precomp.c + $(CCOMPL_PCH) diff --git a/utils/lzma/C/Util/7z/makefile.gcc b/utils/lzma/C/Util/7z/makefile.gcc index 46018201..63c59cab 100644 --- a/utils/lzma/C/Util/7z/makefile.gcc +++ b/utils/lzma/C/Util/7z/makefile.gcc @@ -1,70 +1,70 @@ -PROG = 7zDec -CXX = g++ -LIB = -RM = rm -f -CFLAGS = -c -O2 -Wall - -OBJS = 7zMain.o 7zAlloc.o 7zArcIn.o 7zBuf.o 7zBuf2.o 7zCrc.o 7zCrcOpt.o 7zDec.o CpuArch.o LzmaDec.o Lzma2Dec.o Bra.o Bra86.o Bcj2.o Ppmd7.o Ppmd7Dec.o 7zFile.o 7zStream.o - -all: $(PROG) - -$(PROG): $(OBJS) - $(CXX) -o $(PROG) $(LDFLAGS) $(OBJS) $(LIB) - -7zMain.o: 7zMain.c - $(CXX) $(CFLAGS) 7zMain.c - -7zAlloc.o: ../../7zAlloc.c - $(CXX) $(CFLAGS) ../../7zAlloc.c - -7zArcIn.o: ../../7zArcIn.c - $(CXX) $(CFLAGS) ../../7zArcIn.c - -7zBuf.o: ../../7zBuf.c - $(CXX) $(CFLAGS) ../../7zBuf.c - -7zBuf2.o: ../../7zBuf2.c - $(CXX) $(CFLAGS) ../../7zBuf2.c - -7zCrc.o: ../../7zCrc.c - $(CXX) $(CFLAGS) ../../7zCrc.c - -7zCrcOpt.o: ../../7zCrc.c - $(CXX) $(CFLAGS) ../../7zCrcOpt.c - -7zDec.o: ../../7zDec.c - $(CXX) $(CFLAGS) -D_7ZIP_PPMD_SUPPPORT ../../7zDec.c - -CpuArch.o: ../../CpuArch.c - $(CXX) $(CFLAGS) ../../CpuArch.c - -LzmaDec.o: ../../LzmaDec.c - $(CXX) $(CFLAGS) ../../LzmaDec.c - -Lzma2Dec.o: ../../Lzma2Dec.c - $(CXX) $(CFLAGS) ../../Lzma2Dec.c - -Bra.o: ../../Bra.c - $(CXX) $(CFLAGS) ../../Bra.c - -Bra86.o: ../../Bra86.c - $(CXX) $(CFLAGS) ../../Bra86.c - -Bcj2.o: ../../Bcj2.c - $(CXX) $(CFLAGS) ../../Bcj2.c - -Ppmd7.o: ../../Ppmd7.c - $(CXX) $(CFLAGS) ../../Ppmd7.c - -Ppmd7Dec.o: ../../Ppmd7Dec.c - $(CXX) $(CFLAGS) ../../Ppmd7Dec.c - -7zFile.o: ../../7zFile.c - $(CXX) $(CFLAGS) ../../7zFile.c - -7zStream.o: ../../7zStream.c - $(CXX) $(CFLAGS) ../../7zStream.c - -clean: - -$(RM) $(PROG) $(OBJS) - +PROG = 7zDec +CXX = g++ +LIB = +RM = rm -f +CFLAGS = -c -O2 -Wall + +OBJS = 7zMain.o 7zAlloc.o 7zArcIn.o 7zBuf.o 7zBuf2.o 7zCrc.o 7zCrcOpt.o 7zDec.o CpuArch.o LzmaDec.o Lzma2Dec.o Bra.o Bra86.o Bcj2.o Ppmd7.o Ppmd7Dec.o 7zFile.o 7zStream.o + +all: $(PROG) + +$(PROG): $(OBJS) + $(CXX) -o $(PROG) $(LDFLAGS) $(OBJS) $(LIB) + +7zMain.o: 7zMain.c + $(CXX) $(CFLAGS) 7zMain.c + +7zAlloc.o: ../../7zAlloc.c + $(CXX) $(CFLAGS) ../../7zAlloc.c + +7zArcIn.o: ../../7zArcIn.c + $(CXX) $(CFLAGS) ../../7zArcIn.c + +7zBuf.o: ../../7zBuf.c + $(CXX) $(CFLAGS) ../../7zBuf.c + +7zBuf2.o: ../../7zBuf2.c + $(CXX) $(CFLAGS) ../../7zBuf2.c + +7zCrc.o: ../../7zCrc.c + $(CXX) $(CFLAGS) ../../7zCrc.c + +7zCrcOpt.o: ../../7zCrc.c + $(CXX) $(CFLAGS) ../../7zCrcOpt.c + +7zDec.o: ../../7zDec.c + $(CXX) $(CFLAGS) -D_7ZIP_PPMD_SUPPPORT ../../7zDec.c + +CpuArch.o: ../../CpuArch.c + $(CXX) $(CFLAGS) ../../CpuArch.c + +LzmaDec.o: ../../LzmaDec.c + $(CXX) $(CFLAGS) ../../LzmaDec.c + +Lzma2Dec.o: ../../Lzma2Dec.c + $(CXX) $(CFLAGS) ../../Lzma2Dec.c + +Bra.o: ../../Bra.c + $(CXX) $(CFLAGS) ../../Bra.c + +Bra86.o: ../../Bra86.c + $(CXX) $(CFLAGS) ../../Bra86.c + +Bcj2.o: ../../Bcj2.c + $(CXX) $(CFLAGS) ../../Bcj2.c + +Ppmd7.o: ../../Ppmd7.c + $(CXX) $(CFLAGS) ../../Ppmd7.c + +Ppmd7Dec.o: ../../Ppmd7Dec.c + $(CXX) $(CFLAGS) ../../Ppmd7Dec.c + +7zFile.o: ../../7zFile.c + $(CXX) $(CFLAGS) ../../7zFile.c + +7zStream.o: ../../7zStream.c + $(CXX) $(CFLAGS) ../../7zStream.c + +clean: + -$(RM) $(PROG) $(OBJS) + diff --git a/utils/lzma/C/Util/Lzma/LzmaUtil.dsp b/utils/lzma/C/Util/Lzma/LzmaUtil.dsp index 43b8e176..df1f0cb0 100644 --- a/utils/lzma/C/Util/Lzma/LzmaUtil.dsp +++ b/utils/lzma/C/Util/Lzma/LzmaUtil.dsp @@ -1,168 +1,168 @@ -# Microsoft Developer Studio Project File - Name="LzmaUtil" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=LzmaUtil - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "LzmaUtil.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "LzmaUtil.mak" CFG="LzmaUtil - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "LzmaUtil - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "LzmaUtil - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "LzmaUtil - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /MT /W4 /WX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x419 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\util\7lzma.exe" - -!ELSEIF "$(CFG)" == "LzmaUtil - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /MTd /W4 /WX /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x419 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\util\7lzma.exe" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "LzmaUtil - Win32 Release" -# Name "LzmaUtil - Win32 Debug" -# Begin Source File - -SOURCE=..\..\7zFile.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zFile.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zStream.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zVersion.h -# End Source File -# Begin Source File - -SOURCE=..\..\Alloc.c -# End Source File -# Begin Source File - -SOURCE=..\..\Alloc.h -# End Source File -# Begin Source File - -SOURCE=..\..\CpuArch.h -# End Source File -# Begin Source File - -SOURCE=..\..\LzFind.c -# End Source File -# Begin Source File - -SOURCE=..\..\LzFind.h -# End Source File -# Begin Source File - -SOURCE=..\..\LzFindMt.c -# End Source File -# Begin Source File - -SOURCE=..\..\LzFindMt.h -# End Source File -# Begin Source File - -SOURCE=..\..\LzHash.h -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaDec.c -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaDec.h -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaEnc.c -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaEnc.h -# End Source File -# Begin Source File - -SOURCE=.\LzmaUtil.c -# End Source File -# Begin Source File - -SOURCE=..\..\Threads.c -# End Source File -# Begin Source File - -SOURCE=..\..\Threads.h -# End Source File -# Begin Source File - -SOURCE=..\..\Types.h -# End Source File -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="LzmaUtil" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=LzmaUtil - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "LzmaUtil.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "LzmaUtil.mak" CFG="LzmaUtil - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "LzmaUtil - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "LzmaUtil - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "LzmaUtil - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W4 /WX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\util\7lzma.exe" + +!ELSEIF "$(CFG)" == "LzmaUtil - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W4 /WX /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\util\7lzma.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "LzmaUtil - Win32 Release" +# Name "LzmaUtil - Win32 Debug" +# Begin Source File + +SOURCE=..\..\7zFile.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zFile.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zStream.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zVersion.h +# End Source File +# Begin Source File + +SOURCE=..\..\Alloc.c +# End Source File +# Begin Source File + +SOURCE=..\..\Alloc.h +# End Source File +# Begin Source File + +SOURCE=..\..\CpuArch.h +# End Source File +# Begin Source File + +SOURCE=..\..\LzFind.c +# End Source File +# Begin Source File + +SOURCE=..\..\LzFind.h +# End Source File +# Begin Source File + +SOURCE=..\..\LzFindMt.c +# End Source File +# Begin Source File + +SOURCE=..\..\LzFindMt.h +# End Source File +# Begin Source File + +SOURCE=..\..\LzHash.h +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaDec.c +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaDec.h +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaEnc.c +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaEnc.h +# End Source File +# Begin Source File + +SOURCE=.\LzmaUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\Threads.c +# End Source File +# Begin Source File + +SOURCE=..\..\Threads.h +# End Source File +# Begin Source File + +SOURCE=..\..\Types.h +# End Source File +# End Target +# End Project diff --git a/utils/lzma/C/Util/Lzma/LzmaUtil.dsw b/utils/lzma/C/Util/Lzma/LzmaUtil.dsw index c52eaf6d..f4354875 100644 --- a/utils/lzma/C/Util/Lzma/LzmaUtil.dsw +++ b/utils/lzma/C/Util/Lzma/LzmaUtil.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "LzmaUtil"=.\LzmaUtil.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "LzmaUtil"=.\LzmaUtil.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/utils/lzma/C/Util/Lzma/makefile b/utils/lzma/C/Util/Lzma/makefile index 47953227..3b825f21 100644 --- a/utils/lzma/C/Util/Lzma/makefile +++ b/utils/lzma/C/Util/Lzma/makefile @@ -1,28 +1,28 @@ -# MY_STATIC_LINK=1 -PROG = LZMAc.exe - -CFLAGS = $(CFLAGS) \ - -LIB_OBJS = \ - $O\LzmaUtil.obj \ - -C_OBJS = \ - $O\Alloc.obj \ - $O\LzFind.obj \ - $O\LzFindMt.obj \ - $O\LzmaDec.obj \ - $O\LzmaEnc.obj \ - $O\7zFile.obj \ - $O\7zStream.obj \ - $O\Threads.obj \ - -OBJS = \ - $(LIB_OBJS) \ - $(C_OBJS) \ - -!include "../../../CPP/Build.mak" - -$(LIB_OBJS): $(*B).c - $(COMPL_O2) -$(C_OBJS): ../../$(*B).c - $(COMPL_O2) +# MY_STATIC_LINK=1 +PROG = LZMAc.exe + +CFLAGS = $(CFLAGS) \ + +LIB_OBJS = \ + $O\LzmaUtil.obj \ + +C_OBJS = \ + $O\Alloc.obj \ + $O\LzFind.obj \ + $O\LzFindMt.obj \ + $O\LzmaDec.obj \ + $O\LzmaEnc.obj \ + $O\7zFile.obj \ + $O\7zStream.obj \ + $O\Threads.obj \ + +OBJS = \ + $(LIB_OBJS) \ + $(C_OBJS) \ + +!include "../../../CPP/Build.mak" + +$(LIB_OBJS): $(*B).c + $(COMPL_O2) +$(C_OBJS): ../../$(*B).c + $(COMPL_O2) diff --git a/utils/lzma/C/Util/Lzma/makefile.gcc b/utils/lzma/C/Util/Lzma/makefile.gcc index 67aa8b17..12a72bb8 100644 --- a/utils/lzma/C/Util/Lzma/makefile.gcc +++ b/utils/lzma/C/Util/Lzma/makefile.gcc @@ -1,44 +1,44 @@ -PROG = lzma -CXX = g++ -LIB = -RM = rm -f -CFLAGS = -c -O2 -Wall -D_7ZIP_ST - -OBJS = \ - LzmaUtil.o \ - Alloc.o \ - LzFind.o \ - LzmaDec.o \ - LzmaEnc.o \ - 7zFile.o \ - 7zStream.o \ - - -all: $(PROG) - -$(PROG): $(OBJS) - $(CXX) -o $(PROG) $(LDFLAGS) $(OBJS) $(LIB) $(LIB2) - -LzmaUtil.o: LzmaUtil.c - $(CXX) $(CFLAGS) LzmaUtil.c - -Alloc.o: ../../Alloc.c - $(CXX) $(CFLAGS) ../../Alloc.c - -LzFind.o: ../../LzFind.c - $(CXX) $(CFLAGS) ../../LzFind.c - -LzmaDec.o: ../../LzmaDec.c - $(CXX) $(CFLAGS) ../../LzmaDec.c - -LzmaEnc.o: ../../LzmaEnc.c - $(CXX) $(CFLAGS) ../../LzmaEnc.c - -7zFile.o: ../../7zFile.c - $(CXX) $(CFLAGS) ../../7zFile.c - -7zStream.o: ../../7zStream.c - $(CXX) $(CFLAGS) ../../7zStream.c - -clean: - -$(RM) $(PROG) $(OBJS) +PROG = lzma +CXX = g++ +LIB = +RM = rm -f +CFLAGS = -c -O2 -Wall -D_7ZIP_ST + +OBJS = \ + LzmaUtil.o \ + Alloc.o \ + LzFind.o \ + LzmaDec.o \ + LzmaEnc.o \ + 7zFile.o \ + 7zStream.o \ + + +all: $(PROG) + +$(PROG): $(OBJS) + $(CXX) -o $(PROG) $(LDFLAGS) $(OBJS) $(LIB) $(LIB2) + +LzmaUtil.o: LzmaUtil.c + $(CXX) $(CFLAGS) LzmaUtil.c + +Alloc.o: ../../Alloc.c + $(CXX) $(CFLAGS) ../../Alloc.c + +LzFind.o: ../../LzFind.c + $(CXX) $(CFLAGS) ../../LzFind.c + +LzmaDec.o: ../../LzmaDec.c + $(CXX) $(CFLAGS) ../../LzmaDec.c + +LzmaEnc.o: ../../LzmaEnc.c + $(CXX) $(CFLAGS) ../../LzmaEnc.c + +7zFile.o: ../../7zFile.c + $(CXX) $(CFLAGS) ../../7zFile.c + +7zStream.o: ../../7zStream.c + $(CXX) $(CFLAGS) ../../7zStream.c + +clean: + -$(RM) $(PROG) $(OBJS) diff --git a/utils/lzma/C/Util/LzmaLib/LzmaLib.dsp b/utils/lzma/C/Util/LzmaLib/LzmaLib.dsp index 3421de83..0d4c981c 100644 --- a/utils/lzma/C/Util/LzmaLib/LzmaLib.dsp +++ b/utils/lzma/C/Util/LzmaLib/LzmaLib.dsp @@ -1,178 +1,178 @@ -# Microsoft Developer Studio Project File - Name="LzmaLib" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=LzmaLib - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "LzmaLib.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "LzmaLib.mak" CFG="LzmaLib - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "LzmaLib - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "LzmaLib - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "LzmaLib - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /YX /FD /c -# ADD CPP /nologo /Gr /MT /W3 /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /FD /c -# SUBTRACT CPP /YX -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x419 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"C:\Util\LZMA.dll" /opt:NOWIN98 -# SUBTRACT LINK32 /pdb:none - -!ELSEIF "$(CFG)" == "LzmaLib - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /MTd /W3 /Gm /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /D "COMPRESS_MF_MT" /FD /GZ /c -# SUBTRACT CPP /YX -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x419 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"C:\Util\LZMA.dll" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "LzmaLib - Win32 Release" -# Name "LzmaLib - Win32 Debug" -# Begin Group "Spec" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\LzmaLib.def -# End Source File -# Begin Source File - -SOURCE=.\LzmaLibExports.c -# End Source File -# End Group -# Begin Source File - -SOURCE=..\..\7zTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\Alloc.c -# End Source File -# Begin Source File - -SOURCE=..\..\Alloc.h -# End Source File -# Begin Source File - -SOURCE=..\..\IStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\LzFind.c -# End Source File -# Begin Source File - -SOURCE=..\..\LzFind.h -# End Source File -# Begin Source File - -SOURCE=..\..\LzFindMt.c -# End Source File -# Begin Source File - -SOURCE=..\..\LzFindMt.h -# End Source File -# Begin Source File - -SOURCE=..\..\LzHash.h -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaDec.c -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaDec.h -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaEnc.c -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaEnc.h -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaLib.c -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaLib.h -# End Source File -# Begin Source File - -SOURCE=.\resource.rc -# End Source File -# Begin Source File - -SOURCE=..\..\Threads.c -# End Source File -# Begin Source File - -SOURCE=..\..\Threads.h -# End Source File -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="LzmaLib" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=LzmaLib - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "LzmaLib.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "LzmaLib.mak" CFG="LzmaLib - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "LzmaLib - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "LzmaLib - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "LzmaLib - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /YX /FD /c +# ADD CPP /nologo /Gr /MT /W3 /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"C:\Util\LZMA.dll" /opt:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "LzmaLib - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /D "COMPRESS_MF_MT" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"C:\Util\LZMA.dll" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "LzmaLib - Win32 Release" +# Name "LzmaLib - Win32 Debug" +# Begin Group "Spec" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\LzmaLib.def +# End Source File +# Begin Source File + +SOURCE=.\LzmaLibExports.c +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\7zTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\Alloc.c +# End Source File +# Begin Source File + +SOURCE=..\..\Alloc.h +# End Source File +# Begin Source File + +SOURCE=..\..\IStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\LzFind.c +# End Source File +# Begin Source File + +SOURCE=..\..\LzFind.h +# End Source File +# Begin Source File + +SOURCE=..\..\LzFindMt.c +# End Source File +# Begin Source File + +SOURCE=..\..\LzFindMt.h +# End Source File +# Begin Source File + +SOURCE=..\..\LzHash.h +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaDec.c +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaDec.h +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaEnc.c +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaEnc.h +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaLib.c +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaLib.h +# End Source File +# Begin Source File + +SOURCE=.\resource.rc +# End Source File +# Begin Source File + +SOURCE=..\..\Threads.c +# End Source File +# Begin Source File + +SOURCE=..\..\Threads.h +# End Source File +# End Target +# End Project diff --git a/utils/lzma/C/Util/LzmaLib/LzmaLib.dsw b/utils/lzma/C/Util/LzmaLib/LzmaLib.dsw index 6faf3336..f6c55593 100644 --- a/utils/lzma/C/Util/LzmaLib/LzmaLib.dsw +++ b/utils/lzma/C/Util/LzmaLib/LzmaLib.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "LzmaLib"=.\LzmaLib.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "LzmaLib"=.\LzmaLib.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/utils/lzma/C/Util/LzmaLib/makefile b/utils/lzma/C/Util/LzmaLib/makefile index 74103bb0..e0f31147 100644 --- a/utils/lzma/C/Util/LzmaLib/makefile +++ b/utils/lzma/C/Util/LzmaLib/makefile @@ -1,34 +1,34 @@ -MY_STATIC_LINK=1 -SLIB = sLZMA.lib -PROG = LZMA.dll -SLIBPATH = $O\$(SLIB) - -DEF_FILE = LzmaLib.def -CFLAGS = $(CFLAGS) \ - -LIB_OBJS = \ - $O\LzmaLibExports.obj \ - -C_OBJS = \ - $O\Alloc.obj \ - $O\LzFind.obj \ - $O\LzFindMt.obj \ - $O\LzmaDec.obj \ - $O\LzmaEnc.obj \ - $O\LzmaLib.obj \ - $O\Threads.obj \ - -OBJS = \ - $(LIB_OBJS) \ - $(C_OBJS) \ - $O\resource.res - -!include "../../../CPP/Build.mak" - -$(SLIBPATH): $O $(OBJS) - lib -out:$(SLIBPATH) $(OBJS) $(LIBS) - -$(LIB_OBJS): $(*B).c - $(COMPL_O2) -$(C_OBJS): ../../$(*B).c - $(COMPL_O2) +MY_STATIC_LINK=1 +SLIB = sLZMA.lib +PROG = LZMA.dll +SLIBPATH = $O\$(SLIB) + +DEF_FILE = LzmaLib.def +CFLAGS = $(CFLAGS) \ + +LIB_OBJS = \ + $O\LzmaLibExports.obj \ + +C_OBJS = \ + $O\Alloc.obj \ + $O\LzFind.obj \ + $O\LzFindMt.obj \ + $O\LzmaDec.obj \ + $O\LzmaEnc.obj \ + $O\LzmaLib.obj \ + $O\Threads.obj \ + +OBJS = \ + $(LIB_OBJS) \ + $(C_OBJS) \ + $O\resource.res + +!include "../../../CPP/Build.mak" + +$(SLIBPATH): $O $(OBJS) + lib -out:$(SLIBPATH) $(OBJS) $(LIBS) + +$(LIB_OBJS): $(*B).c + $(COMPL_O2) +$(C_OBJS): ../../$(*B).c + $(COMPL_O2) diff --git a/utils/lzma/C/Util/SfxSetup/SfxSetup.dsp b/utils/lzma/C/Util/SfxSetup/SfxSetup.dsp index 5ce7195b..1d5fdd8a 100644 --- a/utils/lzma/C/Util/SfxSetup/SfxSetup.dsp +++ b/utils/lzma/C/Util/SfxSetup/SfxSetup.dsp @@ -1,211 +1,211 @@ -# Microsoft Developer Studio Project File - Name="SfxSetup" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Application" 0x0101 - -CFG=SfxSetup - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "SfxSetup.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "SfxSetup.mak" CFG="SfxSetup - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "SfxSetup - Win32 Release" (based on "Win32 (x86) Application") -!MESSAGE "SfxSetup - Win32 Debug" (based on "Win32 (x86) Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "SfxSetup - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W4 /WX /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE" /D "UNICODE" /Yu"Precomp.h" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x419 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 - -!ELSEIF "$(CFG)" == "SfxSetup - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE" /D "UNICODE" /Yu"Precomp.h" /FD /GZ /c -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x419 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "SfxSetup - Win32 Release" -# Name "SfxSetup - Win32 Debug" -# Begin Group "Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\7z.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zAlloc.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zAlloc.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zArcIn.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zBuf.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zBuf.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zCrc.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zCrc.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zCrcOpt.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zDec.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zFile.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zFile.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zStream.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\Bcj2.c -# End Source File -# Begin Source File - -SOURCE=..\..\Bcj2.h -# End Source File -# Begin Source File - -SOURCE=..\..\Bra.c -# End Source File -# Begin Source File - -SOURCE=..\..\Bra.h -# End Source File -# Begin Source File - -SOURCE=..\..\Bra86.c -# End Source File -# Begin Source File - -SOURCE=..\..\CpuArch.c -# End Source File -# Begin Source File - -SOURCE=..\..\CpuArch.h -# End Source File -# Begin Source File - -SOURCE=..\..\Lzma2Dec.c -# End Source File -# Begin Source File - -SOURCE=..\..\Lzma2Dec.h -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaDec.c -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaDec.h -# End Source File -# End Group -# Begin Group "Spec" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\Precomp.c -# ADD CPP /Yc"Precomp.h" -# End Source File -# Begin Source File - -SOURCE=.\Precomp.h -# End Source File -# End Group -# Begin Source File - -SOURCE=.\SfxSetup.c -# End Source File -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="SfxSetup" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=SfxSetup - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "SfxSetup.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "SfxSetup.mak" CFG="SfxSetup - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SfxSetup - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "SfxSetup - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SfxSetup - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W4 /WX /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE" /D "UNICODE" /Yu"Precomp.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "SfxSetup - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE" /D "UNICODE" /Yu"Precomp.h" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "SfxSetup - Win32 Release" +# Name "SfxSetup - Win32 Debug" +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\7z.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zAlloc.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zAlloc.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zArcIn.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zBuf.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zBuf.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zCrc.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zCrc.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zCrcOpt.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zDec.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zFile.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zFile.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zStream.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\Bcj2.c +# End Source File +# Begin Source File + +SOURCE=..\..\Bcj2.h +# End Source File +# Begin Source File + +SOURCE=..\..\Bra.c +# End Source File +# Begin Source File + +SOURCE=..\..\Bra.h +# End Source File +# Begin Source File + +SOURCE=..\..\Bra86.c +# End Source File +# Begin Source File + +SOURCE=..\..\CpuArch.c +# End Source File +# Begin Source File + +SOURCE=..\..\CpuArch.h +# End Source File +# Begin Source File + +SOURCE=..\..\Lzma2Dec.c +# End Source File +# Begin Source File + +SOURCE=..\..\Lzma2Dec.h +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaDec.c +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaDec.h +# End Source File +# End Group +# Begin Group "Spec" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Precomp.c +# ADD CPP /Yc"Precomp.h" +# End Source File +# Begin Source File + +SOURCE=.\Precomp.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\SfxSetup.c +# End Source File +# End Target +# End Project diff --git a/utils/lzma/C/Util/SfxSetup/SfxSetup.dsw b/utils/lzma/C/Util/SfxSetup/SfxSetup.dsw index ea231112..128fcdd3 100644 --- a/utils/lzma/C/Util/SfxSetup/SfxSetup.dsw +++ b/utils/lzma/C/Util/SfxSetup/SfxSetup.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "SfxSetup"=.\SfxSetup.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "SfxSetup"=.\SfxSetup.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/utils/lzma/C/Util/SfxSetup/makefile b/utils/lzma/C/Util/SfxSetup/makefile index 5b519807..cc9878af 100644 --- a/utils/lzma/C/Util/SfxSetup/makefile +++ b/utils/lzma/C/Util/SfxSetup/makefile @@ -1,33 +1,33 @@ -PROG = 7zS2.sfx - -C_OBJS = \ - $O\7zAlloc.obj \ - $O\7zArcIn.obj \ - $O\7zBuf.obj \ - $O\7zBuf2.obj \ - $O\7zCrc.obj \ - $O\7zCrcOpt.obj \ - $O\7zFile.obj \ - $O\7zDec.obj \ - $O\7zStream.obj \ - $O\Bcj2.obj \ - $O\Bra.obj \ - $O\Bra86.obj \ - $O\CpuArch.obj \ - $O\Lzma2Dec.obj \ - $O\LzmaDec.obj \ - -7Z_OBJS = \ - $O\SfxSetup.obj \ - -OBJS = \ - $(7Z_OBJS) \ - $(C_OBJS) \ - $O\resource.res - -!include "../../../CPP/Build.mak" - -$(7Z_OBJS): $(*B).c - $(COMPL_O1) -$(C_OBJS): ../../$(*B).c - $(COMPL_O1) +PROG = 7zS2.sfx + +C_OBJS = \ + $O\7zAlloc.obj \ + $O\7zArcIn.obj \ + $O\7zBuf.obj \ + $O\7zBuf2.obj \ + $O\7zCrc.obj \ + $O\7zCrcOpt.obj \ + $O\7zFile.obj \ + $O\7zDec.obj \ + $O\7zStream.obj \ + $O\Bcj2.obj \ + $O\Bra.obj \ + $O\Bra86.obj \ + $O\CpuArch.obj \ + $O\Lzma2Dec.obj \ + $O\LzmaDec.obj \ + +7Z_OBJS = \ + $O\SfxSetup.obj \ + +OBJS = \ + $(7Z_OBJS) \ + $(C_OBJS) \ + $O\resource.res + +!include "../../../CPP/Build.mak" + +$(7Z_OBJS): $(*B).c + $(COMPL_O1) +$(C_OBJS): ../../$(*B).c + $(COMPL_O1) diff --git a/utils/lzma/C/Util/SfxSetup/makefile_con b/utils/lzma/C/Util/SfxSetup/makefile_con index 492191f5..f8bbb1fd 100644 --- a/utils/lzma/C/Util/SfxSetup/makefile_con +++ b/utils/lzma/C/Util/SfxSetup/makefile_con @@ -1,34 +1,34 @@ -PROG = 7zS2con.sfx -CFLAGS = $(CFLAGS) -D_CONSOLE - -C_OBJS = \ - $O\7zAlloc.obj \ - $O\7zArcIn.obj \ - $O\7zBuf.obj \ - $O\7zBuf2.obj \ - $O\7zCrc.obj \ - $O\7zCrcOpt.obj \ - $O\7zFile.obj \ - $O\7zDec.obj \ - $O\7zStream.obj \ - $O\Bcj2.obj \ - $O\Bra.obj \ - $O\Bra86.obj \ - $O\CpuArch.obj \ - $O\Lzma2Dec.obj \ - $O\LzmaDec.obj \ - -7Z_OBJS = \ - $O\SfxSetup.obj \ - -OBJS = \ - $(7Z_OBJS) \ - $(C_OBJS) \ - $O\resource.res - -!include "../../../CPP/Build.mak" - -$(7Z_OBJS): $(*B).c - $(COMPL_O1) -$(C_OBJS): ../../$(*B).c - $(COMPL_O1) +PROG = 7zS2con.sfx +CFLAGS = $(CFLAGS) -D_CONSOLE + +C_OBJS = \ + $O\7zAlloc.obj \ + $O\7zArcIn.obj \ + $O\7zBuf.obj \ + $O\7zBuf2.obj \ + $O\7zCrc.obj \ + $O\7zCrcOpt.obj \ + $O\7zFile.obj \ + $O\7zDec.obj \ + $O\7zStream.obj \ + $O\Bcj2.obj \ + $O\Bra.obj \ + $O\Bra86.obj \ + $O\CpuArch.obj \ + $O\Lzma2Dec.obj \ + $O\LzmaDec.obj \ + +7Z_OBJS = \ + $O\SfxSetup.obj \ + +OBJS = \ + $(7Z_OBJS) \ + $(C_OBJS) \ + $O\resource.res + +!include "../../../CPP/Build.mak" + +$(7Z_OBJS): $(*B).c + $(COMPL_O1) +$(C_OBJS): ../../$(*B).c + $(COMPL_O1) diff --git a/utils/vbsp/disp_vbsp.cpp b/utils/vbsp/disp_vbsp.cpp index f3688595..8802160f 100644 --- a/utils/vbsp/disp_vbsp.cpp +++ b/utils/vbsp/disp_vbsp.cpp @@ -518,6 +518,7 @@ void SnapRemainingVertsToSurface( CCoreDispInfo **ppListBase, ddispinfo_t *pBSPD void EmitDispLMAlphaAndNeighbors() { + int i; Msg( "Finding displacement neighbors...\n" ); diff --git a/utils/vbsp/map.cpp b/utils/vbsp/map.cpp index d39a2d72..7dcc6494 100644 --- a/utils/vbsp/map.cpp +++ b/utils/vbsp/map.cpp @@ -664,6 +664,7 @@ qboolean CMapFile::MakeBrushWindings (mapbrush_t *ob) return true; } + //----------------------------------------------------------------------------- // Purpose: Takes all of the brushes from the current entity and adds them to the // world's brush list. Used by func_detail and func_areaportal. @@ -700,12 +701,16 @@ void CMapFile::MoveBrushesToWorld( entity_t *mapent ) memcpy (mapbrushes + worldbrushes, temp, sizeof(mapbrush_t) * newbrushes); // fix up indexes - entities[0].numbrushes += newbrushes; - for (i=1 ; inumbrushes = 0; + entities[ 0 ].numbrushes += newbrushes; + + { + for ( i = 1; i < num_entities; i++ ) + entities[ i ].firstbrush += newbrushes; + mapent->numbrushes = 0; + } + + free(temp); } //----------------------------------------------------------------------------- @@ -754,13 +759,17 @@ void CMapFile::MoveBrushesToWorldGeneral( entity_t *mapent ) // fix up indexes entities[0].numbrushes += newbrushes; - for (i=1 ; ifirstbrush ) // if we use <=, then we'll remap the passed in ent, which we don't want to + for ( i = 1; i < num_entities; i++ ) { - entities[ i ].firstbrush += newbrushes; + if (entities[ i ].firstbrush < mapent->firstbrush ) // if we use <=, then we'll remap the passed in ent, which we don't want to + { + entities[ i ].firstbrush += newbrushes; + } } } + free (temp); mapent->numbrushes = 0; @@ -1581,11 +1590,12 @@ ChunkFileResult_t CMapFile::LoadEntityCallback(CChunkFile *pFile, int nParam) if ( !strcmp( "func_detail", pClassName ) ) { - MoveBrushesToWorld (mapent); - mapent->numbrushes = 0; - - // clear out this entity - mapent->epairs = NULL; + MoveBrushesToWorld( mapent ); + + mapent->numbrushes = 0; + // clear out this entity + mapent->epairs = NULL; + return(ChunkFile_Ok); } @@ -1971,6 +1981,7 @@ bool CMapFile::DeterminePath( const char *pszBaseFileName, const char *pszInstan //----------------------------------------------------------------------------- void CMapFile::CheckForInstances( const char *pszFileName ) { + if ( this != g_MainMap ) { // all sub-instances will be appended to the main map master list as they are read in // so the main loop below will naturally get to the appended ones. @@ -2019,6 +2030,8 @@ void CMapFile::CheckForInstances( const char *pszFileName ) if ( !strcmp( pEntity, "func_instance" ) ) { char *pInstanceFile = ValueForKey( &entities[ i ], "file" ); + + if ( pInstanceFile[ 0 ] ) { char InstancePath[ MAX_PATH ]; @@ -2368,7 +2381,9 @@ void CMapFile::MergeEntities( entity_t *pInstanceEntity, CMapFile *Instance, Vec entities[ num_entities + i ] = Instance->entities[ i ]; entity_t *entity = &entities[ num_entities + i ]; - entity->firstbrush += ( nummapbrushes - Instance->nummapbrushes ); + { + entity->firstbrush += ( nummapbrushes - Instance->nummapbrushes ); + } char *pID = ValueForKey( entity, "hammerid" ); if ( pID[ 0 ] ) @@ -2403,21 +2418,21 @@ void CMapFile::MergeEntities( entity_t *pInstanceEntity, CMapFile *Instance, Vec GDclass *EntClass = GD.BeginInstanceRemap( pEntity, NameFixup, InstanceOrigin, InstanceAngle ); if ( EntClass ) { - for( int i = 0; i < EntClass->GetVariableCount(); i++ ) + for( int j = 0; j < EntClass->GetVariableCount(); j++ ) { - GDinputvariable *EntVar = EntClass->GetVariableAt( i ); + GDinputvariable *EntVar = EntClass->GetVariableAt( j ); char *pValue = ValueForKey( entity, ( char * )EntVar->GetName() ); if ( GD.RemapKeyValue( EntVar->GetName(), pValue, temp, FixupStyle ) ) { #ifdef MERGE_INSTANCE_DEBUG_INFO - Msg( " %d. Remapped %s: from %s to %s\n", i, EntVar->GetName(), pValue, temp ); + Msg( " %d. Remapped %s: from %s to %s\n", j, EntVar->GetName(), pValue, temp ); #endif // #ifdef MERGE_INSTANCE_DEBUG_INFO SetKeyValue( entity, EntVar->GetName(), temp ); } else { #ifdef MERGE_INSTANCE_DEBUG_INFO - Msg( " %d. Ignored %s: %s\n", i, EntVar->GetName(), pValue ); + Msg( " %d. Ignored %s: %s\n", j, EntVar->GetName(), pValue ); #endif // #ifdef MERGE_INSTANCE_DEBUG_INFO } } diff --git a/utils/vbsp/overlay.cpp b/utils/vbsp/overlay.cpp index edceba9a..b5a2af35 100644 --- a/utils/vbsp/overlay.cpp +++ b/utils/vbsp/overlay.cpp @@ -206,6 +206,7 @@ void OverlayTransition_AddFaceToLists( int iFace, side_t *pSide ) //----------------------------------------------------------------------------- void Overlay_EmitOverlayFace( mapoverlay_t *pMapOverlay ) { + Assert( g_nOverlayCount < MAX_MAP_OVERLAYS ); if ( g_nOverlayCount >= MAX_MAP_OVERLAYS ) { @@ -296,6 +297,7 @@ void Overlay_EmitOverlayFace( mapoverlay_t *pMapOverlay ) //----------------------------------------------------------------------------- void OverlayTransition_EmitOverlayFace( mapoverlay_t *pMapOverlay ) { + Assert( g_nWaterOverlayCount < MAX_MAP_WATEROVERLAYS ); if ( g_nWaterOverlayCount >= MAX_MAP_WATEROVERLAYS ) { @@ -378,6 +380,7 @@ void OverlayTransition_EmitOverlayFace( mapoverlay_t *pMapOverlay ) //----------------------------------------------------------------------------- void Overlay_EmitOverlayFaces( void ) { + int nMapOverlayCount = g_aMapOverlays.Count(); for( int iMapOverlay = 0; iMapOverlay < nMapOverlayCount; ++iMapOverlay ) { @@ -390,6 +393,7 @@ void Overlay_EmitOverlayFaces( void ) //----------------------------------------------------------------------------- void OverlayTransition_EmitOverlayFaces( void ) { + int nMapOverlayCount = g_aMapWaterOverlays.Count(); for( int iMapOverlay = 0; iMapOverlay < nMapOverlayCount; ++iMapOverlay ) { diff --git a/utils/vbsp/staticprop.cpp b/utils/vbsp/staticprop.cpp index 3ba775ea..3f00d0d2 100644 --- a/utils/vbsp/staticprop.cpp +++ b/utils/vbsp/staticprop.cpp @@ -569,6 +569,7 @@ static void SetLumpData( ) void EmitStaticProps() { + CreateInterfaceFn physicsFactory = GetPhysicsFactory(); if ( physicsFactory ) { diff --git a/utils/vbsp/vbsp.cpp b/utils/vbsp/vbsp.cpp index 7b8c0593..fc69b33d 100644 --- a/utils/vbsp/vbsp.cpp +++ b/utils/vbsp/vbsp.cpp @@ -84,6 +84,7 @@ int entity_num; node_t *block_nodes[BLOCKS_SPACE+2][BLOCKS_SPACE+2]; + //----------------------------------------------------------------------------- // Assign occluder areas (must happen *after* the world model is processed) //----------------------------------------------------------------------------- @@ -201,8 +202,10 @@ ProcessWorldModel ============ */ void SplitSubdividedFaces( node_t *headnode ); // garymcthack +void ProcessSubModel(); // fwd decl void ProcessWorldModel (void) { + entity_t *e; tree_t *tree = NULL; qboolean leaked; @@ -392,32 +395,49 @@ void ProcessSubModel( ) mins[0] = mins[1] = mins[2] = MIN_COORD_INTEGER; maxs[0] = maxs[1] = maxs[2] = MAX_COORD_INTEGER; - list = MakeBspBrushList (start, end, mins, maxs, FULL_DETAIL); + int nDetailScreen = FULL_DETAIL; + list = MakeBspBrushList( start, end, mins, maxs, nDetailScreen ); if (!nocsg) list = ChopBrushes (list); tree = BrushBSP (list, mins, maxs); // This would wind up crashing the engine because we'd have a negative leaf index in dmodel_t::headnode. - if ( tree->headnode->planenum == PLANENUM_LEAF ) + if ( ( tree->headnode->planenum == PLANENUM_LEAF ) + ) { const char *pClassName = ValueForKey( e, "classname" ); const char *pTargetName = ValueForKey( e, "targetname" ); Error( "bmodel %d has no head node (class '%s', targetname '%s')", entity_num, pClassName, pTargetName ); } - MakeTreePortals (tree); + { + MakeTreePortals(tree); + } #if DEBUG_BRUSHMODEL if ( entity_num == DEBUG_BRUSHMODEL ) WriteGLView( tree, "tree_all" ); #endif - MarkVisibleSides (tree, start, end, FULL_DETAIL); + MarkVisibleSides( tree, start, end, nDetailScreen ); MakeFaces (tree->headnode); - FixTjuncs( tree->headnode, NULL ); - WriteBSP( tree->headnode, NULL ); + if ( nDetailScreen == NO_DETAIL ) + { + face_t* pLeafFaceList = NULL; + if ( !nodetail ) + { + pLeafFaceList = MergeDetailTree( tree, start, end ); + } + pLeafFaceList = FixTjuncs( tree->headnode, pLeafFaceList ); + WriteBSP( tree->headnode, pLeafFaceList ); + } + else + { + FixTjuncs( tree->headnode, NULL ); + WriteBSP( tree->headnode, NULL ); + } #if DEBUG_BRUSHMODEL if ( entity_num == DEBUG_BRUSHMODEL ) @@ -654,7 +674,9 @@ static void EmitOccluderBrushes() occluderData.polycount = g_OccluderPolyData.Count() - occluderData.firstpoly; // Mark this brush as not having brush geometry so it won't be re-emitted with a brush model - entities[entity_num].numbrushes = 0; + { + entities[ entity_num ].numbrushes = 0; + } } FreeTree( pOccluderTree ); @@ -759,7 +781,6 @@ void FixupOnlyEntsOccluderEntities() } } - void MarkNoDynamicShadowSides() { for ( int iSide=0; iSide < g_MainMap->nummapbrushsides; iSide++ ) @@ -837,6 +858,7 @@ void ProcessModels (void) if ( !pEntity->numbrushes ) continue; + qprintf ("############### model %i ###############\n", nummodels); BeginModel (); diff --git a/utils/vbsp/vbsp.h b/utils/vbsp/vbsp.h index 689bbaa8..0cd3f39b 100644 --- a/utils/vbsp/vbsp.h +++ b/utils/vbsp/vbsp.h @@ -638,6 +638,7 @@ struct mapoverlay_t extern CUtlVector g_aMapOverlays; extern CUtlVector g_aMapWaterOverlays; + int Overlay_GetFromEntity( entity_t *pMapEnt ); void Overlay_UpdateSideLists( int StartIndex ); void Overlay_AddFaceToLists( int iFace, side_t *pSide ); diff --git a/utils/vbsp/worldvertextransitionfixup.cpp b/utils/vbsp/worldvertextransitionfixup.cpp index f97f3933..b4483462 100644 --- a/utils/vbsp/worldvertextransitionfixup.cpp +++ b/utils/vbsp/worldvertextransitionfixup.cpp @@ -163,6 +163,7 @@ const char *GetShaderNameForTexInfo( int iTexInfo ) void WorldVertexTransitionFixup( void ) { + CUtlVector sideList; sideList.SetCount( g_MainMap->num_entities ); int i; diff --git a/utils/vbsp/writebsp.cpp b/utils/vbsp/writebsp.cpp index 005990d6..c3bc09d6 100644 --- a/utils/vbsp/writebsp.cpp +++ b/utils/vbsp/writebsp.cpp @@ -406,6 +406,7 @@ int FindOrCreateOrigFace( face_t *f ) return index; } + /* ================== EmitFace @@ -432,7 +433,8 @@ void EmitFace( face_t *f, qboolean onNode ) return; // don't emit NODRAW faces for runtime - if ( texinfo[f->texinfo].flags & SURF_NODRAW ) + if ( + ( texinfo[ f->texinfo ].flags & SURF_NODRAW ) ) { // keep NODRAW terrain surfaces though if ( f->dispinfo == -1 ) @@ -454,6 +456,7 @@ void EmitFace( face_t *f, qboolean onNode ) dfaceids.AddToTail(); dfaceids[numfaces].hammerfaceid = f->originalface->id; + numfaces++; // @@ -1256,8 +1259,10 @@ void EndBSPFile (void) Overlay_EmitOverlayFaces(); OverlayTransition_EmitOverlayFaces(); - // phys collision needs dispinfo to operate (needs to generate phys collision for displacement surfs) - EmitPhysCollision(); + { + // phys collision needs dispinfo to operate (needs to generate phys collision for displacement surfs) + EmitPhysCollision(); + } // We can't calculate this properly until vvis (since we need vis to do this), so we set // to zero everywhere by default. @@ -1275,6 +1280,7 @@ void EndBSPFile (void) // Make sure that we have a water lod control eneity if we have water in the map. EnsurePresenceOfWaterLODControlEntity(); + // Doing this here because stuff about may filter out entities UnparseEntities (); diff --git a/vgui2/matsys_controls/QCGenerator.cpp b/vgui2/matsys_controls/QCGenerator.cpp new file mode 100644 index 00000000..5a7d2be4 --- /dev/null +++ b/vgui2/matsys_controls/QCGenerator.cpp @@ -0,0 +1,727 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#if defined(WIN32) && !defined( _X360 ) +#include +#endif +#include "filesystem.h" +#include "filesystem_init.h" +#include "appframework/IAppSystemGroup.h" +#include "appframework/IAppSystem.h" +#include "appframework/AppFramework.h" +#include "filesystem_helpers.h" + +#include "matsys_controls/QCGenerator.h" +#include "tier1/KeyValues.h" +#include "tier2/vconfig.h" +#include "vgui_controls/ListPanel.h" +#include "vgui_controls/TextEntry.h" +#include "vgui_controls/Button.h" +#include "vgui_controls/FileOpenDialog.h" +#include "vgui_controls/DirectorySelectDialog.h" +#include "vgui_controls/ComboBox.h" +#include "vgui_controls/CheckButton.h" +#include "vgui_controls/MessageBox.h" +#include "vgui/ISurface.h" +#include "vgui/IInput.h" +#include "vgui/Cursor.h" +#include "vgui_controls/KeyBoardEditorDialog.h" + +#if defined( _X360 ) +#include "xbox/xbox_win32stubs.h" +#endif + +using namespace vgui; + +#define MAX_KEYVALUE 1024 + + +//----------------------------------------------------------------------------- +// Purpose: returns a pointer to the 'count' occurence of a character from the end of a string +// returns 0 of there aren't 'count' number of the character in the string +//----------------------------------------------------------------------------- +char *strrchrcount(char *string, int character, int count ) +{ + int j = count; + int numChars = V_strlen( string ); + for( int i = numChars; i > 0; i-- ) + { + if( string[i-1] == character ) + { + j--; + } + if( j == 0 ) + { + return string + i-1; + } + } + return 0; +} + + + +class CModalPreserveMessageBox : public vgui::MessageBox +{ +public: + CModalPreserveMessageBox(const char *title, const char *text, vgui::Panel *parent) + : vgui::MessageBox( title, text, parent ) + { + m_PrevAppFocusPanel = vgui::input()->GetAppModalSurface(); + } + + ~CModalPreserveMessageBox() + { + vgui::input()->SetAppModalSurface( m_PrevAppFocusPanel ); + } + + +public: + vgui::VPANEL m_PrevAppFocusPanel; +}; + +void VGUIMessageBox( vgui::Panel *pParent, const char *pTitle, const char *pMsg, ... ) +{ + char msg[4096]; + va_list marker; + va_start( marker, pMsg ); + Q_vsnprintf( msg, sizeof( msg ), pMsg, marker ); + va_end( marker ); + + vgui::MessageBox *dlg = new CModalPreserveMessageBox( pTitle, msg, pParent ); + dlg->DoModal(); + dlg->Activate(); + dlg->RequestFocus(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Places all the info from the vgui controls into the QCInfo struct +//----------------------------------------------------------------------------- +void QCInfo::SyncFromControls() +{ + char tempText[MAX_PATH]; + + vgui::Panel *pTargetField = pQCGenerator->FindChildByName( "staticPropCheck" ); + bStaticProp = ((CheckButton *)pTargetField)->IsSelected(); + + pTargetField = pQCGenerator->FindChildByName( "mostlyOpaqueCheck" ); + bMostlyOpaque = ((CheckButton *)pTargetField)->IsSelected(); + + pTargetField = pQCGenerator->FindChildByName( "disableCollisionsCheck" ); + bDisableCollision = ((CheckButton *)pTargetField)->IsSelected(); + + pTargetField = pQCGenerator->FindChildByName( "referencePhysicsCheck" ); + bReferenceAsPhys = ((CheckButton *)pTargetField)->IsSelected(); + + pTargetField = pQCGenerator->FindChildByName( "concaveCheck" ); + bConcave = ((CheckButton *)pTargetField)->IsSelected(); + + pTargetField = pQCGenerator->FindChildByName( "automassCheck" ); + bAutomass = ((CheckButton *)pTargetField)->IsSelected(); + + pTargetField = pQCGenerator->FindChildByName( "massField" ); + ((TextEntry *)pTargetField)->GetText(tempText, MAX_PATH); + fMass = atof(tempText); + + pTargetField = pQCGenerator->FindChildByName( "scaleField" ); + ((TextEntry *)pTargetField)->GetText(tempText, MAX_PATH); + fScale = atof(tempText); + + pTargetField = pQCGenerator->FindChildByName( "collisionSMDField" ); + ((TextEntry *)pTargetField)->GetText( tempText, MAX_PATH ); + V_strcpy_safe( pszCollisionPath, tempText ); + + pTargetField = pQCGenerator->FindChildByName( "surfacePropertyDropDown" ); + ((ComboBox *)pTargetField)->GetText( tempText, MAX_PATH ); + V_strcpy_safe( pszSurfaceProperty, tempText ); + + pTargetField = pQCGenerator->FindChildByName( "materialsField" ); + ((TextEntry *)pTargetField)->GetText( tempText, MAX_PATH ); + V_strcpy_safe( pszMaterialPath, tempText ); + + LODs.RemoveAll(); + pTargetField = pQCGenerator->FindChildByName( "LODList" ); + int numLOD = ((ListPanel *)pTargetField)->GetItemCount(); + for ( int i = 0; i < numLOD; i++ ) + { + KeyValues *key = ((ListPanel *)pTargetField)->GetItem( i ); + LODInfo newLOD; + + V_strcpy_safe( newLOD.pszFilename, key->GetString( "SMD" ) ); + newLOD.iLOD = key->GetInt( "LOD" ); + LODs.AddToTail( newLOD ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Called during intialization to setup the initial state of the VGUI controls +//----------------------------------------------------------------------------- +void QCInfo::SyncToControls() +{ + char tempText[MAX_PATH]; + + vgui::Panel *pTargetField = pQCGenerator->FindChildByName( "staticPropCheck" ); + ((CheckButton *)pTargetField)->SetSelected( bStaticProp ); + + pTargetField = pQCGenerator->FindChildByName( "mostlyOpaqueCheck" ); + ((CheckButton *)pTargetField)->SetSelected( bMostlyOpaque ); + + pTargetField = pQCGenerator->FindChildByName( "disableCollisionsCheck" ); + ((CheckButton *)pTargetField)->SetSelected( bDisableCollision ); + + pTargetField = pQCGenerator->FindChildByName( "referencePhysicsCheck" ); + ((CheckButton *)pTargetField)->SetSelected( bReferenceAsPhys ); + + pTargetField = pQCGenerator->FindChildByName( "concaveCheck" ); + ((CheckButton *)pTargetField)->SetSelected( bConcave ); + + pTargetField = pQCGenerator->FindChildByName( "automassCheck" ); + ((CheckButton *)pTargetField)->SetSelected( bAutomass ); + + Q_snprintf( tempText, 10, "%d", (int)fMass ); + pTargetField = pQCGenerator->FindChildByName( "massField" ); + ((TextEntry *)pTargetField)->SetText( tempText ); + + Q_snprintf( tempText, 10, "%d", (int)fScale ); + pTargetField = pQCGenerator->FindChildByName( "scaleField" ); + ((TextEntry *)pTargetField)->SetText( tempText ); + + pTargetField = pQCGenerator->FindChildByName( "collisionSMDField" ); + ((TextEntry *)pTargetField)->SetText( pszCollisionPath ); + + pTargetField = pQCGenerator->FindChildByName( "materialsField" ); + ((TextEntry *)pTargetField)->SetText( pszMaterialPath ); + + pTargetField = pQCGenerator->FindChildByName( "surfacePropertyDropDown" ); + int numItems = ((ComboBox *)pTargetField)->GetItemCount(); + for( int i = 0; i < numItems; i++ ) + { + ((ComboBox *)pTargetField)->GetItemText( i, tempText, MAX_PATH ); + if ( !Q_strcmp( tempText, pszSurfaceProperty ) ) + { + ((ComboBox *)pTargetField)->SetItemEnabled( i, true ); + ((ComboBox *)pTargetField)->SetText( tempText ); + break; + } + } +} + +CBrowseButton::CBrowseButton( vgui::Panel *pParent ) : BaseClass( pParent, "Browse Button", "...", pParent, "browse" ) +{ + SetParent( pParent ); + pszStartingDirectory = NULL; + pszFileFilter = NULL; + pszTargetField = NULL; +} + +CBrowseButton::~CBrowseButton() +{ +} + +void CBrowseButton::SetCharVar( char **pVar, const char *pszNewText ) +{ + if ( *pVar && pszNewText && !Q_strcmp( *pVar, pszNewText ) ) + { + return; + } + + if ( *pVar ) + { + delete [] *pVar; + *pVar = NULL; + } + + if ( pszNewText ) + { + int len = Q_strlen( pszNewText ) + 1; + *pVar = new char[ len ]; + Q_strncpy( *pVar, pszNewText, len ); + } +} + +void CBrowseButton::InitBrowseInfo( int x, int y, const char *pszName, const char *pszDir, const char *pszFilter, const char *pszField ) +{ + SetSize( 24, 24 ); + SetPos( x, y ); + SetName( pszName ); + SetCharVar( GetStartingDirectory(), pszDir ); + SetCharVar( GetFileFilter(), pszFilter ); + SetCharVar( GetTargetField(), pszField ); + SetActionMessage(); +} + +void CBrowseButton::SetActionMessage() +{ + KeyValues *newActionMessage = new KeyValues( "browse", "directory", pszStartingDirectory, "filter", pszFileFilter); + newActionMessage->SetString( "targetField", pszTargetField ); + SetCommand( newActionMessage ); +} + +const char *ParseKeyvalue( const char *pBuffer, char *key, char *value ) +{ + char com_token[1024]; + + pBuffer = (const char *)ParseFile( pBuffer, com_token, NULL ); + if ( Q_strlen( com_token ) < MAX_KEYVALUE ) + { + Q_strncpy( key, com_token, MAX_KEYVALUE ); + Q_strlower( key ); + } + // no value on a close brace + if ( !Q_strcmp( key, "}" ) ) + { + value[0] = 0; + return pBuffer; + } + + pBuffer = (const char *)ParseFile( pBuffer, com_token, NULL ); + if ( Q_strlen( com_token ) < MAX_KEYVALUE ) + { + Q_strncpy( value, com_token, MAX_KEYVALUE ); + Q_strlower( value ); + } + + return pBuffer; +} + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CQCGenerator::CQCGenerator( vgui::Panel *pParent, const char *pszPath, const char *pszScene ) : BaseClass( pParent, "QCGenerator" ) +{ + m_szTargetField[0] = 0; + m_nSelectedSequence = 0; + m_nSelectedColumn = 0; + + m_QCInfo_t.Init( this ); + + SetMinimumSize(846, 770); + + m_pLODPanel = new ListPanel(this, "LODList"); + m_pLODPanel->SetSelectIndividualCells( true ); + m_pLODPanel->AddColumnHeader(0, "SMD", "LOD SMD", 450, 0); + m_pLODPanel->AddColumnHeader(1, "LOD", "LOD Distance", 50, 0); + m_pLODPanel->AddActionSignalTarget( this ); + m_pLODPanel->SetMouseInputEnabled( true ); + + LoadControlSettings( "QCGenerator.res" ); + + m_pCollisionBrowseButton = new CBrowseButton( this ); + m_pCollisionBrowseButton->InitBrowseInfo( 808, 158, "collisionBrowseButton", pszPath, "*.smd", "collisionSMDField" ); + + char szTerminatedPath[1024] = "\0"; + sprintf( szTerminatedPath, "%s\\", pszPath ); + + InitializeSMDPaths( szTerminatedPath, pszScene ); + + char *pszMaterialsStart = strrchrcount( szTerminatedPath, '\\', 3 ) + 1; + char *pszMaterialsEnd = strrchr( szTerminatedPath, '\\'); + Q_strncpy( m_QCInfo_t.pszMaterialPath, pszMaterialsStart, pszMaterialsEnd - pszMaterialsStart + 1 ); + + SetParent( pParent ); + + char szGamePath[1024] = "\0"; + char szSearchPath[1024] = "\0"; + + // Get the currently set game configuration + GetVConfigRegistrySetting( GAMEDIR_TOKEN, szGamePath, sizeof( szGamePath ) ); + static const char *pSurfacePropFilename = "\\scripts\\surfaceproperties.txt"; + + sprintf( szSearchPath, "%s%s", szGamePath, pSurfacePropFilename ); + + FileHandle_t fp = g_pFullFileSystem->Open( szSearchPath, "rb" ); + + if ( !fp ) + { + //the set game configuration didn't have a surfaceproperties file; we are grabbing it from hl2 + //TODO: This only works if they are in a subdirectory that is a peer to an hl2 directory + // that contains the file. It potentially needs to search the entire drive or prompt for the location + char *pszEndGamePath = Q_strrchr( szGamePath, '\\' ); + pszEndGamePath[0] = 0; + V_strcat_safe( szGamePath, "\\hl2" ); + sprintf( szSearchPath, "%s%s", szGamePath, pSurfacePropFilename ); + fp = g_pFullFileSystem->Open( szSearchPath, "rb" ); + } + + int len = g_pFullFileSystem->Size( fp ); + + const char *szSurfacePropContents = new char[len+1]; + g_pFullFileSystem->Read( (void *)szSurfacePropContents, len, fp ); + + char key[MAX_KEYVALUE], value[MAX_KEYVALUE]; + + vgui::Panel *pSurfacePropDropDown = FindChildByName( "surfacePropertyDropDown" ); + + //filling up the surface property dropdown + while ( szSurfacePropContents ) + { + szSurfacePropContents = ParseKeyvalue( szSurfacePropContents, key, value ); + ((ComboBox *)pSurfacePropDropDown)->AddItem( key, NULL ); + while ( szSurfacePropContents ) + { + szSurfacePropContents = ParseKeyvalue( szSurfacePropContents, key, value ); + if (!stricmp( key, "}" ) ) + { + break; + } + } + } + m_QCInfo_t.SyncToControls(); + + m_pLODEdit = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: Destructor +//----------------------------------------------------------------------------- +CQCGenerator::~CQCGenerator() +{ +} + +void CQCGenerator::OnCommand( const char *command ) +{ + if ( Q_stricmp( command, "createQC" ) == 0 ) + { + m_QCInfo_t.SyncFromControls(); + GenerateQCFile(); + } + if ( Q_stricmp( command, "deleteSeq" ) == 0 ) + { + //delete it + DeleteLOD(); + } + if ( Q_stricmp( command, "editSeq" ) == 0 ) + { + //edit + EditLOD(); + } + + BaseClass::OnCommand( command ); +} + + +void CQCGenerator::OnKeyCodeTyped( KeyCode code ) +{ + switch ( code ) + { + case KEY_ENTER: + EditLOD(); + } +} + + +void CQCGenerator::OnBrowse( KeyValues *data ) +{ + V_strcpy_safe( m_szTargetField, data->GetString( "targetField" ) ); + const char *filter = data->GetString( "filter" ); + + if ( Q_strlen( filter ) == 0 ) + { +// BrowseDirectory( data ); + } + else + { + BrowseFile( data ); + } +} + +/* +//This function is no longer used in the current version of the program. +void CQCGenerator::BrowseDirectory( KeyValues *data ) +{ + DirectorySelectDialog *pDialog = new DirectorySelectDialog( this, "Select Directory" ); + pDialog->AddActionSignalTarget( this ); + pDialog->DoModal(); + pDialog->SetStartDirectory( data->GetString( "directory" ) ); +} +*/ + +void CQCGenerator::BrowseFile( KeyValues *data ) +{ + const char *filter = data->GetString( "filter" ); + + FileOpenDialog *pDialog = new FileOpenDialog( this, "Select File", true ); + pDialog->AddFilter( filter, filter, true ); + pDialog->AddActionSignalTarget(this); + pDialog->SetStartDirectory( data->GetString( "directory" ) ); + pDialog->DoModal( true ); +} + +void CQCGenerator::OnFileSelected( KeyValues *data ) +{ + if ( *m_szTargetField ) + { + vgui::Panel *pTargetField = FindChildByName( m_szTargetField ); + ((TextEntry *)pTargetField)->SetText( data->GetString( "fullpath" ) ); + Repaint(); + } +} + +void CQCGenerator::OnDirectorySelected( KeyValues *data ) +{ + if ( *m_szTargetField ) + { + vgui::Panel *pTargetField = FindChildByName( m_szTargetField ); + ((TextEntry *)pTargetField)->SetText( data->GetString( "dir" ) ); + Repaint(); + } +} + +bool CQCGenerator::GenerateQCFile() +{ + //TODO: clean this up. Consider creating a datatype that includes the string to write out when the QC file is created + char *nameBegin = strrchr( m_QCInfo_t.pszSMDPath, '\\' ); + + char szPath[MAX_PATH]; + char szName[MAX_PATH]; + Q_strncpy( szPath, m_QCInfo_t.pszSMDPath, nameBegin - m_QCInfo_t.pszSMDPath + 2 ); + V_strcpy_safe( szName, szPath); + V_strcat_safe( szName, m_QCInfo_t.pszSceneName); + V_strcat_safe( szName, ".qc" ); + FileHandle_t pSaveFile = g_pFullFileSystem->Open( szName, "wt" ); + if (!pSaveFile) + { + char szSaveError[1024] = ""; + Q_snprintf( szSaveError, 1024, "Save failed: invalid file name '%s'\n\nDirectory '%s' must exist.", szName, szPath ); + VGUIMessageBox( this, "QC Generator error", szSaveError ); + return 0; + } + + //write qc header + g_pFullFileSystem->FPrintf( pSaveFile, "//\n// .qc file version 1.0\n\n"); + //write out modelname info + char szModelName[MAX_PATH]; + char *modelStart = strrchrcount( szName, '\\', 2) + 1; + char *modelEnd = strrchr( szName, '.' ); + Q_strncpy( szModelName, modelStart, modelEnd - modelStart + 1 ); + V_strcat_safe( szModelName, ".mdl" ); + g_pFullFileSystem->FPrintf( pSaveFile, "$modelname %s\n\n", szModelName ); + //write out scale info + g_pFullFileSystem->FPrintf( pSaveFile, "$scale %f\n", m_QCInfo_t.fScale ); + //write out body info + g_pFullFileSystem->FPrintf( pSaveFile, "$body \"Body\" \"%s\"\n", strrchr( m_QCInfo_t.pszSMDPath, '\\' ) + 1 ); + + if ( m_QCInfo_t.bStaticProp == true ) + { + g_pFullFileSystem->FPrintf( pSaveFile, "$staticprop\n" ); + } + + if ( m_QCInfo_t.bMostlyOpaque == true ) + { + g_pFullFileSystem->FPrintf( pSaveFile, "$mostlyopaque\n" ); + } + + //write out surfaceprop info + g_pFullFileSystem->FPrintf( pSaveFile, "$surfaceprop \"%s\"\n\n", m_QCInfo_t.pszSurfaceProperty ); + //write materials + + g_pFullFileSystem->FPrintf( pSaveFile, "$cdmaterials %s\n\n", m_QCInfo_t.pszMaterialPath); + + if ( m_QCInfo_t.bStaticProp || m_QCInfo_t.bNoAnimation ) + { + g_pFullFileSystem->FPrintf( pSaveFile, "// --------- Animation sequences -------\n"); + g_pFullFileSystem->FPrintf( pSaveFile, "$sequence \"idle\" \"%s\" fps 30\n\n", strrchr(m_QCInfo_t.pszSMDPath, '\\')+1); + } + + //write out lod info + for( int i = 0; i < m_QCInfo_t.LODs.Count(); i++ ) + { + LODInfo thisLOD = m_QCInfo_t.LODs.Element( i ); + g_pFullFileSystem->FPrintf( pSaveFile, "$lod %d\n{\n\treplacemodel \"%s\" \"%s\"\n}\n\n", thisLOD.iLOD, strrchr(m_QCInfo_t.pszSMDPath, '\\')+1, thisLOD.pszFilename ); + } + + if ( m_QCInfo_t.bDisableCollision != true ) + { + //write out collision header + g_pFullFileSystem->FPrintf( pSaveFile, "\n" ); + //write out collision info + if ( m_QCInfo_t.bReferenceAsPhys == true ) + { + g_pFullFileSystem->FPrintf( pSaveFile, "$collisionmodel \"%s\"", strrchr( m_QCInfo_t.pszSMDPath, '\\' ) + 1 ); + } + else + { + if( Q_strcmp( m_QCInfo_t.pszCollisionPath, "" ) ) + { + g_pFullFileSystem->FPrintf( pSaveFile, "$collisionmodel \"%s\"", strrchr( m_QCInfo_t.pszCollisionPath, '\\' ) + 1 ); + } + } + + g_pFullFileSystem->FPrintf( pSaveFile, " {\n\t// Mass in kilograms\n "); + + if ( m_QCInfo_t.bAutomass == true ) + { + g_pFullFileSystem->FPrintf( pSaveFile, "\t$automass\n" ); + } + else + { + g_pFullFileSystem->FPrintf( pSaveFile, "\t$mass %f\n", m_QCInfo_t.fMass ); + } + + if ( m_QCInfo_t.bConcave == true ) + { + g_pFullFileSystem->FPrintf( pSaveFile, "\t$concave\n" ); + } + g_pFullFileSystem->FPrintf( pSaveFile, "}\n\n"); + } + + g_pFullFileSystem->Close( pSaveFile ); + + char szCommand[MAX_PATH]; + char szGamePath[MAX_PATH]; + + char studiomdlPath[512]; + g_pFullFileSystem->RelativePathToFullPath( "studiomdl.bat", NULL, studiomdlPath, sizeof( studiomdlPath )); + + GetVConfigRegistrySetting( GAMEDIR_TOKEN, szGamePath, sizeof( szGamePath ) ); + +#ifdef WIN32 + STARTUPINFO startup; + PROCESS_INFORMATION process; + + + memset(&startup, 0, sizeof(startup)); + startup.cb = sizeof(startup); + + + sprintf( szCommand, "%s -game %s %s", studiomdlPath, szGamePath, szName); + bool bReturn = CreateProcess( NULL, szCommand, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &startup, &process); +#else + Assert( !"Implement me, why aren't we using a thread tool abstraction?" ); + bool bReturn = false; +#endif + return bReturn; +} + +void CQCGenerator::InitializeSMDPaths( const char *pszPath, const char *pszScene ) +{ + V_strcpy_safe( m_QCInfo_t.pszSceneName, pszScene ); + + FileFindHandle_t *pFileHandle = new FileFindHandle_t(); + + g_pFullFileSystem->AddSearchPath( pszPath, "SMD_DIR" ); + + const char *filename = g_pFullFileSystem->FindFirst( "*.smd", pFileHandle ); + + bool bFoundReference = false; + bool bFoundCollision = false; + bool bFoundLOD = false; + + //iterate through .smd files + const char *startName = pszScene; + + int nSearchLength = Q_strlen( pszScene ); + + int currentLOD = 1; + + while( filename ) + { + if ( !strncmp( startName, filename, nSearchLength ) ) + { + const char *filenameEnd = filename + nSearchLength; + if ( !strncmp( filenameEnd, "_ref", 4 ) || !strncmp( filenameEnd, ".smd", 4 ) ) + { + bFoundReference = true; + //we have found the reference smd. + V_strcpy_safe( m_QCInfo_t.pszSMDPath, pszPath ); + V_strcat_safe( m_QCInfo_t.pszSMDPath, filename ); + } + if ( !strncmp( filenameEnd, "_phy", 4) || !strncmp( filenameEnd, "_col", 4 ) ) + { + bFoundCollision = true; + //we have found the collision smd. + V_strcpy_safe( m_QCInfo_t.pszCollisionPath, pszPath ); + V_strcat_safe( m_QCInfo_t.pszCollisionPath, filename ); + } + if ( !strncmp( filenameEnd, "_lod", 4) ) + { + bFoundLOD = true; + //we found an LOD smd. + char lodName[255]; + Q_snprintf( lodName, Q_strlen( lodName ), "lod%d", currentLOD ); + //we found an LOD + KeyValues *newKv = new KeyValues( lodName, "SMD", filename, "LOD", "10" ); + m_pLODPanel->AddItem( newKv, currentLOD, false, false ); + currentLOD++; + } + } + filename = g_pFullFileSystem->FindNext( *pFileHandle ); + } + char pszMessage[2048] = ""; + char pszRefMessage[1024] = ""; + char pszColMessage[1024] = ""; + if (!bFoundReference ) + { + V_strcat_safe( m_QCInfo_t.pszSMDPath, pszPath ); + V_strcat_safe( m_QCInfo_t.pszSMDPath, pszScene ); + V_strcat_safe( m_QCInfo_t.pszSMDPath, ".smd" ); + Q_snprintf( pszRefMessage, 1024, "Reference SMD not found.\n\nValid default reference SMDs are %s%s_ref*.smd and %s%s.smd\nUsing default of %s. Model will not compile.\n\n", pszPath, pszScene, pszPath, pszScene, m_QCInfo_t.pszSMDPath ); + } + if ( !bFoundCollision ) + { + Q_snprintf( pszColMessage, 1024, "Collision SMD not found.\n\nThe valid default collision SMD is %s%s_phy*.smd.\nUsing reference SMD as default.\n", pszPath, pszScene ); + V_strcpy_safe( m_QCInfo_t.pszCollisionPath, m_QCInfo_t.pszSMDPath ); + m_QCInfo_t.bReferenceAsPhys = true; + } + if ( !bFoundReference || !bFoundCollision) + { + V_strcpy_safe( pszMessage, pszRefMessage ); + V_strcat_safe( pszMessage, pszColMessage ); + VGUIMessageBox( this, "Error Initializing Paths", pszMessage ); + } +} + + +void CQCGenerator::DeleteLOD() +{ + int numSelected = m_pLODPanel->GetSelectedItemsCount(); + int selected; + for ( int i = numSelected-1; i >= 0; i-- ) + { + selected = m_pLODPanel->GetSelectedItem( i ); + m_pLODPanel->RemoveItem( selected ); + } +} + +void CQCGenerator::EditLOD() +{ + int numSelected = m_pLODPanel->GetSelectedItemsCount(); + if ( numSelected == 1 && !m_pLODPanel->IsInEditMode() ) + { + if ( m_pLODEdit ) + { + m_pLODEdit->MarkForDeletion(); + m_pLODEdit = NULL; + } + m_pLODEdit = new vgui::TextEntry( this, "Edit" ); + m_pLODEdit->SendNewLine( true ); + m_nSelectedSequence = m_pLODPanel->GetSelectedItem( 0 ); + m_nSelectedColumn = m_pLODPanel->GetSelectedColumn(); + m_pLODPanel->EnterEditMode( m_nSelectedSequence, m_nSelectedColumn, m_pLODEdit ); + } +} + +void CQCGenerator::OnNewLODText() +{ + KeyValues *pEditItem = m_pLODPanel->GetItem( m_nSelectedSequence ); + KeyValues *pListItem = pEditItem; + wchar_t szEditText[MAX_PATH]; + + pEditItem = pEditItem->GetFirstValue(); + const char *name = pEditItem->GetName(); + for( int i = 0; i < m_nSelectedColumn; i++ ) + { + pEditItem = pEditItem->GetNextValue(); + name = pEditItem->GetName(); + } + m_pLODEdit->GetText( szEditText, MAX_PATH ); + + pListItem->SetWString( name, szEditText ); + + m_pLODPanel->LeaveEditMode(); + m_pLODPanel->InvalidateLayout(); + return; +} \ No newline at end of file diff --git a/vgui2/matsys_controls/assetpicker.cpp b/vgui2/matsys_controls/assetpicker.cpp new file mode 100644 index 00000000..4d30b7f5 --- /dev/null +++ b/vgui2/matsys_controls/assetpicker.cpp @@ -0,0 +1,47 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "matsys_controls/assetpicker.h" + + +using namespace vgui; + + +//----------------------------------------------------------------------------- +// +// Asset Picker with no preview +// +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CAssetPicker::CAssetPicker( vgui::Panel *pParent, const char *pAssetType, + const char *pExt, const char *pSubDir, const char *pTextType ) : + BaseClass( pParent, pAssetType, pExt, pSubDir, pTextType ) +{ + CreateStandardControls( this ); + LoadControlSettingsAndUserConfig( "resource/assetpicker.res" ); +} + + +//----------------------------------------------------------------------------- +// +// Purpose: Modal picker frame +// +//----------------------------------------------------------------------------- +CAssetPickerFrame::CAssetPickerFrame( vgui::Panel *pParent, const char *pTitle, + const char *pAssetType, const char *pExt, const char *pSubDir, const char *pTextType ) : + BaseClass( pParent ) +{ + SetAssetPicker( new CAssetPicker( this, pAssetType, pExt, pSubDir, pTextType ) ); + LoadControlSettingsAndUserConfig( "resource/assetpickerframe.res" ); + SetTitle( pTitle, false ); +} + + + diff --git a/vgui2/matsys_controls/baseassetpicker.cpp b/vgui2/matsys_controls/baseassetpicker.cpp new file mode 100644 index 00000000..30144f2b --- /dev/null +++ b/vgui2/matsys_controls/baseassetpicker.cpp @@ -0,0 +1,1625 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "filesystem.h" +#include "matsys_controls/baseassetpicker.h" +#include "tier1/KeyValues.h" +#include "tier1/utlntree.h" +#include "tier1/utlrbtree.h" +#include "vgui_controls/ListPanel.h" +#include "vgui_controls/TextEntry.h" +#include "vgui_controls/ComboBox.h" +#include "vgui_controls/Button.h" +#include "vgui_controls/Splitter.h" +#include "vgui_controls/TreeView.h" +#include "vgui_controls/ImageList.h" +#include "vgui_controls/CheckButton.h" +#include "vgui/ISurface.h" +#include "vgui/IInput.h" +#include "vgui/IVGui.h" +#include "vgui/Cursor.h" + + +using namespace vgui; + + +#define ASSET_LIST_DIRECTORY_INITIAL_SEARCH_TIME 0.25f +#define ASSET_LIST_DIRECTORY_SEARCH_TIME 0.025f + + +//----------------------------------------------------------------------------- +// sorting function, should return true if node1 should be displayed before node2 +//----------------------------------------------------------------------------- +bool AssetTreeViewSortFunc( KeyValues *node1, KeyValues *node2 ) +{ + const char *pDir1 = node1->GetString( "text", NULL ); + const char *pDir2 = node2->GetString( "text", NULL ); + return Q_stricmp( pDir1, pDir2 ) < 0; +} + + +//----------------------------------------------------------------------------- +// +// Tree view for assets +// +//----------------------------------------------------------------------------- +class CAssetTreeView : public vgui::TreeView +{ + DECLARE_CLASS_SIMPLE( CAssetTreeView, vgui::TreeView ); + +public: + CAssetTreeView( vgui::Panel *parent, const char *name, const char *pRootFolderName, const char *pRootDir ); + + // Inherited from base classes + virtual void GenerateChildrenOfNode( int itemIndex ); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + + // Opens and selects the root folder + void OpenRoot(); + + // Purpose: Refreshes the active file list + void RefreshFileList(); + + // Adds a subdirectory + DirHandle_t GetRootDirectory( ); + DirHandle_t AddSubDirectory( DirHandle_t hParent, const char *pDirName ); + void ClearDirectories(); + + // Selects a folder + void SelectFolder( const char *pSubDir, const char *pPath ); + +private: + // Allocates the root node + void AllocateRootNode( ); + + // Purpose: Refreshes the active file list + DirHandle_t RefreshTreeViewItem( int nItemIndex ); + + // Sets an item to be colored as if its a menu + void SetItemColorForDirectories( int nItemID ); + + // Add a directory into the treeview + void AddDirectoryToTreeView( int nParentItemIndex, const char *pFullParentPath, DirHandle_t hPath ); + + // Selects an item in the tree + bool SelectFolder_R( int nItemID, const char *pPath ); + + CUtlString m_RootFolderName; + CUtlString m_RootDirectory; + vgui::ImageList m_Images; + CUtlNTree< CUtlString, DirHandle_t > m_DirectoryStructure; +}; + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CAssetTreeView::CAssetTreeView( Panel *pParent, const char *pName, const char *pRootFolderName, const char *pRootDir ) : BaseClass(pParent, pName), m_Images( false ) +{ + SetSortFunc( AssetTreeViewSortFunc ); + + m_RootFolderName = pRootFolderName; + m_RootDirectory = pRootDir; + AllocateRootNode(); + + // build our list of images + m_Images.AddImage( scheme()->GetImage( "resource/icon_folder", false ) ); + SetImageList( &m_Images, false ); + + SETUP_PANEL( this ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Refreshes the active file list +//----------------------------------------------------------------------------- +void CAssetTreeView::OpenRoot() +{ + RemoveAll(); + + // add the base node + const char *pRootDir = m_DirectoryStructure[ m_DirectoryStructure.Root() ]; + KeyValues *pkv = new KeyValues( "root" ); + pkv->SetString( "text", m_RootFolderName.Get() ); + pkv->SetInt( "root", 1 ); + pkv->SetInt( "expand", 1 ); + pkv->SetInt( "dirHandle", m_DirectoryStructure.Root() ); + pkv->SetString( "path", pRootDir ); + int iRoot = AddItem( pkv, GetRootItemIndex() ); + pkv->deleteThis(); + ExpandItem( iRoot, true ); +} + + +//----------------------------------------------------------------------------- +// Allocates the root node +//----------------------------------------------------------------------------- +void CAssetTreeView::AllocateRootNode( ) +{ + DirHandle_t hRoot = m_DirectoryStructure.Alloc(); + m_DirectoryStructure.SetRoot( hRoot ); + m_DirectoryStructure[hRoot] = m_RootDirectory; +} + + +//----------------------------------------------------------------------------- +// Adds a subdirectory (maintains sorted order) +//----------------------------------------------------------------------------- +DirHandle_t CAssetTreeView::GetRootDirectory( ) +{ + return m_DirectoryStructure.Root(); +} + +DirHandle_t CAssetTreeView::AddSubDirectory( DirHandle_t hParent, const char *pDirName ) +{ + DirHandle_t hSubdir = m_DirectoryStructure.Alloc(); + m_DirectoryStructure[hSubdir] = pDirName; + m_DirectoryStructure[hSubdir].ToLower(); + + DirHandle_t hChild = m_DirectoryStructure.FirstChild( hParent ); + m_DirectoryStructure.LinkChildBefore( hParent, hChild, hSubdir ); + + return hSubdir; +} + +void CAssetTreeView::ClearDirectories() +{ + m_DirectoryStructure.RemoveAll(); + AllocateRootNode(); +} + + +//----------------------------------------------------------------------------- +// Sets an item to be colored as if its a menu +//----------------------------------------------------------------------------- +void CAssetTreeView::SetItemColorForDirectories( int nItemID ) +{ + // mark directories in orange + SetItemFgColor( nItemID, Color(224, 192, 0, 255) ); +} + + +//----------------------------------------------------------------------------- +// Add a directory into the treeview +//----------------------------------------------------------------------------- +void CAssetTreeView::AddDirectoryToTreeView( int nParentItemIndex, const char *pFullParentPath, DirHandle_t hPath ) +{ + const char *pDirName = m_DirectoryStructure[hPath].Get(); + KeyValues *kv = new KeyValues( "node", "text", pDirName ); + + char pFullPath[MAX_PATH]; + Q_snprintf( pFullPath, sizeof( pFullPath ), "%s/%s", pFullParentPath, pDirName ); + Q_FixSlashes( pFullPath ); + Q_strlower( pFullPath ); + bool bHasSubdirectories = m_DirectoryStructure.FirstChild( hPath ) != m_DirectoryStructure.InvalidIndex(); + kv->SetString( "path", pFullPath ); + kv->SetInt( "expand", bHasSubdirectories ); + kv->SetInt( "image", 0 ); + kv->SetInt( "dirHandle", hPath ); + + int nItemID = AddItem( kv, nParentItemIndex ); + kv->deleteThis(); + + // mark directories in orange + SetItemColorForDirectories( nItemID ); +} + + +//----------------------------------------------------------------------------- +// override to incremental request and show p4 directories +//----------------------------------------------------------------------------- +void CAssetTreeView::GenerateChildrenOfNode( int nItemIndex ) +{ + KeyValues *pkv = GetItemData( nItemIndex ); + + const char *pFullParentPath = pkv->GetString( "path", NULL ); + if ( !pFullParentPath ) + return; + + DirHandle_t hPath = (DirHandle_t)pkv->GetInt( "dirHandle", m_DirectoryStructure.InvalidIndex() ); + if ( hPath == m_DirectoryStructure.InvalidIndex() ) + return; + + DirHandle_t hChild = m_DirectoryStructure.FirstChild( hPath ); + while ( hChild != m_DirectoryStructure.InvalidIndex() ) + { + AddDirectoryToTreeView( nItemIndex, pFullParentPath, hChild ); + hChild = m_DirectoryStructure.NextSibling( hChild ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Refreshes the active file list +//----------------------------------------------------------------------------- +DirHandle_t CAssetTreeView::RefreshTreeViewItem( int nItemIndex ) +{ + if ( nItemIndex < 0 ) + return m_DirectoryStructure.InvalidIndex(); + + // Make sure the expand icons are set correctly + KeyValues *pkv = GetItemData( nItemIndex ); + DirHandle_t hPath = (DirHandle_t)pkv->GetInt( "dirHandle", m_DirectoryStructure.InvalidIndex() ); + const char *pFullParentPath = pkv->GetString( "path", NULL ); + bool bHasSubdirectories = m_DirectoryStructure.FirstChild( hPath ) != m_DirectoryStructure.InvalidIndex(); + if ( bHasSubdirectories != ( pkv->GetInt( "expand" ) != 0 ) ) + { + pkv->SetInt( "expand", bHasSubdirectories ); + ModifyItem( nItemIndex, pkv ); + } + bool bIsExpanded = IsItemExpanded( nItemIndex ); + if ( !bIsExpanded ) + return hPath; + + // Check all children + build a list of children we've already got + int nChildCount = GetNumChildren( nItemIndex ); + DirHandle_t *pFoundHandles = (DirHandle_t*)_alloca( nChildCount * sizeof(DirHandle_t) ); + memset( pFoundHandles, 0xFF, nChildCount * sizeof(DirHandle_t) ); + for ( int i = 0; i < nChildCount; ++i ) + { + int nChildItemIndex = GetChild( nItemIndex, i ); + pFoundHandles[i] = RefreshTreeViewItem( nChildItemIndex ); + } + + // Check directory structure to see if other directories were added + DirHandle_t hChild = m_DirectoryStructure.FirstChild( hPath ); + for ( ; hChild != m_DirectoryStructure.InvalidIndex(); hChild = m_DirectoryStructure.NextSibling( hChild ) ) + { + // Search for existence of this child already + bool bFound = false; + for ( int j = 0; j < nChildCount; ++j ) + { + if ( pFoundHandles[j] == hChild ) + { + pFoundHandles[j] = pFoundHandles[nChildCount-1]; + --nChildCount; + bFound = true; + break; + } + } + + if ( bFound ) + continue; + + // Child is new, add it + AddDirectoryToTreeView( nItemIndex, pFullParentPath, hChild ); + } + + return hPath; +} + +void CAssetTreeView::RefreshFileList() +{ + // Make sure the expand icons are set correctly + RefreshTreeViewItem( GetRootItemIndex() ); + InvalidateLayout(); +} + + +//----------------------------------------------------------------------------- +// Selects a folder +//----------------------------------------------------------------------------- +bool CAssetTreeView::SelectFolder_R( int nItemID, const char *pPath ) +{ + if ( nItemID < 0 ) + return false; + + KeyValues *kv = GetItemData( nItemID ); + const char *pTestPath = kv->GetString( "path" ); + if ( !Q_stricmp( pTestPath, pPath ) ) + { + AddSelectedItem( nItemID, true, false, true ); + return true; + } + + // Substring match.. + CUtlString str = pTestPath; + str += '\\'; + if ( Q_strnicmp( str, pPath, str.Length() ) ) + return false; + + ExpandItem( nItemID, true ); + + int nChildCount = GetNumChildren( nItemID ); + for ( int i = 0; i < nChildCount; ++i ) + { + int nChildItemID = GetChild( nItemID, i ); + if ( SelectFolder_R( nChildItemID, pPath ) ) + return true; + } + return false; +} + +void CAssetTreeView::SelectFolder( const char *pSubDir, const char *pPath ) +{ + char pTemp[MAX_PATH]; + Q_snprintf( pTemp, sizeof(pTemp), "%s\\%s", pSubDir, pPath ); + Q_StripTrailingSlash( pTemp ); + + int nItem = GetRootItemIndex(); + SelectFolder_R( nItem, pTemp ); +} + + + +//----------------------------------------------------------------------------- +// setup a smaller font +//----------------------------------------------------------------------------- +void CAssetTreeView::ApplySchemeSettings( IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + SetFont( pScheme->GetFont("DefaultSmall") ); + SetFgColor( Color(216, 222, 211, 255) ); +} + + +//----------------------------------------------------------------------------- +// +// Cache of asset data so we don't need to rebuild all the time +// +//----------------------------------------------------------------------------- +DECLARE_POINTER_HANDLE( AssetList_t ); +#define ASSET_LIST_INVALID ((AssetList_t)(0xFFFF)) + + +class CAssetCache +{ +public: + struct CachedAssetInfo_t + { + CUtlString m_AssetName; + int m_nModIndex; + }; + + struct ModInfo_t + { + CUtlString m_ModName; + CUtlString m_Path; + }; + + CAssetCache(); + + // Mod iteration + int ModCount() const; + const ModInfo_t& ModInfo( int nIndex ) const; + + // Building the mod list + void BuildModList(); + + AssetList_t FindAssetList( const char *pAssetType, const char *pSubDir, int nExtCount, const char **ppExt ); + bool BeginAssetScan( AssetList_t hList, bool bForceRescan = false ); + CAssetTreeView* GetFileTree( AssetList_t hList ); + int GetAssetCount( AssetList_t hList ) const; + const CachedAssetInfo_t& GetAsset( AssetList_t hList, int nIndex ) const; + + void AddAsset( AssetList_t hList, const CachedAssetInfo_t& info ); + + bool ContinueSearchForAssets( AssetList_t hList, float flDuration ); + +private: + struct DirToCheck_t + { + CUtlString m_DirName; + DirHandle_t m_hDirHandle; + }; + + struct CachedAssetList_t + { + CachedAssetList_t() {} + CachedAssetList_t( const char *pSearchSubDir, int nExtCount, const char **ppSearchExt ) : + m_pSubDir( pSearchSubDir, Q_strlen( pSearchSubDir ) + 1 ) + { + m_Ext.AddMultipleToTail( nExtCount, ppSearchExt ); + } + CachedAssetList_t( const CachedAssetList_t& ) + { + // Only used during insertion; do nothing + } + + CUtlVector< CachedAssetInfo_t > m_AssetList; + CAssetTreeView *m_pFileTree; + + CUtlString m_pSubDir; + CUtlVector< const char * > m_Ext; + + CUtlLinkedList< DirToCheck_t > m_DirectoriesToCheck; + FileFindHandle_t m_hFind; + bool m_bAssetScanComplete; + }; + +private: + bool AddFilesInDirectory( CachedAssetList_t& list, const char *pStartingFile, const char *pFilePath, DirHandle_t hDirHandle, float flStartTime, float flDuration ); + bool DoesExtensionMatch( CachedAssetList_t& list, const char *pFileName ); + void AddAssetToList( CachedAssetList_t& list, const char *pAssetName, int nModIndex ); + +private: + // List of known mods + CUtlVector< ModInfo_t > m_ModList; + + // List of cached assets + CUtlRBTree< CachedAssetList_t > m_CachedAssets; + + // Have we built the mod list? + bool m_bBuiltModList; + + static bool CachedAssetLessFunc( const CachedAssetList_t& src1, const CachedAssetList_t& src2 ); +}; + + +//----------------------------------------------------------------------------- +// Static instance of the asset cache +//----------------------------------------------------------------------------- +static CAssetCache s_AssetCache; + + +//----------------------------------------------------------------------------- +// Map sort func +//----------------------------------------------------------------------------- +bool CAssetCache::CachedAssetLessFunc( const CAssetCache::CachedAssetList_t& src1, const CAssetCache::CachedAssetList_t& src2 ) +{ + int nRetVal = Q_stricmp( src1.m_pSubDir, src2.m_pSubDir ) > 0; + if ( nRetVal != 0 ) + return nRetVal > 0; + + int nCount = src1.m_Ext.Count(); + int nDiff = nCount - src2.m_Ext.Count(); + if ( nDiff != 0 ) + return nDiff > 0; + + for ( int i = 0; i < nCount; ++i ) + { + nRetVal = Q_stricmp( src1.m_Ext[i], src2.m_Ext[i] ); + if ( nRetVal != 0 ) + return nRetVal > 0; + } + + return false; +} + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CAssetCache::CAssetCache() : m_CachedAssets( 0, 0, CachedAssetLessFunc ) +{ + m_bBuiltModList = false; +} + + +//----------------------------------------------------------------------------- +// Mod iteration +//----------------------------------------------------------------------------- +int CAssetCache::ModCount() const +{ + return m_ModList.Count(); +} + +const CAssetCache::ModInfo_t& CAssetCache::ModInfo( int nIndex ) const +{ + return m_ModList[nIndex]; +} + + +//----------------------------------------------------------------------------- +// Building the mod list +//----------------------------------------------------------------------------- +void CAssetCache::BuildModList() +{ + if ( m_bBuiltModList ) + return; + + m_bBuiltModList = true; + + m_ModList.RemoveAll(); + + // Add all mods + int nLen = g_pFullFileSystem->GetSearchPath( "GAME", false, NULL, 0 ); + char *pSearchPath = (char*)stackalloc( nLen * sizeof(char) ); + g_pFullFileSystem->GetSearchPath( "GAME", false, pSearchPath, nLen ); + char *pPath = pSearchPath; + while( pPath ) + { + char *pSemiColon = strchr( pPath, ';' ); + if ( pSemiColon ) + { + *pSemiColon = 0; + } + + Q_StripTrailingSlash( pPath ); + Q_FixSlashes( pPath ); + + char pModName[ MAX_PATH ]; + Q_FileBase( pPath, pModName, sizeof( pModName ) ); + + // Always start in an asset-specific directory +// char pAssetPath[MAX_PATH]; +// Q_snprintf( pAssetPath, MAX_PATH, "%s\\%s", pPath, m_pAssetSubDir ); +// Q_FixSlashes( pPath ); + + int i = m_ModList.AddToTail( ); + m_ModList[i].m_ModName.Set( pModName ); + m_ModList[i].m_Path.Set( pPath ); + + pPath = pSemiColon ? pSemiColon + 1 : NULL; + } +} + + +//----------------------------------------------------------------------------- +// Adds an asset to the list of assets of this type +//----------------------------------------------------------------------------- +void CAssetCache::AddAssetToList( CachedAssetList_t& list, const char *pAssetName, int nModIndex ) +{ + int i = list.m_AssetList.AddToTail( ); + CachedAssetInfo_t& info = list.m_AssetList[i]; + info.m_AssetName.Set( pAssetName ); + info.m_nModIndex = nModIndex; +} + + +//----------------------------------------------------------------------------- +// Extension matches? +//----------------------------------------------------------------------------- +bool CAssetCache::DoesExtensionMatch( CachedAssetList_t& info, const char *pFileName ) +{ + char pChildExt[MAX_PATH]; + Q_ExtractFileExtension( pFileName, pChildExt, sizeof(pChildExt) ); + + // Check the extension matches + int nCount = info.m_Ext.Count(); + for ( int i = 0; i < nCount; ++i ) + { + if ( !Q_stricmp( info.m_Ext[i], pChildExt ) ) + return true; + } + + return false; +} + + +//----------------------------------------------------------------------------- +// Recursively add all files matching the wildcard under this directory +//----------------------------------------------------------------------------- +bool CAssetCache::AddFilesInDirectory( CachedAssetList_t& list, const char *pStartingFile, const char *pFilePath, DirHandle_t hCurrentDir, float flStartTime, float flDuration ) +{ + // Indicates no files found + if ( list.m_hFind == FILESYSTEM_INVALID_FIND_HANDLE ) + return true; + + // generate children + // add all the items + int nModCount = m_ModList.Count(); + int nSubDirLen = list.m_pSubDir ? Q_strlen(list.m_pSubDir) : 0; + const char *pszFileName = pStartingFile; + while ( pszFileName ) + { + char pRelativeChildPath[MAX_PATH]; + Q_snprintf( pRelativeChildPath, MAX_PATH, "%s\\%s", pFilePath, pszFileName ); + + if ( g_pFullFileSystem->FindIsDirectory( list.m_hFind ) ) + { + // If .svn is in the name, don't add this directory!! + if ( strstr (pszFileName, ".svn") ) + { + pszFileName = g_pFullFileSystem->FindNext( list.m_hFind ); + continue; + } + + if ( Q_strnicmp( pszFileName, ".", 2 ) && Q_strnicmp( pszFileName, "..", 3 ) ) + { + DirHandle_t hDirHandle = list.m_pFileTree->AddSubDirectory( hCurrentDir, pszFileName ); + int i = list.m_DirectoriesToCheck.AddToTail(); + list.m_DirectoriesToCheck[i].m_DirName = pRelativeChildPath; + list.m_DirectoriesToCheck[i].m_hDirHandle = hDirHandle; + } + } + else + { + // Check the extension matches + if ( DoesExtensionMatch( list, pszFileName ) ) + { + char pFullAssetPath[MAX_PATH]; + g_pFullFileSystem->RelativePathToFullPath( pRelativeChildPath, "GAME", pFullAssetPath, sizeof(pFullAssetPath) ); + + int nModIndex = -1; + for ( int i = 0; i < nModCount; ++i ) + { + if ( !Q_strnicmp( pFullAssetPath, m_ModList[i].m_Path, m_ModList[i].m_Path.Length() ) ) + { + nModIndex = i; + break; + } + } + + if ( nModIndex >= 0 ) + { + // Strip 'subdir/' prefix + char *pAssetName = pRelativeChildPath; + if ( list.m_pSubDir ) + { + if ( !Q_strnicmp( list.m_pSubDir, pAssetName, nSubDirLen ) ) + { + if ( pAssetName[nSubDirLen] == '\\' ) + { + pAssetName += nSubDirLen + 1; + } + } + } + strlwr( pAssetName ); + + AddAssetToList( list, pAssetName, nModIndex ); + } + } + } + + // Don't let the search go for too long at a time + if ( Plat_FloatTime() - flStartTime >= flDuration ) + return false; + + pszFileName = g_pFullFileSystem->FindNext( list.m_hFind ); + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Recursively add all files matching the wildcard under this directory +//----------------------------------------------------------------------------- +bool CAssetCache::ContinueSearchForAssets( AssetList_t hList, float flDuration ) +{ + CachedAssetList_t& list = m_CachedAssets[ (intp)hList ]; + + float flStartTime = Plat_FloatTime(); + while ( list.m_DirectoriesToCheck.Count() ) + { + const char *pFilePath = list.m_DirectoriesToCheck[ list.m_DirectoriesToCheck.Head() ].m_DirName; + DirHandle_t hCurrentDir = list.m_DirectoriesToCheck[ list.m_DirectoriesToCheck.Head() ].m_hDirHandle; + + const char *pStartingFile; + if ( list.m_hFind == FILESYSTEM_INVALID_FIND_HANDLE ) + { + char pSearchString[MAX_PATH]; + Q_snprintf( pSearchString, MAX_PATH, "%s\\*", pFilePath ); + + // get the list of files + pStartingFile = g_pFullFileSystem->FindFirstEx( pSearchString, "GAME", &list.m_hFind ); + } + else + { + pStartingFile = g_pFullFileSystem->FindNext( list.m_hFind ); + } + + if ( !AddFilesInDirectory( list, pStartingFile, pFilePath, hCurrentDir, flStartTime, flDuration ) ) + return false; + + g_pFullFileSystem->FindClose( list.m_hFind ); + list.m_hFind = FILESYSTEM_INVALID_FIND_HANDLE; + list.m_DirectoriesToCheck.Remove( list.m_DirectoriesToCheck.Head() ); + } + list.m_bAssetScanComplete = true; + return true; +} + + +//----------------------------------------------------------------------------- +// Asset cache iteration +//----------------------------------------------------------------------------- +bool CAssetCache::BeginAssetScan( AssetList_t hList, bool bForceRescan ) +{ + CachedAssetList_t& list = m_CachedAssets[ (intp)hList ]; + if ( bForceRescan ) + { + list.m_bAssetScanComplete = false; + if ( list.m_hFind != FILESYSTEM_INVALID_FIND_HANDLE ) + { + g_pFullFileSystem->FindClose( list.m_hFind ); + list.m_hFind = FILESYSTEM_INVALID_FIND_HANDLE; + } + list.m_DirectoriesToCheck.RemoveAll(); + } + + if ( list.m_bAssetScanComplete ) + return false; + + // This case occurs if we stopped the picker previously while in the middle of a scan + if ( list.m_hFind != FILESYSTEM_INVALID_FIND_HANDLE ) + return true; + + list.m_AssetList.RemoveAll(); + list.m_pFileTree->ClearDirectories(); + + // Add all files, determine which mod they are in. + int i = list.m_DirectoriesToCheck.AddToTail(); + list.m_DirectoriesToCheck[i].m_DirName = list.m_pSubDir; + list.m_DirectoriesToCheck[i].m_hDirHandle = list.m_pFileTree->GetRootDirectory(); + return true; +} + + +//----------------------------------------------------------------------------- +// Asset cache iteration +//----------------------------------------------------------------------------- +AssetList_t CAssetCache::FindAssetList( const char *pAssetType, const char *pSubDir, int nExtCount, const char **ppExt ) +{ + CachedAssetList_t search( pSubDir, nExtCount, ppExt ); + int nIndex = m_CachedAssets.Find( search ); + if ( nIndex == m_CachedAssets.InvalidIndex() ) + { + nIndex = m_CachedAssets.Insert( search ); + CachedAssetList_t &list = m_CachedAssets[nIndex]; + list.m_pSubDir = pSubDir; + list.m_Ext.AddMultipleToTail( nExtCount, ppExt ); + list.m_hFind = FILESYSTEM_INVALID_FIND_HANDLE; + list.m_bAssetScanComplete = false; + list.m_pFileTree = new CAssetTreeView( NULL, "FolderFilter", pAssetType, pSubDir ); + } + + return (AssetList_t)(intp)nIndex; +} + +CAssetTreeView* CAssetCache::GetFileTree( AssetList_t hList ) +{ + if ( hList == ASSET_LIST_INVALID ) + return NULL; + return m_CachedAssets[ (intp)hList ].m_pFileTree; +} + +int CAssetCache::GetAssetCount( AssetList_t hList ) const +{ + if ( hList == ASSET_LIST_INVALID ) + return 0; + return m_CachedAssets[ (intp)hList ].m_AssetList.Count(); +} + +const CAssetCache::CachedAssetInfo_t& CAssetCache::GetAsset( AssetList_t hList, int nIndex ) const +{ + Assert( nIndex < GetAssetCount(hList) ); + return m_CachedAssets[ (intp)hList ].m_AssetList[ nIndex ]; +} + + + +//----------------------------------------------------------------------------- +// +// Base asset Picker +// +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// Sort by asset name +//----------------------------------------------------------------------------- +static int __cdecl AssetBrowserSortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 ) +{ + bool bRoot1 = item1.kv->GetInt("root") != 0; + bool bRoot2 = item2.kv->GetInt("root") != 0; + if ( bRoot1 != bRoot2 ) + return bRoot1 ? -1 : 1; + const char *pString1 = item1.kv->GetString("asset"); + const char *pString2 = item2.kv->GetString("asset"); + return Q_stricmp( pString1, pString2 ); +} + +static int __cdecl AssetBrowserModSortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 ) +{ + int nMod1 = item1.kv->GetInt("modIndex", -1); + int nMod2 = item2.kv->GetInt("modIndex", -1); + if ( nMod1 != nMod2 ) + return nMod1 - nMod2; + return AssetBrowserSortFunc( pPanel, item1, item2 ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CBaseAssetPicker::CBaseAssetPicker( vgui::Panel *pParent, const char *pAssetType, + const char *pExt, const char *pSubDir, const char *pTextType ) : + BaseClass( pParent, "AssetPicker" ) +{ + m_bBuiltAssetList = false; + m_pAssetType = pAssetType; + m_pAssetTextType = pTextType; + m_pAssetExt = pExt; + m_pAssetSubDir = pSubDir; + m_bFinishedAssetListScan = false; + m_bFirstAssetScan = false; + m_nMatchingAssets = 0; + m_bSubDirCheck = true; + m_hAssetList = ASSET_LIST_INVALID; +} + + +//----------------------------------------------------------------------------- +// Purpose: Destructor +//----------------------------------------------------------------------------- +CBaseAssetPicker::~CBaseAssetPicker() +{ + SaveUserConfig(); + + // Detach! + m_pFileTree->RemoveActionSignalTarget( this ); + m_pFileTree->SetParent( (Panel*)NULL ); + m_pFileTree = NULL; +} + + +//----------------------------------------------------------------------------- +// Creates standard controls +//----------------------------------------------------------------------------- +void CBaseAssetPicker::CreateStandardControls( vgui::Panel *pParent, bool bAllowMultiselect ) +{ + int nExtCount = 1 + m_ExtraAssetExt.Count(); + const char **ppExt = (const char **)_alloca( nExtCount * sizeof(const char *) ); + ppExt[0] = m_pAssetExt; + if ( nExtCount > 1 ) + { + memcpy( ppExt + 1, m_ExtraAssetExt.Base(), nExtCount - 1 ); + } + + m_hAssetList = s_AssetCache.FindAssetList( m_pAssetType, m_pAssetSubDir, nExtCount, ppExt ); + + m_pAssetSplitter = new vgui::Splitter( pParent, "AssetSplitter", SPLITTER_MODE_HORIZONTAL, 1 ); + vgui::Panel *pSplitterTopSide = m_pAssetSplitter->GetChild( 0 ); + vgui::Panel *pSplitterBottomSide = m_pAssetSplitter->GetChild( 1 ); + + // Combo box for mods + m_pModSelector = new ComboBox( pSplitterTopSide, "ModFilter", 5, false ); + m_pModSelector->AddActionSignalTarget( this ); + + // Rescan button + m_pRescanButton = new Button( pSplitterTopSide, "RescanButton", "Rescan", this, "AssetRescan" ); + + // file browser tree controls + m_pFileTree = s_AssetCache.GetFileTree( m_hAssetList ); + m_pFileTree->SetParent( pSplitterTopSide ); + m_pFileTree->AddActionSignalTarget( this ); + + m_pSubDirCheck = new CheckButton( pSplitterTopSide, "SubDirCheck", "Check subfolders for files?" ); + m_pSubDirCheck->SetSelected( true ); + m_pSubDirCheck->SetEnabled( false ); + m_pSubDirCheck->SetVisible( false ); + m_pSubDirCheck->AddActionSignalTarget( this ); + + char pTemp[512]; + Q_snprintf( pTemp, sizeof(pTemp), "No .%s files", m_pAssetExt ); + m_pAssetBrowser = new vgui::ListPanel( pSplitterBottomSide, "AssetBrowser" ); + m_pAssetBrowser->AddColumnHeader( 0, "mod", "Mod", 52, 0 ); + m_pAssetBrowser->AddColumnHeader( 1, "asset", m_pAssetType, 128, ListPanel::COLUMN_RESIZEWITHWINDOW ); + m_pAssetBrowser->SetSelectIndividualCells( false ); + m_pAssetBrowser->SetMultiselectEnabled( bAllowMultiselect ); + m_pAssetBrowser->SetEmptyListText( pTemp ); + m_pAssetBrowser->SetDragEnabled( true ); + m_pAssetBrowser->AddActionSignalTarget( this ); + m_pAssetBrowser->SetSortFunc( 0, AssetBrowserModSortFunc ); + m_pAssetBrowser->SetSortFunc( 1, AssetBrowserSortFunc ); + m_pAssetBrowser->SetSortColumn( 1 ); + + // filter selection + m_pFilter = new TextEntry( pSplitterBottomSide, "FilterList" ); + m_pFilter->AddActionSignalTarget( this ); + + // full path + m_pFullPath = new TextEntry( pSplitterBottomSide, "FullPath" ); + m_pFullPath->SetEnabled( false ); + m_pFullPath->SetEditable( false ); + + m_nCurrentModFilter = -1; +} + + +//----------------------------------------------------------------------------- +// Reads user config settings +//----------------------------------------------------------------------------- +void CBaseAssetPicker::ApplyUserConfigSettings( KeyValues *pUserConfig ) +{ + BaseClass::ApplyUserConfigSettings( pUserConfig ); + + // Populates the mod list names + RefreshAssetList(); + + const char *pFilter = pUserConfig->GetString( "filter", "" ); + m_FolderFilter = pUserConfig->GetString( "folderfilter", "" ); + const char *pMod = pUserConfig->GetString( "mod", "" ); + SetFilter( pFilter ); + m_nCurrentModFilter = -1; + if ( pMod && pMod[0] ) + { + int nCount = s_AssetCache.ModCount(); + for ( int i = 0; i < nCount; ++i ) + { + const CAssetCache::ModInfo_t& modInfo = s_AssetCache.ModInfo( i ); + if ( Q_stricmp( pMod, modInfo.m_ModName ) ) + continue; + + int nItemCount = m_pModSelector->GetItemCount(); + for ( int j = 0; j < nItemCount; ++j ) + { + int nItemID = m_pModSelector->GetItemIDFromRow( j ); + KeyValues *kv = m_pModSelector->GetItemUserData( nItemID ); + int nModIndex = kv->GetInt( "mod" ); + if ( nModIndex == i ) + { + m_nCurrentModFilter = i; + m_pModSelector->ActivateItem( nItemID ); + break; + } + } + break; + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: returns user config settings for this control +//----------------------------------------------------------------------------- +void CBaseAssetPicker::GetUserConfigSettings( KeyValues *pUserConfig ) +{ + BaseClass::GetUserConfigSettings( pUserConfig ); + pUserConfig->SetString( "filter", m_Filter ); + pUserConfig->SetString( "folderfilter", m_FolderFilter ); + pUserConfig->SetString( "mod", ( m_nCurrentModFilter >= 0 ) ? + s_AssetCache.ModInfo( m_nCurrentModFilter ).m_ModName : "" ); +} + + +//----------------------------------------------------------------------------- +// Purpose: optimization, return true if this control has any user config settings +//----------------------------------------------------------------------------- +bool CBaseAssetPicker::HasUserConfigSettings() +{ + return true; +} + + +//----------------------------------------------------------------------------- +// Allows the picker to browse multiple asset types +//----------------------------------------------------------------------------- +void CBaseAssetPicker::AddExtension( const char *pExtension ) +{ + m_ExtraAssetExt.AddToTail( pExtension ); +} + + +//----------------------------------------------------------------------------- +// Is multiselect enabled? +//----------------------------------------------------------------------------- +bool CBaseAssetPicker::IsMultiselectEnabled() const +{ + return m_pAssetBrowser->IsMultiselectEnabled(); +} + + +//----------------------------------------------------------------------------- +// Sets the initial selected asset +//----------------------------------------------------------------------------- +void CBaseAssetPicker::SetInitialSelection( const char *pAssetName ) +{ + // This makes it so the background list filling code will automatically select this asset when it gets to it. + m_SelectedAsset = pAssetName; + + if ( pAssetName ) + { + // Sometimes we've already refreshed our list with a bunch of cached resources and the item is already in the list, + // so in that case just select it here. + int cnt = m_pAssetBrowser->GetItemCount(); + for ( int i=0; i < cnt; i++ ) + { + KeyValues *kv = m_pAssetBrowser->GetItem( i ); + if ( !kv ) + continue; + + const char *pTestAssetName = kv->GetString( "asset" ); + if ( !pTestAssetName ) + continue; + + if ( Q_stricmp( pTestAssetName, pAssetName ) == 0 ) + { + m_pAssetBrowser->SetSelectedCell( i, 0 ); + break; + } + } + } +} + + +//----------------------------------------------------------------------------- +// Set/get the filter +//----------------------------------------------------------------------------- +void CBaseAssetPicker::SetFilter( const char *pFilter ) +{ + m_Filter = pFilter; + m_pFilter->SetText( pFilter ); +} + +const char *CBaseAssetPicker::GetFilter() +{ + return m_Filter; +} + + +//----------------------------------------------------------------------------- +// Purpose: called to open +//----------------------------------------------------------------------------- +void CBaseAssetPicker::Activate() +{ + RefreshAssetList(); + RequestFilterFocus(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBaseAssetPicker::OnKeyCodePressed( KeyCode code ) +{ + if (( code == KEY_UP ) || ( code == KEY_DOWN ) || ( code == KEY_PAGEUP ) || ( code == KEY_PAGEDOWN )) + { + KeyValues *pMsg = new KeyValues("KeyCodePressed", "code", code); + vgui::ipanel()->SendMessage( m_pAssetBrowser->GetVPanel(), pMsg, GetVPanel()); + pMsg->deleteThis(); + } + else + { + BaseClass::OnKeyCodePressed( code ); + } +} + + +//----------------------------------------------------------------------------- +// Is a particular asset visible? +//----------------------------------------------------------------------------- +bool CBaseAssetPicker::IsAssetVisible( int nAssetIndex ) +{ + const CAssetCache::CachedAssetInfo_t& info = s_AssetCache.GetAsset( m_hAssetList, nAssetIndex ); + + // Filter based on active mod + int nModIndex = info.m_nModIndex; + if ( ( m_nCurrentModFilter >= 0 ) && ( m_nCurrentModFilter != nModIndex ) ) + return false; + + // Filter based on name + const char *pAssetName = info.m_AssetName; + if ( !Q_strcmp( pAssetName, m_SelectedAsset ) ) + return true; + + if ( m_Filter.Length() && !Q_stristr( pAssetName, m_Filter.Get() ) ) + return false; + + // Filter based on folder + if ( m_FolderFilter.Length() && Q_strnicmp( pAssetName, m_FolderFilter.Get(), m_FolderFilter.Length() ) ) + return false; + + // Filter based on subdirectory check + if ( !m_bSubDirCheck && strchr( pAssetName + m_FolderFilter.Length(), '\\' ) ) + return false; + + return true; +} + + +//----------------------------------------------------------------------------- +// Adds an asset from the cache to the list +//----------------------------------------------------------------------------- +void CBaseAssetPicker::AddAssetToList( int nAssetIndex ) +{ + const CAssetCache::CachedAssetInfo_t& info = s_AssetCache.GetAsset( m_hAssetList, nAssetIndex ); + + bool bInRootDir = !strchr( info.m_AssetName, '\\' ) && !strchr( info.m_AssetName, '/' ); + + KeyValues *kv = new KeyValues( "node", "asset", info.m_AssetName ); + kv->SetString( "mod", s_AssetCache.ModInfo( info.m_nModIndex ).m_ModName ); + kv->SetInt( "modIndex", info.m_nModIndex ); + kv->SetInt( "root", bInRootDir ); + int nItemID = m_pAssetBrowser->AddItem( kv, 0, false, false ); + kv->deleteThis(); + + if ( m_pAssetBrowser->GetSelectedItemsCount() == 0 && !Q_strcmp( m_SelectedAsset, info.m_AssetName ) ) + { + m_pAssetBrowser->SetSelectedCell( nItemID, 0 ); + } + + KeyValues *pDrag = new KeyValues( "drag", "text", info.m_AssetName ); + if ( m_pAssetTextType ) + { + pDrag->SetString( "texttype", m_pAssetTextType ); + } + m_pAssetBrowser->SetItemDragData( nItemID, pDrag ); + + int i = m_AssetList.AddToTail( ); + m_AssetList[i].m_nAssetIndex = nAssetIndex; + m_AssetList[i].m_nItemId = nItemID; + + bool bIsVisible = IsAssetVisible( i ); + m_pAssetBrowser->SetItemVisible( nItemID, bIsVisible ); + if ( bIsVisible ) + { + ++m_nMatchingAssets; + } +} + + +//----------------------------------------------------------------------------- +// Continues to build the asset list +//----------------------------------------------------------------------------- +void CBaseAssetPicker::OnTick() +{ + BaseClass::OnTick(); + + int nPreAssetCount = s_AssetCache.GetAssetCount( m_hAssetList ); + + // Stop getting called back once all assets have been found + float flTime = m_bFirstAssetScan ? ASSET_LIST_DIRECTORY_INITIAL_SEARCH_TIME : ASSET_LIST_DIRECTORY_SEARCH_TIME; + bool bFinished = s_AssetCache.ContinueSearchForAssets( m_hAssetList, flTime ); + + if ( m_bFirstAssetScan ) + { + m_pFileTree->OpenRoot(); + } + m_bFirstAssetScan = false; + + int nPostAssetCount = s_AssetCache.GetAssetCount( m_hAssetList ); + for ( int i = nPreAssetCount; i < nPostAssetCount; ++i ) + { + AddAssetToList( i ); + } + + if ( bFinished ) + { + vgui::ivgui()->RemoveTickSignal( GetVPanel() ); + m_bFinishedAssetListScan = true; + + // Copy the current folder filter.. this is necessary + // to finally select the folder loaded from the user config settings + // in the free view (since it's finally populated at this point) + // NOTE: if a user has changed the folder filter between startup + // and this point, this should still work since m_FolderFilter should be updated + m_pFileTree->SelectFolder( m_pAssetSubDir, m_FolderFilter ); + RefreshAssetList( ); + return; + } + + UpdateAssetColumnHeader(); +} + + +//----------------------------------------------------------------------------- +// Builds the Bsp name list +//----------------------------------------------------------------------------- +void CBaseAssetPicker::BuildAssetNameList( ) +{ + if ( m_bBuiltAssetList ) + return; + + m_bBuiltAssetList = true; + m_nMatchingAssets = 0; + m_nCurrentModFilter = -1; + + // Build the list of known mods if we haven't + s_AssetCache.BuildModList(); + + m_pModSelector->RemoveAll(); + m_pModSelector->AddItem( "All Mods", new KeyValues( "Mod", "mod", -1 ) ); + int nModCount = s_AssetCache.ModCount(); + for ( int i = 0; i < nModCount; ++i ) + { + const char *pModName = s_AssetCache.ModInfo( i ).m_ModName; + m_pModSelector->AddItem( pModName, new KeyValues( "Mod", "mod", i ) ); + } + m_pModSelector->ActivateItemByRow( 0 ); + + // If we've already read in + if ( s_AssetCache.BeginAssetScan( m_hAssetList ) ) + { + m_bFirstAssetScan = true; + m_bFinishedAssetListScan = false; + vgui::ivgui()->AddTickSignal( GetVPanel(), 10 ); + } + else + { + m_bFirstAssetScan = false; + m_bFinishedAssetListScan = true; + } + + int nAssetCount = s_AssetCache.GetAssetCount( m_hAssetList ); + for ( int i = 0; i < nAssetCount; ++i ) + { + AddAssetToList( i ); + } +} + + +//----------------------------------------------------------------------------- +// Rescan assets +//----------------------------------------------------------------------------- +void CBaseAssetPicker::RescanAssets() +{ + m_pAssetBrowser->RemoveAll(); + m_AssetList.RemoveAll(); + s_AssetCache.BeginAssetScan( m_hAssetList, true ); + m_bFirstAssetScan = true; + m_nMatchingAssets = 0; + + if ( m_bFinishedAssetListScan ) + { + m_bFinishedAssetListScan = false; + vgui::ivgui()->AddTickSignal( GetVPanel(), 10 ); + } +} + + +//----------------------------------------------------------------------------- +// Returns the mod path to the item index +//----------------------------------------------------------------------------- +const char *CBaseAssetPicker::GetModPath( int nModIndex ) +{ + return s_AssetCache.ModInfo( nModIndex ).m_Path.Get(); +} + + +//----------------------------------------------------------------------------- +// Command handler +//----------------------------------------------------------------------------- +void CBaseAssetPicker::OnCommand( const char *pCommand ) +{ + if ( !Q_stricmp( pCommand, "AssetRescan" ) ) + { + RescanAssets(); + return; + } + + BaseClass::OnCommand( pCommand ); +} + + +//----------------------------------------------------------------------------- +// Update column headers +//----------------------------------------------------------------------------- +void CBaseAssetPicker::UpdateAssetColumnHeader( ) +{ + char pColumnTitle[512]; + Q_snprintf( pColumnTitle, sizeof(pColumnTitle), "%s (%d/%d)%s", + m_pAssetType, m_nMatchingAssets, m_AssetList.Count(), m_bFinishedAssetListScan ? "" : " ..." ); + m_pAssetBrowser->SetColumnHeaderText( 1, pColumnTitle ); +} + + +//----------------------------------------------------------------------------- +// Request focus of the filter box +//----------------------------------------------------------------------------- +void CBaseAssetPicker::RequestFilterFocus() +{ + if ( m_Filter.Length() ) + { + m_pFilter->SelectAllOnFirstFocus( true ); + } + m_pFilter->RequestFocus(); +} + + +//----------------------------------------------------------------------------- +// Purpose: refreshes the asset list +//----------------------------------------------------------------------------- +void CBaseAssetPicker::RefreshAssetList( ) +{ + BuildAssetNameList(); + + // Check the filter matches + int nCount = m_AssetList.Count(); + m_nMatchingAssets = 0; + for ( int i = 0; i < nCount; ++i ) + { + // Filter based on active mod + bool bIsVisible = IsAssetVisible( i ); + m_pAssetBrowser->SetItemVisible( m_AssetList[i].m_nItemId, bIsVisible ); + if ( bIsVisible ) + { + ++m_nMatchingAssets; + } + } + + UpdateAssetColumnHeader(); + m_pAssetBrowser->SortList(); + + if ( ( m_pAssetBrowser->GetSelectedItemsCount() == 0 ) && ( m_pAssetBrowser->GetItemCount() > 0 ) ) + { + // Invoke a callback if the next selection will be a 'default' selection + OnNextSelectionIsDefault(); + int nItemID = m_pAssetBrowser->GetItemIDFromRow( 0 ); + m_pAssetBrowser->SetSelectedCell( nItemID, 0 ); + } + + m_pFileTree->RefreshFileList(); +} + + +//----------------------------------------------------------------------------- +// Purpose: refreshes dialog on file folder changing +//----------------------------------------------------------------------------- +void CBaseAssetPicker::OnFileSelected() +{ + // update list + const char *pFolderFilter = ""; + int iItem = m_pFileTree->GetFirstSelectedItem(); + if ( iItem >= 0 ) + { + KeyValues *pkv = m_pFileTree->GetItemData( iItem ); + pFolderFilter = pkv->GetString( "path" ); + + // The first keys are always the subdir + pFolderFilter += Q_strlen( m_pAssetSubDir ); + if ( *pFolderFilter ) + { + ++pFolderFilter; + } + } + + if ( Q_stricmp( pFolderFilter, m_FolderFilter.Get() ) ) + { + int nLen = Q_strlen( pFolderFilter ); + m_FolderFilter = pFolderFilter; + if ( nLen > 0 ) + { + m_FolderFilter += '\\'; + } + RefreshAssetList(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: refreshes dialog on text changing +//----------------------------------------------------------------------------- +void CBaseAssetPicker::OnTextChanged( KeyValues *pKeyValues ) +{ + vgui::Panel *pSource = (vgui::Panel*)pKeyValues->GetPtr( "panel" ); + if ( pSource == m_pFilter ) + { + int nLength = m_pFilter->GetTextLength(); + char *pNewFilter = (char*)_alloca( (nLength+1) * sizeof(char) ); + if ( nLength > 0 ) + { + m_pFilter->GetText( pNewFilter, nLength+1 ); + } + else + { + pNewFilter[0] = 0; + } + if ( Q_stricmp( pNewFilter, m_Filter.Get() ) ) + { + m_Filter.SetLength( nLength ); + m_Filter = pNewFilter; + RefreshAssetList(); + } + return; + } + + if ( pSource == m_pModSelector ) + { + KeyValues *pKeyValuesActive = m_pModSelector->GetActiveItemUserData(); + if ( pKeyValuesActive ) + { + m_nCurrentModFilter = pKeyValuesActive->GetInt( "mod", -1 ); + RefreshAssetList(); + } + return; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Updates preview when an item is selected +//----------------------------------------------------------------------------- +void CBaseAssetPicker::OnItemSelected( KeyValues *kv ) +{ + Panel *pPanel = (Panel *)kv->GetPtr( "panel", NULL ); + if ( pPanel == m_pAssetBrowser ) + { + int nCount = GetSelectedAssetCount(); + Assert( nCount > 0 ); + const char *pSelectedAsset = GetSelectedAsset( nCount - 1 ); + + // Fill in the full path + int nModIndex = GetSelectedAssetModIndex(); + char pBuf[MAX_PATH]; + Q_snprintf( pBuf, sizeof(pBuf), "%s\\%s\\%s", + s_AssetCache.ModInfo( nModIndex ).m_Path.Get(), m_pAssetSubDir, pSelectedAsset ); + Q_FixSlashes( pBuf ); + m_pFullPath->SetText( pBuf ); + + surface()->SetCursor( dc_waitarrow ); + OnSelectedAssetPicked( pSelectedAsset ); + return; + } +} + +void CBaseAssetPicker::OnCheckButtonChecked( KeyValues *kv ) +{ + vgui::Panel *pSource = (vgui::Panel*)kv->GetPtr( "panel" ); + if ( pSource == m_pSubDirCheck ) + { + m_bSubDirCheck = m_pSubDirCheck->IsSelected(); + RefreshAssetList(); + } +} + + +//----------------------------------------------------------------------------- +// Returns the selceted asset count +//----------------------------------------------------------------------------- +int CBaseAssetPicker::GetSelectedAssetCount() +{ + return m_pAssetBrowser->GetSelectedItemsCount(); +} + + +//----------------------------------------------------------------------------- +// Returns the selceted asset name +//----------------------------------------------------------------------------- +const char *CBaseAssetPicker::GetSelectedAsset( int nAssetIndex ) +{ + int nSelectedAssetCount = m_pAssetBrowser->GetSelectedItemsCount(); + if ( nAssetIndex < 0 ) + { + nAssetIndex = nSelectedAssetCount - 1; + } + if ( nSelectedAssetCount <= nAssetIndex || nAssetIndex < 0 ) + return NULL; + + int nIndex = m_pAssetBrowser->GetSelectedItem( nAssetIndex ); + KeyValues *pItemKeyValues = m_pAssetBrowser->GetItem( nIndex ); + return pItemKeyValues->GetString( "asset" ); +} + + +//----------------------------------------------------------------------------- +// Returns the selceted asset mod index +//----------------------------------------------------------------------------- +int CBaseAssetPicker::GetSelectedAssetModIndex( ) +{ + if ( m_pAssetBrowser->GetSelectedItemsCount() == 0 ) + return 0; + + int nIndex = m_pAssetBrowser->GetSelectedItem( 0 ); + KeyValues *pItemKeyValues = m_pAssetBrowser->GetItem( nIndex ); + return pItemKeyValues->GetInt( "modIndex" ); +} + + +//----------------------------------------------------------------------------- +// +// Purpose: Modal picker frame +// +//----------------------------------------------------------------------------- +CBaseAssetPickerFrame::CBaseAssetPickerFrame( vgui::Panel *pParent ) : + BaseClass( pParent, "AssetPickerFrame" ) +{ + m_pContextKeyValues = NULL; + SetDeleteSelfOnClose( true ); + m_pOpenButton = new Button( this, "OpenButton", "#FileOpenDialog_Open", this, "Open" ); + m_pCancelButton = new Button( this, "CancelButton", "#FileOpenDialog_Cancel", this, "Cancel" ); + SetBlockDragChaining( true ); +} + +CBaseAssetPickerFrame::~CBaseAssetPickerFrame() +{ + CleanUpMessage(); +} + + +//----------------------------------------------------------------------------- +// Allows the derived class to create the picker +//----------------------------------------------------------------------------- +void CBaseAssetPickerFrame::SetAssetPicker( CBaseAssetPicker* pPicker ) +{ + m_pPicker = pPicker; + m_pPicker->AddActionSignalTarget( this ); +} + + +//----------------------------------------------------------------------------- +// Deletes the message +//----------------------------------------------------------------------------- +void CBaseAssetPickerFrame::CleanUpMessage() +{ + if ( m_pContextKeyValues ) + { + m_pContextKeyValues->deleteThis(); + m_pContextKeyValues = NULL; + } +} + + +//----------------------------------------------------------------------------- +// Sets the initial selected asset +//----------------------------------------------------------------------------- +void CBaseAssetPickerFrame::SetInitialSelection( const char *pAssetName ) +{ + m_pPicker->SetInitialSelection( pAssetName ); +} + + +//----------------------------------------------------------------------------- +// Set/get the filter +//----------------------------------------------------------------------------- +void CBaseAssetPickerFrame::SetFilter( const char *pFilter ) +{ + m_pPicker->SetFilter( pFilter ); +} + +const char *CBaseAssetPickerFrame::GetFilter() +{ + return m_pPicker->GetFilter( ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Activate the dialog +//----------------------------------------------------------------------------- +void CBaseAssetPickerFrame::DoModal( KeyValues *pKeyValues ) +{ + BaseClass::DoModal(); + CleanUpMessage(); + m_pContextKeyValues = pKeyValues; + m_pPicker->Activate(); +} + + +//----------------------------------------------------------------------------- +// Posts a message (passing the key values) +//----------------------------------------------------------------------------- +void CBaseAssetPickerFrame::PostMessageAndClose( KeyValues *pKeyValues ) +{ + if ( m_pContextKeyValues ) + { + pKeyValues->AddSubKey( m_pContextKeyValues ); + m_pContextKeyValues = NULL; + } + CloseModal(); + PostActionSignal( pKeyValues ); +} + + +//----------------------------------------------------------------------------- +// On command +//----------------------------------------------------------------------------- +void CBaseAssetPickerFrame::OnCommand( const char *pCommand ) +{ + if ( !Q_stricmp( pCommand, "Open" ) ) + { + KeyValues *pActionKeys = new KeyValues( "AssetSelected" ); + if ( !m_pPicker->IsMultiselectEnabled() ) + { + const char *pAssetName = m_pPicker->GetSelectedAsset( ); + pActionKeys->SetString( "asset", pAssetName ); + } + else + { + char pBuf[512]; + KeyValues *pAssetKeys = pActionKeys->FindKey( "assets", true ); + int nCount = m_pPicker->GetSelectedAssetCount(); + for ( int i = 0; i < nCount; ++i ) + { + Q_snprintf( pBuf, sizeof(pBuf), "asset%d", i ); + pAssetKeys->SetString( pBuf, m_pPicker->GetSelectedAsset( i ) ); + } + } + PostMessageAndClose( pActionKeys ); + return; + } + + if ( !Q_stricmp( pCommand, "Cancel" ) ) + { + CloseModal(); + return; + } + + BaseClass::OnCommand( pCommand ); +} + + diff --git a/vgui2/matsys_controls/colorpickerpanel.cpp b/vgui2/matsys_controls/colorpickerpanel.cpp new file mode 100644 index 00000000..848f78a5 --- /dev/null +++ b/vgui2/matsys_controls/colorpickerpanel.cpp @@ -0,0 +1,1255 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#include "matsys_controls/colorpickerpanel.h" +#include "matsys_controls/matsyscontrols.h" +#include "matsys_controls/proceduraltexturepanel.h" +#include "materialsystem/imaterialsystem.h" +#include "materialsystem/itexture.h" +#include "pixelwriter.h" +#include "VGuiMatSurface/IMatSystemSurface.h" +#include "vgui_controls/Button.h" +#include "vgui_controls/TextEntry.h" +#include "vgui_controls/RadioButton.h" +#include "vgui/IInput.h" +#include "tier1/KeyValues.h" +#include "bitmap/imageformat.h" + +using namespace vgui; + + +//----------------------------------------------------------------------------- +// Color picker +//----------------------------------------------------------------------------- +enum ColorType_t +{ + COLOR_TYPE_RGB = 0, + COLOR_TYPE_HSV, +}; + +enum ColorChannel_t +{ + CHANNEL_RED = 0, + CHANNEL_GREEN, + CHANNEL_BLUE, + + CHANNEL_HUE = 0, + CHANNEL_SATURATION, + CHANNEL_VALUE, +}; + + +//----------------------------------------------------------------------------- +// Converts RGB to normalized +//----------------------------------------------------------------------------- +static void RGB888ToVector( RGB888_t inColor, Vector *pOutVector ) +{ + pOutVector->Init( inColor.r / 255.0f, inColor.g / 255.0f, inColor.b / 255.0f ); +} + +static void VectorToRGB888( const Vector &inVector, RGB888_t &outColor ) +{ + int r = (int)((inVector.x * 255.0f) + 0.5f); + int g = (int)((inVector.y * 255.0f) + 0.5f); + int b = (int)((inVector.z * 255.0f) + 0.5f); + outColor.r = clamp( r, 0, 255 ); + outColor.g = clamp( g, 0, 255 ); + outColor.b = clamp( b, 0, 255 ); +} + + +//----------------------------------------------------------------------------- +// Convert RGB to HSV +//----------------------------------------------------------------------------- +static inline void RGBtoHSV( const RGB888_t &rgb, Vector &hsv ) +{ + Vector vecRGB; + RGB888ToVector( rgb, &vecRGB ); + RGBtoHSV( vecRGB, hsv ); +} + + +//----------------------------------------------------------------------------- +// Convert HSV to RGB +//----------------------------------------------------------------------------- +static inline void HSVtoRGB( const Vector &hsv, RGB888_t &rgb ) +{ + Vector vecRGB; + HSVtoRGB( hsv, vecRGB ); + VectorToRGB888( vecRGB, rgb ); +} + + +//----------------------------------------------------------------------------- +// This previews the 'xy' color +//----------------------------------------------------------------------------- +class CColorXYPreview : public CProceduralTexturePanel +{ + DECLARE_CLASS_SIMPLE( CColorXYPreview, CProceduralTexturePanel ); + +public: + // constructor + CColorXYPreview( vgui::Panel *pParent, const char *pName ); + + virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect ); + virtual void Paint( void ); + virtual void OnMousePressed( vgui::MouseCode code ); + virtual void OnMouseReleased( vgui::MouseCode code ); + virtual void OnCursorMoved( int x, int y ); + + void SetMode( ColorType_t type, ColorChannel_t channel ); + void SetColor( const RGB888_t &color, const Vector &hsvColor ); + +private: + // Computes a color given a particular x,y value + void ComputeColorForPoint( int x, int y, RGB888_t &color ); + void ComputeHSVColorForPoint( int x, int y, Vector &vscHSV ); + + // Updates the color based on the mouse position + void UpdateColorFromMouse( int x, int y ); + + static ColorChannel_t s_pHSVRemapX[3]; + static ColorChannel_t s_pHSVRemapY[3]; + static ColorChannel_t s_pRGBRemapX[3]; + static ColorChannel_t s_pRGBRemapY[3]; + + ColorType_t m_Type; + ColorChannel_t m_Channel; + RGB888_t m_CurrentColor; + Vector m_CurrentHSVColor; + vgui::HCursor m_hPickerCursor; + bool m_bDraggingMouse; +}; + + +ColorChannel_t CColorXYPreview::s_pHSVRemapX[3] = +{ + CHANNEL_SATURATION, CHANNEL_HUE, CHANNEL_HUE +}; + +ColorChannel_t CColorXYPreview::s_pHSVRemapY[3] = +{ + CHANNEL_VALUE, CHANNEL_VALUE, CHANNEL_SATURATION +}; + +ColorChannel_t CColorXYPreview::s_pRGBRemapX[3] = +{ + CHANNEL_BLUE, CHANNEL_BLUE, CHANNEL_RED +}; + +ColorChannel_t CColorXYPreview::s_pRGBRemapY[3] = +{ + CHANNEL_GREEN, CHANNEL_RED, CHANNEL_GREEN +}; + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CColorXYPreview::CColorXYPreview( vgui::Panel *pParent, const char *pName ) : BaseClass( pParent, pName ) +{ + Init( 256, 256, false ); + m_CurrentColor.r = m_CurrentColor.g = m_CurrentColor.b = 255; + SetMode( COLOR_TYPE_HSV, CHANNEL_HUE ); + SetMouseInputEnabled( true ); + m_hPickerCursor = surface()->CreateCursorFromFile( "resource/colorpicker.cur" ); + SetCursor( m_hPickerCursor ); + m_bDraggingMouse = false; +} + + +//----------------------------------------------------------------------------- +// Sets the mode for the preview +//----------------------------------------------------------------------------- +void CColorXYPreview::SetMode( ColorType_t type, ColorChannel_t channel ) +{ + if ( m_Type != type || m_Channel != channel ) + { + m_Type = type; + m_Channel = channel; + DownloadTexture(); + } +} + +void CColorXYPreview::SetColor( const RGB888_t &color, const Vector &hsvColor ) +{ + if ( color != m_CurrentColor || m_CurrentHSVColor != hsvColor ) + { + m_CurrentColor = color; + m_CurrentHSVColor = hsvColor; + DownloadTexture(); + } +} + + +//----------------------------------------------------------------------------- +// Computes a color given a particular x,y value +//----------------------------------------------------------------------------- +void CColorXYPreview::ComputeColorForPoint( int x, int y, RGB888_t &color ) +{ + color = m_CurrentColor; + ((unsigned char*)&color)[ s_pRGBRemapX[m_Channel] ] = x; + ((unsigned char*)&color)[ s_pRGBRemapY[m_Channel] ] = GetImageHeight() - y - 1; +} + +void CColorXYPreview::ComputeHSVColorForPoint( int x, int y, Vector &vscHSV ) +{ + vscHSV = m_CurrentHSVColor; + vscHSV[ s_pHSVRemapX[m_Channel] ] = (float)x / 255.0f; + vscHSV[ s_pHSVRemapY[m_Channel] ] = (float)(GetImageHeight() - y - 1) / 255.0f; + if ( vscHSV.y == 0.0f ) + { + vscHSV.x = -1.0f; + } + + if ( m_Channel != CHANNEL_HUE ) + { + if ( vscHSV.x != -1.0f ) + { + vscHSV.x *= 360.0f; + } + } +} + + +//----------------------------------------------------------------------------- +// Fills the texture w/ the image buffer +//----------------------------------------------------------------------------- +void CColorXYPreview::RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect ) +{ + Assert( pVTFTexture->FrameCount() == 1 ); + Assert( pVTFTexture->FaceCount() == 1 ); + Assert( !pTexture->IsMipmapped() ); + + int nWidth, nHeight, nDepth; + pVTFTexture->ComputeMipLevelDimensions( 0, &nWidth, &nHeight, &nDepth ); + Assert( nDepth == 1 ); + Assert( nWidth == m_nWidth && nHeight == m_nHeight ); + + CPixelWriter pixelWriter; + pixelWriter.SetPixelMemory( pVTFTexture->Format(), + pVTFTexture->ImageData( 0, 0, 0 ), pVTFTexture->RowSizeInBytes( 0 ) ); + + for ( int y = 0; y < nHeight; ++y ) + { + pixelWriter.Seek( 0, y ); + + for ( int x = 0; x < nWidth; ++x ) + { + RGB888_t color; + if ( m_Type != COLOR_TYPE_RGB ) + { + Vector vecHSV; + ComputeHSVColorForPoint( x, y, vecHSV ); + HSVtoRGB( vecHSV, color ); + } + else + { + ComputeColorForPoint( x, y, color ); + } + + pixelWriter.WritePixel( color.r, color.g, color.b, 255 ); + } + } +} + + +//----------------------------------------------------------------------------- +// Paints a circle over the currently selected color +//----------------------------------------------------------------------------- +void CColorXYPreview::Paint( void ) +{ + BaseClass::Paint(); + + int x, y; + if ( m_Type != COLOR_TYPE_RGB ) + { + Vector vecHSVNormalized = m_CurrentHSVColor; + if ( vecHSVNormalized.x != -1.0f ) + { + vecHSVNormalized.x *= 255.0f / 360.0f; + } + vecHSVNormalized.y *= 255.0f; + vecHSVNormalized.z *= 255.0f; + + x = (int)( vecHSVNormalized[ s_pHSVRemapX[m_Channel] ] + 0.5f); + y = GetImageHeight() - 1 - (int)( vecHSVNormalized[ s_pHSVRemapY[m_Channel] ] + 0.5f ); + } + else + { + x = ((unsigned char*)&m_CurrentColor)[ s_pRGBRemapX[m_Channel] ]; + y = GetImageHeight() - 1 - ((unsigned char*)&m_CurrentColor)[ s_pRGBRemapY[m_Channel] ]; + } + + // Renormalize x, y to actual size + int w, h; + GetSize( w, h ); + x = (int)( w * (float)x / 255.0f + 0.5f ); + y = (int)( h * (float)y / 255.0f + 0.5f ); + vgui::surface()->DrawSetColor( 255, 255, 255, 255 ); + vgui::surface()->DrawOutlinedCircle( x, y, 5, 8 ); + vgui::surface()->DrawSetColor( 0, 0, 0, 255 ); + vgui::surface()->DrawOutlinedCircle( x, y, 6, 8 ); +} + + +//----------------------------------------------------------------------------- +// Updates the color based on the mouse position +//----------------------------------------------------------------------------- +void CColorXYPreview::UpdateColorFromMouse( int x, int y ) +{ + int w, h; + GetSize( w, h ); + + float flNormalizedX = (float)x / (w-1); + float flNormalizedY = (float)y / (h-1); + flNormalizedX = clamp( flNormalizedX, 0.0f, 1.0f ); + flNormalizedY = clamp( flNormalizedY, 0.0f, 1.0f ); + + int tx = (int)( (GetImageWidth()-1) * flNormalizedX + 0.5f ); + int ty = (int)( (GetImageHeight()-1) * flNormalizedY + 0.5f ); + if ( m_Type != COLOR_TYPE_RGB ) + { + Vector vecHSV; + ComputeHSVColorForPoint( tx, ty, vecHSV ); + + KeyValues *pKeyValues = new KeyValues( "HSVSelected" ); + pKeyValues->SetFloat( "hue", vecHSV.x ); + pKeyValues->SetFloat( "saturation", vecHSV.y ); + pKeyValues->SetFloat( "value", vecHSV.z ); + PostActionSignal( pKeyValues ); + + // This prevents a 1-frame lag in the current color position + RGB888_t color; + HSVtoRGB( vecHSV, color ); + SetColor( color, vecHSV ); + } + else + { + RGB888_t color; + ComputeColorForPoint( tx, ty, color ); + + Color c( color.r, color.g, color.b, 255 ); + KeyValues *pKeyValues = new KeyValues( "ColorSelected" ); + pKeyValues->SetColor( "color", c ); + PostActionSignal( pKeyValues ); + + // This prevents a 1-frame lag in the current color position + Vector vecHSV; + RGBtoHSV( color, vecHSV ); + SetColor( color, vecHSV ); + } +} + + +//----------------------------------------------------------------------------- +// Handle input +//----------------------------------------------------------------------------- +void CColorXYPreview::OnMousePressed( vgui::MouseCode code ) +{ + BaseClass::OnMousePressed( code ); + + if ( code == MOUSE_LEFT ) + { + if ( !m_bDraggingMouse ) + { + m_bDraggingMouse = true; + input()->SetMouseCapture(GetVPanel()); + + int x, y; + input()->GetCursorPos( x, y ); + ScreenToLocal( x, y ); + + UpdateColorFromMouse( x, y ); + } + } +} + +void CColorXYPreview::OnMouseReleased( vgui::MouseCode code ) +{ + BaseClass::OnMouseReleased( code ); + + if ( code == MOUSE_LEFT ) + { + if ( m_bDraggingMouse ) + { + m_bDraggingMouse = false; + input()->SetMouseCapture( (VPANEL)0 ); + } + } +} + +void CColorXYPreview::OnCursorMoved( int x, int y ) +{ + BaseClass::OnCursorMoved( x, y ); + + if ( m_bDraggingMouse ) + { + UpdateColorFromMouse( x, y ); + } +} + + +//----------------------------------------------------------------------------- +// This previews the 'z' color +//----------------------------------------------------------------------------- +class CColorZPreview : public CProceduralTexturePanel +{ + DECLARE_CLASS_SIMPLE( CColorZPreview, CProceduralTexturePanel ); + +public: + // constructor + CColorZPreview( vgui::Panel *pParent, const char *pName ); + + virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect ); + virtual void PerformLayout(); + virtual void Paint( void ); + virtual void OnCursorMoved( int x,int y ); + virtual void OnMousePressed( vgui::MouseCode code ); + virtual void OnMouseReleased( vgui::MouseCode code ); + + void SetMode( ColorType_t type, ColorChannel_t channel ); + void SetColor( const RGB888_t &color, const Vector &hsvColor ); + + // Computes a color given a particular x,y value + void ComputeColorForPoint( int y, RGB888_t &color ); + void ComputeHSVColorForPoint( int y, bool bProceduralTexture, Vector &vecHSV ); + +private: + // Updates the color based on the mouse position + void UpdateColorFromMouse( int x, int y ); + + ColorType_t m_Type; + ColorChannel_t m_Channel; + RGB888_t m_CurrentColor; + Vector m_CurrentHSVColor; + bool m_bDraggingMouse; +}; + +#define MARKER_WIDTH 6 + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CColorZPreview::CColorZPreview( vgui::Panel *pParent, const char *pName ) : BaseClass( pParent, pName ) +{ + Init( 8, 256, false ); + m_CurrentColor.r = m_CurrentColor.g = m_CurrentColor.b = 255; + + Vector vecRGB; + RGB888ToVector( m_CurrentColor, &vecRGB ); + RGBtoHSV( vecRGB, m_CurrentHSVColor ); + m_bDraggingMouse = false; + + SetMouseInputEnabled( true ); + SetMode( COLOR_TYPE_HSV, CHANNEL_HUE ); +} + + +//----------------------------------------------------------------------------- +// Sets the mode for the preview +//----------------------------------------------------------------------------- +void CColorZPreview::SetMode( ColorType_t type, ColorChannel_t channel ) +{ + if ( m_Type != type || m_Channel != channel ) + { + m_Type = type; + m_Channel = channel; + DownloadTexture(); + } +} + +void CColorZPreview::SetColor( const RGB888_t &color, const Vector &hsvColor ) +{ + if ( color != m_CurrentColor || m_CurrentHSVColor != hsvColor ) + { + m_CurrentColor = color; + m_CurrentHSVColor = hsvColor; + DownloadTexture(); + } +} + + +//----------------------------------------------------------------------------- +// Lays out the panel +//----------------------------------------------------------------------------- +void CColorZPreview::PerformLayout() +{ + BaseClass::PerformLayout(); + + int w, h; + GetSize( w, h ); + Rect_t r; + r.x = MARKER_WIDTH; + r.y = MARKER_WIDTH; + r.width = w - (MARKER_WIDTH*2); + r.height = h - (MARKER_WIDTH*2); + + SetPaintRect( &r ); +} + + +//----------------------------------------------------------------------------- +// Computes a color given a particular x,y value +//----------------------------------------------------------------------------- +void CColorZPreview::ComputeColorForPoint( int y, RGB888_t &color ) +{ + color = m_CurrentColor; + ((unsigned char*)&color)[ m_Channel ] = GetImageHeight() - y - 1; +} + +void CColorZPreview::ComputeHSVColorForPoint( int y, bool bProceduralTexture, Vector &vecHSV ) +{ + vecHSV = m_CurrentHSVColor; + vecHSV[ m_Channel ] = (float)(GetImageHeight() - y - 1) / 255.0f; + if ( m_Channel == CHANNEL_HUE ) + { + if ( vecHSV.x != -1.0f ) + { + vecHSV.x *= 360.0f; + } + + if ( bProceduralTexture ) + { + vecHSV.y = 1.0f; + vecHSV.z = 1.0f; + } + } +} + + +//----------------------------------------------------------------------------- +// Fills the texture w/ the image buffer +//----------------------------------------------------------------------------- +void CColorZPreview::RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect ) +{ + Assert( pVTFTexture->FrameCount() == 1 ); + Assert( pVTFTexture->FaceCount() == 1 ); + Assert( !pTexture->IsMipmapped() ); + + int nWidth, nHeight, nDepth; + pVTFTexture->ComputeMipLevelDimensions( 0, &nWidth, &nHeight, &nDepth ); + Assert( nDepth == 1 ); + Assert( nWidth == m_nWidth && nHeight == m_nHeight ); + + CPixelWriter pixelWriter; + pixelWriter.SetPixelMemory( pVTFTexture->Format(), + pVTFTexture->ImageData( 0, 0, 0 ), pVTFTexture->RowSizeInBytes( 0 ) ); + + for ( int y = 0; y < nHeight; ++y ) + { + pixelWriter.Seek( 0, y ); + + RGB888_t color; + if ( m_Type != COLOR_TYPE_RGB ) + { + Vector vecHSV; + ComputeHSVColorForPoint( y, true, vecHSV ); + HSVtoRGB( vecHSV, color ); + } + else + { + ComputeColorForPoint( y, color ); + } + + for ( int x = 0; x < nWidth; ++x ) + { + pixelWriter.WritePixel( color.r, color.g, color.b, 255 ); + } + } +} + + +//----------------------------------------------------------------------------- +// Updates the color based on the mouse position +//----------------------------------------------------------------------------- +void CColorZPreview::UpdateColorFromMouse( int x, int y ) +{ + int w, h; + GetSize( w, h ); + h -= 2 * MARKER_WIDTH; + + float flNormalizedY = (float)( y - MARKER_WIDTH ) / (h-1); + flNormalizedY = clamp( flNormalizedY, 0.0f, 1.0f ); + + int ty = (int)( (GetImageHeight() - 1) * flNormalizedY + 0.5f ); + if ( m_Type != COLOR_TYPE_RGB ) + { + Vector vecHSV; + ComputeHSVColorForPoint( ty, false, vecHSV ); + + KeyValues *pKeyValues = new KeyValues( "HSVSelected" ); + pKeyValues->SetFloat( "hue", vecHSV.x ); + pKeyValues->SetFloat( "saturation", vecHSV.y ); + pKeyValues->SetFloat( "value", vecHSV.z ); + PostActionSignal( pKeyValues ); + + // This prevents a 1-frame lag in the current color position + RGB888_t color; + HSVtoRGB( vecHSV, color ); + SetColor( color, vecHSV ); + } + else + { + RGB888_t color; + ComputeColorForPoint( ty, color ); + + Color c( color.r, color.g, color.b, 255 ); + KeyValues *pKeyValues = new KeyValues( "ColorSelected" ); + pKeyValues->SetColor( "color", c ); + PostActionSignal( pKeyValues ); + + // This prevents a 1-frame lag in the current color position + Vector vecHSV; + RGBtoHSV( color, vecHSV ); + SetColor( color, vecHSV ); + } +} + + +//----------------------------------------------------------------------------- +// Handle input +//----------------------------------------------------------------------------- +void CColorZPreview::OnMousePressed( vgui::MouseCode code ) +{ + BaseClass::OnMousePressed( code ); + + if ( code == MOUSE_LEFT ) + { + if ( !m_bDraggingMouse ) + { + m_bDraggingMouse = true; + input()->SetMouseCapture(GetVPanel()); + + int x, y; + input()->GetCursorPos( x, y ); + ScreenToLocal( x, y ); + + UpdateColorFromMouse( x, y ); + } + } +} + +void CColorZPreview::OnMouseReleased( vgui::MouseCode code ) +{ + BaseClass::OnMouseReleased( code ); + + if ( code == MOUSE_LEFT ) + { + if ( m_bDraggingMouse ) + { + m_bDraggingMouse = false; + input()->SetMouseCapture( (VPANEL)0 ); + } + } +} + +void CColorZPreview::OnCursorMoved( int x, int y ) +{ + BaseClass::OnCursorMoved( x, y ); + + if ( m_bDraggingMouse ) + { + UpdateColorFromMouse( x, y ); + } +} + + +//----------------------------------------------------------------------------- +// Paints the panel (the two arrows, specifically) +//----------------------------------------------------------------------------- +void CColorZPreview::Paint( void ) +{ + BaseClass::Paint(); + + int y; + if ( m_Type != COLOR_TYPE_RGB ) + { + Vector vecHSVNormalized = m_CurrentHSVColor; + if ( vecHSVNormalized.x != -1.0f ) + { + vecHSVNormalized.x *= 255.0f / 360.0f; + } + vecHSVNormalized.y *= 255.0f; + vecHSVNormalized.z *= 255.0f; + + y = GetImageHeight() - 1 - (int)( vecHSVNormalized[ m_Channel ] + 0.5f ); + } + else + { + y = GetImageHeight() - 1 - ((unsigned char*)&m_CurrentColor)[ m_Channel ]; + } + + // Renormalize y to actual size + int w, h; + GetSize( w, h ); + h -= 2 * MARKER_WIDTH; + y = (int)( h * (float)y / 255.0f + 0.5f ); + + vgui::surface()->DrawSetColor( 255, 255, 255, 255 ); + + int px[3] = { 0, 0, MARKER_WIDTH }; + int py[3] = { MARKER_WIDTH + y - MARKER_WIDTH, MARKER_WIDTH + y + MARKER_WIDTH, MARKER_WIDTH + y }; + vgui::surface()->DrawPolyLine( px, py, 3 ); + + px[0] = px[1] = w-1; + px[2] = w - 1 - MARKER_WIDTH; + vgui::surface()->DrawPolyLine( px, py, 3 ); +} + + +//----------------------------------------------------------------------------- +// +// Color picker panel +// +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// constructor +//----------------------------------------------------------------------------- +CColorPickerPanel::CColorPickerPanel( vgui::Panel *pParent, const char *pName ) : + BaseClass( pParent, pName ) +{ + m_pColorXYPreview = new CColorXYPreview( this, "ColorXYPreview" ); + m_pColorZPreview = new CColorZPreview( this, "ColorZPreview" ); + m_pColorXYPreview->AddActionSignalTarget( this ); + + m_pHueRadio = new RadioButton( this, "HueRadio", "H" ); + m_pSaturationRadio = new RadioButton( this, "SaturationRadio", "S" ); + m_pValueRadio = new RadioButton( this, "ValueRadio", "V" ); + m_pRedRadio = new RadioButton( this, "RedRadio", "R" ); + m_pGreenRadio = new RadioButton( this, "GreenRadio", "G" ); + m_pBlueRadio = new RadioButton( this, "BlueRadio", "B" ); + + m_pHueText = new TextEntry( this, "HueText" ); + m_pSaturationText = new TextEntry( this, "SaturationText"); + m_pValueText = new TextEntry( this, "ValueText" ); + m_pRedText = new TextEntry( this, "RedText" ); + m_pGreenText = new TextEntry( this, "GreenText" ); + m_pBlueText = new TextEntry( this, "BlueText" ); + m_pAlphaText= new TextEntry( this, "AlphaText" ); + + m_pInitialColor = new Panel( this, "InitialColor" ); + m_pCurrentColor = new Panel( this, "CurrentColor" ); + m_pInitialColor->SetVisible( true ); + m_pCurrentColor->SetVisible( true ); + m_pInitialColor->SetPaintBackgroundEnabled( true ); + m_pCurrentColor->SetPaintBackgroundEnabled( true ); + + m_pInitialColor->SetMouseInputEnabled( false ); + SetMouseInputEnabled( true ); + + Color c( 255, 255, 255, 255 ); + SetInitialColor( c ); + + LoadControlSettings( "resource/colorpicker.res" ); +} + + +//----------------------------------------------------------------------------- +// Sets the initial color +//----------------------------------------------------------------------------- +void CColorPickerPanel::SetInitialColor( Color initialColor ) +{ + m_InitialColor.r = initialColor.r(); + m_InitialColor.g = initialColor.g(); + m_InitialColor.b = initialColor.b(); + + m_CurrentAlpha = initialColor.a(); + m_InitialAlpha = m_CurrentAlpha; + m_CurrentColor = m_InitialColor; + + RGBtoHSV( m_CurrentColor, m_CurrentHSVColor ); + if ( m_CurrentHSVColor.x == -1 ) + { + m_CurrentHSVColor.x = 0; + } + OnColorChanged(); +} + + +//----------------------------------------------------------------------------- +// Handle input +//----------------------------------------------------------------------------- +void CColorPickerPanel::OnMousePressed( vgui::MouseCode code ) +{ + BaseClass::OnMousePressed( code ); + + if ( code == MOUSE_LEFT ) + { + // Clicking inside the initial color window + // resets the current color to the initial color + int x, y; + input()->GetCursorPos( x, y ); + ScreenToLocal( x, y ); + + int cx, cy, cw, ch; + m_pInitialColor->GetBounds( cx, cy, cw, ch ); + if ( ( cx <= x ) && ( cx+cw > x ) && ( cy <= y ) && ( cy+ch > y ) ) + { + m_CurrentColor = m_InitialColor; + m_CurrentAlpha = m_InitialAlpha; + RGBtoHSV( m_CurrentColor, m_CurrentHSVColor ); + if ( m_CurrentHSVColor.x == -1 ) + { + m_CurrentHSVColor.x = 0; + } + OnColorChanged(); + } + } +} + + +//----------------------------------------------------------------------------- +// Gets the current/initial color +//----------------------------------------------------------------------------- +void CColorPickerPanel::GetCurrentColor( Color *pColor ) +{ + pColor->SetColor( m_CurrentColor.r, m_CurrentColor.g, m_CurrentColor.b, m_CurrentAlpha ); +} + +void CColorPickerPanel::GetInitialColor( Color *pColor ) +{ + pColor->SetColor( m_InitialColor.r, m_InitialColor.g, m_InitialColor.b, m_InitialAlpha ); +} + + +//----------------------------------------------------------------------------- +// Updates the preview colors +//----------------------------------------------------------------------------- +void CColorPickerPanel::UpdatePreviewColors() +{ + Color c; + c.SetColor( m_InitialColor.r, m_InitialColor.g, m_InitialColor.b, 255 ); + m_pInitialColor->SetBgColor( c ); + c.SetColor( m_CurrentColor.r, m_CurrentColor.g, m_CurrentColor.b, 255 ); + m_pCurrentColor->SetBgColor( c ); +} + + +//----------------------------------------------------------------------------- +// Used to make sure we win over the scheme settings +//----------------------------------------------------------------------------- +void CColorPickerPanel::ApplySchemeSettings(IScheme *pScheme) +{ + // Need to override the scheme settings for this button + BaseClass::ApplySchemeSettings( pScheme ); + UpdatePreviewColors(); +} + + +//----------------------------------------------------------------------------- +// Callbacks from the color preview dialogs +//----------------------------------------------------------------------------- +void CColorPickerPanel::OnHSVSelected( KeyValues *data ) +{ + m_CurrentHSVColor.x = data->GetFloat( "hue" ); + m_CurrentHSVColor.y = data->GetFloat( "saturation" ); + m_CurrentHSVColor.z = data->GetFloat( "value" ); + HSVtoRGB( m_CurrentHSVColor, m_CurrentColor ); + OnColorChanged(); +} + +void CColorPickerPanel::OnColorSelected( KeyValues *data ) +{ + Color c = data->GetColor( "color" ); + m_CurrentColor.r = c.r(); + m_CurrentColor.g = c.g(); + m_CurrentColor.b = c.b(); + RGBtoHSV( m_CurrentColor, m_CurrentHSVColor ); + OnColorChanged(); +} + + +//----------------------------------------------------------------------------- +// Radio buttons +//----------------------------------------------------------------------------- +void CColorPickerPanel::OnRadioButtonChecked( KeyValues *pKeyValues ) +{ + // NOTE: The radio button command strings are defined in the colorpicker.res file + // in game/platform/resource. + vgui::Panel *pPanel = (vgui::Panel *)pKeyValues->GetPtr( "panel" ); + if ( pPanel == m_pRedRadio ) + { + m_pColorXYPreview->SetMode( COLOR_TYPE_RGB, CHANNEL_RED ); + m_pColorZPreview->SetMode( COLOR_TYPE_RGB, CHANNEL_RED ); + } + else if ( pPanel == m_pGreenRadio ) + { + m_pColorXYPreview->SetMode( COLOR_TYPE_RGB, CHANNEL_GREEN ); + m_pColorZPreview->SetMode( COLOR_TYPE_RGB, CHANNEL_GREEN ); + } + else if ( pPanel == m_pBlueRadio ) + { + m_pColorXYPreview->SetMode( COLOR_TYPE_RGB, CHANNEL_BLUE ); + m_pColorZPreview->SetMode( COLOR_TYPE_RGB, CHANNEL_BLUE ); + } + else if ( pPanel == m_pHueRadio ) + { + m_pColorXYPreview->SetMode( COLOR_TYPE_HSV, CHANNEL_HUE ); + m_pColorZPreview->SetMode( COLOR_TYPE_HSV, CHANNEL_HUE ); + } + else if ( pPanel == m_pSaturationRadio ) + { + m_pColorXYPreview->SetMode( COLOR_TYPE_HSV, CHANNEL_SATURATION ); + m_pColorZPreview->SetMode( COLOR_TYPE_HSV, CHANNEL_SATURATION ); + } + else if ( pPanel == m_pValueRadio ) + { + m_pColorXYPreview->SetMode( COLOR_TYPE_HSV, CHANNEL_VALUE ); + m_pColorZPreview->SetMode( COLOR_TYPE_HSV, CHANNEL_VALUE ); + } +} + + +//----------------------------------------------------------------------------- +// Called when the color changes +//----------------------------------------------------------------------------- +void CColorPickerPanel::OnColorChanged( vgui::TextEntry *pChanged ) +{ + char temp[256]; + + if ( pChanged != m_pRedText ) + { + Q_snprintf( temp, sizeof(temp), "%d", m_CurrentColor.r ); + m_pRedText->SetText( temp ); + } + if ( pChanged != m_pGreenText ) + { + Q_snprintf( temp, sizeof(temp), "%d", m_CurrentColor.g ); + m_pGreenText->SetText( temp ); + } + if ( pChanged != m_pBlueText ) + { + Q_snprintf( temp, sizeof(temp), "%d", m_CurrentColor.b ); + m_pBlueText->SetText( temp ); + } + if ( pChanged != m_pAlphaText ) + { + Q_snprintf( temp, sizeof( temp ), "%d", m_CurrentAlpha ); + m_pAlphaText->SetText( temp ); + } + + if ( pChanged != m_pHueText ) + { + Q_snprintf( temp, sizeof(temp), "%d", (int)(m_CurrentHSVColor.x + 0.5f) ); + m_pHueText->SetText( temp ); + } + if ( pChanged != m_pSaturationText ) + { + Q_snprintf( temp, sizeof(temp), "%d", (int)(m_CurrentHSVColor.y * 100 + 0.5f) ); + m_pSaturationText->SetText( temp ); + } + if ( pChanged != m_pValueText ) + { + Q_snprintf( temp, sizeof(temp), "%d", (int)(m_CurrentHSVColor.z * 100 + 0.5f) ); + m_pValueText->SetText( temp ); + } + + m_pColorXYPreview->SetColor( m_CurrentColor, m_CurrentHSVColor ); + m_pColorZPreview->SetColor( m_CurrentColor, m_CurrentHSVColor ); + UpdatePreviewColors(); + PostActionSignal( new KeyValues( "command", "command", "preview" ) ); +} + + +//----------------------------------------------------------------------------- +// Called when the color text entry panels change +//----------------------------------------------------------------------------- +void CColorPickerPanel::OnTextChanged( KeyValues *data ) +{ + Panel *pPanel = (Panel *)data->GetPtr( "panel", NULL ); + + float flHue = m_CurrentHSVColor.x; + + char buf[256]; + if ( pPanel == m_pRedText ) + { + m_pRedText->GetText( buf, sizeof(buf) ); + int val = atoi( buf ); + m_CurrentColor.r = clamp( val, 0, 255 ); + RGBtoHSV( m_CurrentColor, m_CurrentHSVColor ); + } + else if ( pPanel == m_pGreenText ) + { + m_pGreenText->GetText( buf, sizeof(buf) ); + int val = atoi( buf ); + m_CurrentColor.g = clamp( val, 0, 255 ); + RGBtoHSV( m_CurrentColor, m_CurrentHSVColor ); + } + else if ( pPanel == m_pBlueText ) + { + m_pBlueText->GetText( buf, sizeof(buf) ); + int val = atoi( buf ); + m_CurrentColor.b = clamp( val, 0, 255 ); + RGBtoHSV( m_CurrentColor, m_CurrentHSVColor ); + } + else if ( pPanel == m_pAlphaText ) + { + m_pAlphaText->GetText( buf, sizeof( buf ) ); + int val = atoi( buf ); + m_CurrentAlpha = clamp( val, 0, 255 ); + } + else if ( pPanel == m_pHueText ) + { + m_pHueText->GetText( buf, sizeof(buf) ); + int val = atoi( buf ); + m_CurrentHSVColor.x = clamp( val, 0, 360 ); + HSVtoRGB( m_CurrentHSVColor, m_CurrentColor ); + } + else if ( pPanel == m_pSaturationText ) + { + m_pSaturationText->GetText( buf, sizeof(buf) ); + int val = atoi( buf ); + val = clamp( val, 0, 100 ); + m_CurrentHSVColor.y = (float)val / 100.0f; + HSVtoRGB( m_CurrentHSVColor, m_CurrentColor ); + } + else if ( pPanel == m_pValueText ) + { + m_pValueText->GetText( buf, sizeof(buf) ); + int val = atoi( buf ); + val = clamp( val, 0, 100 ); + m_CurrentHSVColor.z = (float)val / 100.0f; + HSVtoRGB( m_CurrentHSVColor, m_CurrentColor ); + } + + // Preserve hue + if ( m_CurrentHSVColor.x == -1 ) + { + m_CurrentHSVColor.x = flHue; + } + OnColorChanged( static_cast(pPanel) ); +} + + +//----------------------------------------------------------------------------- +// +// Purpose: Modal picker frame +// +//----------------------------------------------------------------------------- +CColorPickerFrame::CColorPickerFrame( vgui::Panel *pParent, const char *pTitle ) : + BaseClass( pParent, "ColorPickerFrame" ) +{ + m_pContextKeys = NULL; + SetDeleteSelfOnClose( true ); + m_pPicker = new CColorPickerPanel( this, "ColorPicker" ); + m_pPicker->AddActionSignalTarget( this ); + m_pOpenButton = new Button( this, "OkButton", "Ok", this, "Ok" ); + m_pCancelButton = new Button( this, "CancelButton", "#FileOpenDialog_Cancel", this, "Cancel" ); + SetBlockDragChaining( true ); + + LoadControlSettings( "resource/colorpickerframe.res" ); + + int w, h; + GetSize( w, h ); + SetMinimumSize( w, h ); + + SetTitle( pTitle, false ); +} + +CColorPickerFrame::~CColorPickerFrame() +{ + CleanUpMessage(); +} + + +//----------------------------------------------------------------------------- +// Deletes the message +//----------------------------------------------------------------------------- +void CColorPickerFrame::CleanUpMessage() +{ + if ( m_pContextKeys ) + { + m_pContextKeys->deleteThis(); + m_pContextKeys = NULL; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Activate the dialog +//----------------------------------------------------------------------------- +void CColorPickerFrame::DoModal( Color initialColor, KeyValues *pContextKeys ) +{ + CleanUpMessage(); + m_pPicker->SetInitialColor( initialColor ); + m_pContextKeys = pContextKeys; + + BaseClass::DoModal(); +} + + +//----------------------------------------------------------------------------- +// Gets the initial color +//----------------------------------------------------------------------------- +void CColorPickerFrame::GetInitialColor( Color *pColor ) +{ + m_pPicker->GetInitialColor( pColor ); +} + + +//----------------------------------------------------------------------------- +// On command +//----------------------------------------------------------------------------- +void CColorPickerFrame::OnCommand( const char *pCommand ) +{ + if ( !Q_stricmp( pCommand, "Ok" ) ) + { + Color c; + m_pPicker->GetCurrentColor( &c ); + + KeyValues *pActionKeys = new KeyValues( "ColorPickerPicked" ); + pActionKeys->SetColor( "color", c ); + if ( m_pContextKeys ) + { + pActionKeys->AddSubKey( m_pContextKeys ); + m_pContextKeys = NULL; + } + CloseModal(); + PostActionSignal( pActionKeys ); + return; + } + + if ( !Q_stricmp( pCommand, "Cancel" ) ) + { + vgui::input()->ReleaseAppModalSurface(); + KeyValues *pActionKeys = new KeyValues( "ColorPickerCancel" ); + if ( m_pContextKeys ) + { + pActionKeys->AddSubKey( m_pContextKeys ); + m_pContextKeys = NULL; + } + CloseModal(); + PostActionSignal( pActionKeys ); + return; + } + + if ( !Q_stricmp( pCommand, "Preview" ) ) + { + Color c; + m_pPicker->GetCurrentColor( &c ); + + KeyValues *pActionKeys = new KeyValues( "ColorPickerPreview" ); + pActionKeys->SetColor( "color", c ); + if ( m_pContextKeys ) + { + pActionKeys->AddSubKey( m_pContextKeys->MakeCopy() ); + } + PostActionSignal( pActionKeys ); + return; + } + + BaseClass::OnCommand( pCommand ); +} + + +//----------------------------------------------------------------------------- +// +// Purpose: A button which brings up the color picker +// +//----------------------------------------------------------------------------- +CColorPickerButton::CColorPickerButton( vgui::Panel *pParent, const char *pName, vgui::Panel *pActionSignalTarget ) : + BaseClass( pParent, pName, "" ) +{ + m_CurrentColor.SetColor( 255, 255, 255, 255 ); + if ( pActionSignalTarget ) + { + AddActionSignalTarget( pActionSignalTarget ); + } +} + +CColorPickerButton::~CColorPickerButton() +{ +} + +void CColorPickerButton::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + UpdateButtonColor(); +} + + +//----------------------------------------------------------------------------- +// Called when the picker gets a new color +//----------------------------------------------------------------------------- +void CColorPickerButton::OnPicked( KeyValues *data ) +{ + SetColor( data->GetColor( "color" ) ); + + // Fire normal action signal messages + KeyValues *pMessage = new KeyValues( "ColorPickerPicked" ); + pMessage->SetColor( "color", m_CurrentColor ); + PostActionSignal( pMessage ); + PlayButtonReleasedSound(); + SetSelected( false ); +} + + +//----------------------------------------------------------------------------- +// Called when a color is previewed +//----------------------------------------------------------------------------- +void CColorPickerButton::OnPreview( KeyValues *data ) +{ + KeyValues *pMessage = new KeyValues( "ColorPickerPreview" ); + pMessage->SetColor( "color", data->GetColor( "color" ) ); + PostActionSignal( pMessage ); +} + + +//----------------------------------------------------------------------------- +// Called when cancel is hit in the picker +//----------------------------------------------------------------------------- +void CColorPickerButton::OnCancelled( ) +{ + SetSelected( false ); + + KeyValues *pMessage = new KeyValues( "ColorPickerCancel" ); + pMessage->SetColor( "startingColor", m_CurrentColor ); + PostActionSignal( pMessage ); +} + + +//----------------------------------------------------------------------------- +// Perform the click +//----------------------------------------------------------------------------- +void CColorPickerButton::DoClick() +{ + SetSelected( true ); + + CColorPickerFrame *pColorPickerDialog = new CColorPickerFrame( this, "Select Color" ); + pColorPickerDialog->AddActionSignalTarget( this ); + pColorPickerDialog->DoModal( m_CurrentColor ); +} + + +//----------------------------------------------------------------------------- +// Set current color +//----------------------------------------------------------------------------- +void CColorPickerButton::SetColor( const Color& clr ) +{ + m_CurrentColor = clr; + UpdateButtonColor(); +} + +void CColorPickerButton::SetColor( int r, int g, int b, int a ) +{ + m_CurrentColor.SetColor( r, g, b, a ); + UpdateButtonColor(); +} + + +//----------------------------------------------------------------------------- +// Update button color +//----------------------------------------------------------------------------- +void CColorPickerButton::UpdateButtonColor() +{ + SetDefaultColor( m_CurrentColor, m_CurrentColor ); + SetArmedColor( m_CurrentColor, m_CurrentColor ); + SetDepressedColor( m_CurrentColor, m_CurrentColor ); +} diff --git a/vgui2/matsys_controls/curveeditorpanel.cpp b/vgui2/matsys_controls/curveeditorpanel.cpp new file mode 100644 index 00000000..186444d9 --- /dev/null +++ b/vgui2/matsys_controls/curveeditorpanel.cpp @@ -0,0 +1,200 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#include "matsys_controls/curveeditorpanel.h" +#include "matsys_controls/matsyscontrols.h" +#include "tier1/KeyValues.h" +#include "vgui/ISurface.h" +#include "vgui/IInput.h" +#include "vgui/MouseCode.h" + +using namespace vgui; + + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- +CCurveEditorPanel::CCurveEditorPanel( vgui::Panel *pParent, const char *pName ) : BaseClass( pParent, pName ) +{ + m_nSelectedPoint = -1; + SetMouseInputEnabled( true ); + SetKeyBoardInputEnabled( true ); + m_nHighlightedPoint = -1; +} + +CCurveEditorPanel::~CCurveEditorPanel() +{ +} + + +//----------------------------------------------------------------------------- +// Converts screen location to normalized values +//----------------------------------------------------------------------------- +void CCurveEditorPanel::ScreenToValue( int x, int y, float *pIn, float *pOut ) +{ + int w, h; + GetSize( w, h ); + + *pIn = (float)x / (w-1); + *pOut = 1.0f - ((float)y / (h-1)); +} + +void CCurveEditorPanel::ValueToScreen( float flIn, float flOut, int *x, int *y ) +{ + int w, h; + GetSize( w, h ); + + *x = (int)(flIn * (w-1) + 0.5f); + *y = (h-1) - (int)(flOut * (h-1) + 0.5f); +} + + +//----------------------------------------------------------------------------- +// Handle input +//----------------------------------------------------------------------------- +void CCurveEditorPanel::OnMousePressed( vgui::MouseCode code ) +{ + BaseClass::OnMousePressed( code ); + + int x, y; + input()->GetCursorPos( x, y ); + ScreenToLocal( x, y ); + + if ( code == MOUSE_LEFT ) + { + int w, h; + GetSize( w, h ); + + float flIn, flOut; + ScreenToValue( x, y, &flIn, &flOut ); + float flTolerance = 5.0f / (w-1); // +/- 3 pixels to select the point + m_nSelectedPoint = FindOrAddControlPoint( flIn, flTolerance, flOut ); + } +} + +void CCurveEditorPanel::OnMouseReleased( vgui::MouseCode code ) +{ + BaseClass::OnMouseReleased( code ); + + if ( code == MOUSE_LEFT ) + { + m_nSelectedPoint = -1; + } +} + +void CCurveEditorPanel::OnCursorMoved( int x, int y ) +{ + BaseClass::OnCursorMoved( x, y ); + + float flIn, flOut; + ScreenToValue( x, y, &flIn, &flOut ); + + int w, h; + GetSize( w, h ); + float flTolerance = 5.0f / (w-1); // +/- 3 pixels to select the point + m_nHighlightedPoint = FindControlPoint( flIn, flTolerance ); + + if ( m_nSelectedPoint < 0 ) + return; + m_nSelectedPoint = ModifyControlPoint( m_nSelectedPoint, flIn, flOut ); +} + + +//----------------------------------------------------------------------------- +// Handles keypresses +//----------------------------------------------------------------------------- +void CCurveEditorPanel::OnKeyCodePressed( vgui::KeyCode code ) +{ + BaseClass::OnKeyCodePressed( code ); + + if ( m_nSelectedPoint >= 0 ) + { + RemoveControlPoint( m_nSelectedPoint ); + m_nSelectedPoint = -1; + } +} + + +//----------------------------------------------------------------------------- +// This paints the grid behind the curves +//----------------------------------------------------------------------------- +void CCurveEditorPanel::PaintBackground( void ) +{ + int w, h; + GetSize( w, h ); + + vgui::surface()->DrawSetColor( 255, 255, 255, 255 ); + vgui::surface()->DrawFilledRect( 0, 0, w, h ); + + vgui::surface()->DrawSetColor( 128, 128, 128, 255 ); + vgui::surface()->DrawLine( 0, h/4, w, h/4 ); + vgui::surface()->DrawLine( 0, h/2, w, h/2 ); + vgui::surface()->DrawLine( 0, 3*h/4, w, 3*h/4 ); + + vgui::surface()->DrawLine( w/4, 0, w/4, h ); + vgui::surface()->DrawLine( w/2, 0, w/2, h ); + vgui::surface()->DrawLine( 3*w/4, 0, 3*w/4, h ); + + vgui::surface()->DrawSetColor( 0, 0, 0, 255 ); + vgui::surface()->DrawLine( 0, 0, w, 0 ); + vgui::surface()->DrawLine( w, 0, w, h ); + vgui::surface()->DrawLine( w, h, 0, h ); + vgui::surface()->DrawLine( 0, h, 0, 0 ); +} + + +//----------------------------------------------------------------------------- +// Sets the color curves operation to edit +//----------------------------------------------------------------------------- +void CCurveEditorPanel::Paint( void ) +{ + int w, h; + GetSize( w, h ); + + int x0 = 0, y0 = 0; + + // FIXME: Add method to draw multiple lines DrawPolyLine connects the 1st and last points... bleah + vgui::surface()->DrawSetColor( 0, 0, 0, 255 ); + for ( int i = 0; i < w; ++i ) + { + float flIn = (float)i / (w-1); + float flOut = GetValue( flIn ); + int x = i; + int y = (h-1) - (int)(flOut * (h-1) + 0.5f); + y = clamp( y, 0, h-1 ); + + if ( i != 0 ) + { + vgui::surface()->DrawLine( x0, y0, x, y ); + } + + x0 = x; y0 = y; + } + + + // This will paint the control points + // The currently selected one will be painted red and filled. + for ( int i = ControlPointCount(); --i >= 0; ) + { + float flIn, flOut; + GetControlPoint( i, &flIn, &flOut ); + + int cx, cy; + ValueToScreen( flIn, flOut, &cx, &cy ); + + if ( (i == m_nSelectedPoint) || ((m_nSelectedPoint == -1) && (i == m_nHighlightedPoint)) ) + { + vgui::surface()->DrawSetColor( 255, 0, 0, 255 ); + vgui::surface()->DrawFilledRect( cx-3, cy-3, cx+3, cy+3 ); + } + else + { + vgui::surface()->DrawSetColor( 0, 0, 0, 255 ); + vgui::surface()->DrawOutlinedRect( cx-3, cy-3, cx+3, cy+3 ); + } + } +} \ No newline at end of file diff --git a/vgui2/matsys_controls/gamefiletreeview.cpp b/vgui2/matsys_controls/gamefiletreeview.cpp new file mode 100644 index 00000000..712d54f2 --- /dev/null +++ b/vgui2/matsys_controls/gamefiletreeview.cpp @@ -0,0 +1,301 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#if defined(WIN32) && !defined( _X360 ) +#include +#endif +#undef PropertySheet + +#include "matsys_controls/gamefiletreeview.h" +#include "filesystem.h" +#include "tier1/KeyValues.h" +#include "vgui/ISurface.h" +#include "vgui/Cursor.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +using namespace vgui; + + +//----------------------------------------------------------------------------- +// list of all tree view icons +//----------------------------------------------------------------------------- +enum +{ + IMAGE_FOLDER = 1, + IMAGE_OPENFOLDER, + IMAGE_FILE, +}; + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CGameFileTreeView::CGameFileTreeView( Panel *parent, const char *name, const char *pRootFolderName, const char *pRootDir, const char *pExtension ) : BaseClass(parent, name), m_Images( false ) +{ + m_RootDir = pRootDir; + + m_Ext = pExtension; + m_bUseExt = ( pExtension != NULL ); + + m_RootFolderName = pRootFolderName; + + // build our list of images + m_Images.AddImage( scheme()->GetImage( "resource/icon_folder", false ) ); + m_Images.AddImage( scheme()->GetImage( "resource/icon_folder_selected", false ) ); + m_Images.AddImage( scheme()->GetImage( "resource/icon_file", false ) ); + SetImageList( &m_Images, false ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Refreshes the active file list +//----------------------------------------------------------------------------- +void CGameFileTreeView::RefreshFileList() +{ + RemoveAll(); + SetFgColor(Color(216, 222, 211, 255)); + + // add the base node + KeyValues *pkv = new KeyValues( "root" ); + pkv->SetString( "text", m_RootFolderName ); + pkv->SetInt( "root", 1 ); + pkv->SetInt( "expand", 1 ); + int iRoot = AddItem( pkv, GetRootItemIndex() ); + pkv->deleteThis(); + ExpandItem( iRoot, true ); +} + + +//----------------------------------------------------------------------------- +// Selects the root folder +//----------------------------------------------------------------------------- +void CGameFileTreeView::SelectRoot() +{ + AddSelectedItem( GetRootItemIndex(), true ); +} + + +//----------------------------------------------------------------------------- +// Gets the number of root directories +//----------------------------------------------------------------------------- +int CGameFileTreeView::GetRootDirectoryCount() +{ + return GetNumChildren( GetRootItemIndex() ); +} + + +//----------------------------------------------------------------------------- +// Gets the ith root directory +//----------------------------------------------------------------------------- +const char *CGameFileTreeView::GetRootDirectory( int nIndex ) +{ + int nItemIndex = GetChild( GetRootItemIndex(), nIndex ); + KeyValues *kv = GetItemData( nItemIndex ); + if ( !kv ) + return NULL; + return kv->GetString( "path", NULL ); +} + + +//----------------------------------------------------------------------------- +// Populate the root node (necessary since tree view can't have multiple roots) +//----------------------------------------------------------------------------- +void CGameFileTreeView::PopulateRootNode( int itemIndex ) +{ + AddDirectoriesOfNode( itemIndex, m_RootDir ); + + if ( m_bUseExt ) + { + AddFilesOfNode( itemIndex, m_RootDir, m_Ext ); + } +} + + +//----------------------------------------------------------------------------- +// Populate the root node with directories +//----------------------------------------------------------------------------- +bool CGameFileTreeView::DoesDirectoryHaveSubdirectories( const char *pFilePath ) +{ + char pSearchString[MAX_PATH]; + Q_snprintf( pSearchString, MAX_PATH, "%s\\*", pFilePath ); + + // get the list of files + FileFindHandle_t findHandle; + + // generate children + // add all the items + const char *pszFileName = g_pFullFileSystem->FindFirstEx( pSearchString, "GAME", &findHandle ); + while ( pszFileName ) + { + bool bIsDirectory = g_pFullFileSystem->FindIsDirectory( findHandle ); + if ( bIsDirectory && Q_strnicmp( pszFileName, ".", 2 ) && Q_strnicmp( pszFileName, "..", 3 ) ) + return true; + + pszFileName = g_pFullFileSystem->FindNext( findHandle ); + } + + g_pFullFileSystem->FindClose( findHandle ); + return false; +} + + +//----------------------------------------------------------------------------- +// Populate the root node with directories +//----------------------------------------------------------------------------- +void CGameFileTreeView::AddDirectoriesOfNode( int itemIndex, const char *pFilePath ) +{ + char pSearchString[MAX_PATH]; + Q_snprintf( pSearchString, MAX_PATH, "%s\\*", pFilePath ); + + // get the list of files + FileFindHandle_t findHandle; + + // generate children + // add all the items + const char *pszFileName = g_pFullFileSystem->FindFirstEx( pSearchString, "GAME", &findHandle ); + while ( pszFileName ) + { + bool bIsDirectory = g_pFullFileSystem->FindIsDirectory( findHandle ); + if ( bIsDirectory && Q_strnicmp( pszFileName, ".", 2 ) && Q_strnicmp( pszFileName, "..", 3 ) ) + { + KeyValues *kv = new KeyValues( "node", "text", pszFileName ); + + char pFullPath[MAX_PATH]; + Q_snprintf( pFullPath, sizeof(pFullPath), "%s/%s", pFilePath, pszFileName ); + Q_FixSlashes( pFullPath ); + Q_strlower( pFullPath ); + bool bHasSubdirectories = DoesDirectoryHaveSubdirectories( pFullPath ); + kv->SetString( "path", pFullPath ); + + kv->SetInt( "expand", bHasSubdirectories ); + kv->SetInt( "dir", 1 ); + kv->SetInt( "image", IMAGE_FOLDER ); + + int itemID = AddItem(kv, itemIndex); + kv->deleteThis(); + + // mark directories in orange + SetItemColorForDirectories( itemID ); + } + + pszFileName = g_pFullFileSystem->FindNext( findHandle ); + } + + g_pFullFileSystem->FindClose( findHandle ); +} + + +//----------------------------------------------------------------------------- +// Populate the root node with files +//----------------------------------------------------------------------------- +void CGameFileTreeView::AddFilesOfNode( int itemIndex, const char *pFilePath, const char *pExt ) +{ + char pSearchString[MAX_PATH]; + Q_snprintf( pSearchString, MAX_PATH, "%s\\*.%s", pFilePath, pExt ); + + // get the list of files + FileFindHandle_t findHandle; + + // generate children + // add all the items + const char *pszFileName = g_pFullFileSystem->FindFirst( pSearchString, &findHandle ); + while ( pszFileName ) + { + if ( !g_pFullFileSystem->FindIsDirectory( findHandle ) ) + { + KeyValues *kv = new KeyValues( "node", "text", pszFileName ); + + char pFullPath[MAX_PATH]; + Q_snprintf( pFullPath, MAX_PATH, "%s\\%s", pFilePath, pszFileName ); + kv->SetString( "path", pFullPath ); + kv->SetInt( "image", IMAGE_FILE ); + + AddItem(kv, itemIndex); + kv->deleteThis(); + } + + pszFileName = g_pFullFileSystem->FindNext( findHandle ); + } + + g_pFullFileSystem->FindClose( findHandle ); +} + + +//----------------------------------------------------------------------------- +// override to incremental request and show p4 directories +//----------------------------------------------------------------------------- +void CGameFileTreeView::GenerateChildrenOfNode(int itemIndex) +{ + KeyValues *pkv = GetItemData(itemIndex); + if ( pkv->GetInt("root") ) + { + PopulateRootNode( itemIndex ); + return; + } + + if (!pkv->GetInt("dir")) + return; + + const char *pFilePath = pkv->GetString("path", ""); + if (!pFilePath[0]) + return; + + surface()->SetCursor(dc_waitarrow); + + AddDirectoriesOfNode( itemIndex, pFilePath ); + + if ( m_bUseExt ) + { + AddFilesOfNode( itemIndex, pFilePath, m_Ext ); + } +} + + +//----------------------------------------------------------------------------- +// setup a context menu whenever a directory is clicked on +//----------------------------------------------------------------------------- +void CGameFileTreeView::GenerateContextMenu( int itemIndex, int x, int y ) +{ + return; + + /* + KeyValues *pkv = GetItemData(itemIndex); + const char *pFilePath = pkv->GetString("path", ""); + if (!pFilePath[0]) + return; + + Menu *pContext = new Menu(this, "FileContext"); + pContext->AddMenuItem("Cloak folder", new KeyValues("CloakFolder", "item", itemIndex), GetParent(), NULL); + + // show the context menu + pContext->SetPos(x, y); + pContext->SetVisible(true); + */ +} + + +//----------------------------------------------------------------------------- +// Sets an item to be colored as if its a menu +//----------------------------------------------------------------------------- +void CGameFileTreeView::SetItemColorForDirectories( int itemID ) +{ + // mark directories in orange + SetItemFgColor( itemID, Color(224, 192, 0, 255) ); +} + + +//----------------------------------------------------------------------------- +// setup a smaller font +//----------------------------------------------------------------------------- +void CGameFileTreeView::ApplySchemeSettings(IScheme *pScheme) +{ + BaseClass::ApplySchemeSettings(pScheme); + SetFont( pScheme->GetFont("DefaultSmall") ); +} + diff --git a/vgui2/matsys_controls/manipulator.cpp b/vgui2/matsys_controls/manipulator.cpp new file mode 100644 index 00000000..b582b11f --- /dev/null +++ b/vgui2/matsys_controls/manipulator.cpp @@ -0,0 +1,201 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "matsys_controls/manipulator.h" + +#include "materialsystem/imaterialsystem.h" + +#include "vgui/IVGui.h" +#include "vgui/IInput.h" +#include "vgui/ISystem.h" +#include "vgui/MouseCode.h" + +#include "mathlib/vector.h" +#include "mathlib/vmatrix.h" +#include "mathlib/mathlib.h" + +#include + +using namespace vgui; + + +//----------------------------------------------------------------------------- +// local helper functions +//----------------------------------------------------------------------------- +static float UpdateTime( float &flLastTime ) +{ + float flTime = vgui::system()->GetFrameTime(); + float dt = flTime - flLastTime; + flLastTime = flTime; + return dt; +} + + +//----------------------------------------------------------------------------- +// Base class for manipulators which operate on transforms +//----------------------------------------------------------------------------- +CTransformManipulator::CTransformManipulator( matrix3x4_t *pTransform ) : + m_pTransform( pTransform ) +{ +} + +void CTransformManipulator::SetTransform( matrix3x4_t *pTransform ) +{ + m_pTransform = pTransform; +} + +matrix3x4_t *CTransformManipulator::GetTransform( void ) +{ + return m_pTransform; +} + + +//----------------------------------------------------------------------------- +// CPotteryWheelManip - nendo-style camera manipulator +//----------------------------------------------------------------------------- +CPotteryWheelManip::CPotteryWheelManip( matrix3x4_t *pTransform ) : + CTransformManipulator( pTransform ), + m_lastx( -1 ), m_lasty( -1 ), + m_zoom( 100.0f ), m_altitude( 0.0f ), m_azimuth( 0.0f ), + m_prevZoom( 100.0f ), m_prevAltitude( 0.0f ), m_prevAzimuth( 0.0f ), + m_flLastMouseTime( 0.0f ), m_flLastTickTime( 0.0f ), + m_flSpin( 0.0f ), m_bSpin( false ) +{ +} + +void CPotteryWheelManip::OnBeginManipulation( void ) +{ + m_prevZoom = m_zoom; + m_prevAltitude = m_altitude; + m_prevAzimuth = m_azimuth; + m_flLastMouseTime = m_flLastTickTime = vgui::system()->GetFrameTime(); + m_flSpin = 0.0f; + m_bSpin = false; +} + +// Sets the zoom level +void CPotteryWheelManip::SetZoom( float flZoom ) +{ + m_prevZoom = m_zoom = flZoom; +} + + +void CPotteryWheelManip::OnAcceptManipulation( void ) +{ + m_flSpin = 0.0f; + m_bSpin = false; +} + +void CPotteryWheelManip::OnCancelManipulation( void ) +{ + m_zoom = m_prevZoom; + m_altitude = m_prevAltitude; + m_azimuth = m_prevAzimuth; + m_flSpin = 0.0f; + m_bSpin = false; + UpdateTransform(); +} + + +void CPotteryWheelManip::OnTick( void ) +{ + float dt = UpdateTime( m_flLastTickTime ); + + if ( m_bSpin ) + { + m_azimuth += dt * m_flSpin; + UpdateTransform(); + } +} + +void CPotteryWheelManip::OnCursorMoved( int x, int y ) +{ + float dt = UpdateTime( m_flLastMouseTime ); + + if ( m_bSpin ) + { + m_lastx = x; + m_lasty = y; + return; + } + + if ( input()->IsMouseDown( MOUSE_MIDDLE ) ) + { + int dy = y - m_lasty; + int dx = x - m_lastx; + + if ( abs( dx ) < 2 * abs( dy ) ) + { + UpdateZoom( 0.2f * dy ); + } + else + { + m_flSpin = (dt != 0.0f) ? 0.002f * dx / dt : 0.0f; + m_azimuth += 0.002f * dx; + } + } + else + { + m_azimuth += 0.002f * ( x - m_lastx ); + m_altitude -= 0.002f * ( y - m_lasty ); + m_altitude = max( (float)-M_PI/2, min( (float)M_PI/2, m_altitude ) ); + } + m_lastx = x; + m_lasty = y; + + UpdateTransform(); +} + +void CPotteryWheelManip::OnMousePressed( vgui::MouseCode code, int x, int y ) +{ + UpdateTime( m_flLastMouseTime ); + m_lastx = x; + m_lasty = y; + m_bSpin = false; + m_flSpin = 0.0f; +} + +void CPotteryWheelManip::OnMouseReleased( vgui::MouseCode code, int x, int y ) +{ + UpdateTime( m_flLastMouseTime ); + + if ( code == MOUSE_MIDDLE ) + { + m_bSpin = ( fabs( m_flSpin ) > 1.0f ); + } + + m_lastx = x; + m_lasty = y; +} + +void CPotteryWheelManip::OnMouseWheeled( int delta ) +{ + UpdateTime( m_flLastMouseTime ); + + UpdateZoom( -10.0f * delta ); + UpdateTransform(); +} + +void CPotteryWheelManip::UpdateTransform() +{ + if ( !m_pTransform ) + return; + + float y = m_zoom * sin( m_altitude ); + float xz = m_zoom * cos( m_altitude ); + float x = xz * sin( m_azimuth ); + float z = xz * cos( m_azimuth ); + + Vector position(x, y, z); + AngleMatrix( RadianEuler( -m_altitude, m_azimuth, 0 ), position, *m_pTransform ); +} + + +void CPotteryWheelManip::UpdateZoom( float delta ) +{ + m_zoom *= pow( 1.01f, delta ); +} diff --git a/vgui2/matsys_controls/matsys_controls.vpc b/vgui2/matsys_controls/matsys_controls.vpc new file mode 100644 index 00000000..c4b1bc8c --- /dev/null +++ b/vgui2/matsys_controls/matsys_controls.vpc @@ -0,0 +1,66 @@ +//----------------------------------------------------------------------------- +// MATSYS_CONTROLS.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$macro SRCDIR "..\.." + +$include "$SRCDIR\vpc_scripts\source_lib_base.vpc" + +$Project "matsys_controls" +{ + $Folder "Source Files" + { + $File "assetpicker.cpp" + $File "baseassetpicker.cpp" + $File "colorpickerpanel.cpp" + $File "curveeditorpanel.cpp" + $File "gamefiletreeview.cpp" + $File "manipulator.cpp" + $File "matsyscontrols.cpp" + $File "mdlpanel.cpp" + $File "mdlpicker.cpp" + $File "mdlsequencepicker.cpp" + $File "picker.cpp" + $File "potterywheelpanel.cpp" + $File "proceduraltexturepanel.cpp" + $File "QCGenerator.cpp" + $File "sequencepicker.cpp" + $File "tgapreviewpanel.cpp" + $File "vmtpicker.cpp" + $File "vmtpreviewpanel.cpp" + $File "vtfpicker.cpp" + $File "vtfpreviewpanel.cpp" + $File "vmtpanel.cpp" + } + + $Folder "Header Files" + { + $File "$SRCDIR\public\matsys_controls\assetpicker.h" + $File "$SRCDIR\public\matsys_controls\baseassetpicker.h" + $File "$SRCDIR\public\matsys_controls\colorpickerpanel.h" + $File "$SRCDIR\public\matsys_controls\gamefiletreeview.h" + $File "$SRCDIR\public\matsys_controls\manipulator.h" + $File "$SRCDIR\public\matsys_controls\matsyscontrols.h" + $File "$SRCDIR\public\matsys_controls\mdlpanel.h" + $File "$SRCDIR\public\matsys_controls\mdlpicker.h" + $File "$SRCDIR\public\matsys_controls\mdlsequencepicker.h" + $File "$SRCDIR\public\matsys_controls\picker.h" + $File "$SRCDIR\public\matsys_controls\potterywheelpanel.h" + $File "$SRCDIR\public\matsys_controls\proceduraltexturepanel.h" + $File "$SRCDIR\public\matsys_controls\QCGenerator.h" + $File "$SRCDIR\public\matsys_controls\sequencepicker.h" + $File "$SRCDIR\public\matsys_controls\tgapreviewpanel.h" + $File "$SRCDIR\public\matsys_controls\vmtpicker.h" + $File "$SRCDIR\public\matsys_controls\vmtpreviewpanel.h" + $File "$SRCDIR\public\matsys_controls\vtfpicker.h" + $File "$SRCDIR\public\matsys_controls\vtfpreviewpanel.h" + $File "$SRCDIR\public\matsys_controls\vmtpanel.h" + } + + $Folder "Link Libraries" + { + $Lib bitmap [$WIN32] + } +} diff --git a/vgui2/matsys_controls/matsyscontrols.cpp b/vgui2/matsys_controls/matsyscontrols.cpp new file mode 100644 index 00000000..11c415f2 --- /dev/null +++ b/vgui2/matsys_controls/matsyscontrols.cpp @@ -0,0 +1,100 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#include "matsys_controls/matsyscontrols.h" +#include +#include +#include +#include +#include +#include "vgui_controls/Controls.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +namespace vgui +{ + +IMaterialSystem *g_pMaterialSystem = NULL; +IMaterialSystem *MaterialSystem() +{ + return g_pMaterialSystem; +} + +IMaterialSystemHardwareConfig *g_pMaterialSystemHardwareConfig = NULL; +IMaterialSystemHardwareConfig *MaterialSystemHardwareConfig() +{ + return g_pMaterialSystemHardwareConfig; +} + +IMDLCache *g_pMDLCache = NULL; +IMDLCache *MDLCache() +{ + return g_pMDLCache; +} + +IMatSystemSurface *g_pMatSystemSurface = NULL; +IMatSystemSurface *MatSystemSurface() +{ + return g_pMatSystemSurface; +} + +IStudioRender *g_pStudioRender = NULL; +IStudioRender *StudioRender() +{ + return g_pStudioRender; +} + + +//----------------------------------------------------------------------------- +// Purpose: finds a particular interface in the factory set +//----------------------------------------------------------------------------- +static void *InitializeInterface( char const *interfaceName, CreateInterfaceFn *factoryList, int numFactories ) +{ + void *retval; + + for ( int i = 0; i < numFactories; i++ ) + { + CreateInterfaceFn factory = factoryList[ i ]; + if ( !factory ) + continue; + + retval = factory( interfaceName, NULL ); + if ( retval ) + return retval; + } + + // No provider for requested interface!!! + // Assert( !"No provider for requested interface!!!" ); + + return NULL; +} + + +//----------------------------------------------------------------------------- +// Purpose: Initializes the controls +//----------------------------------------------------------------------------- +bool VGui_InitMatSysInterfacesList( const char *moduleName, CreateInterfaceFn *factoryList, int numFactories ) +{ + if ( !vgui::VGui_InitInterfacesList( moduleName, factoryList, numFactories ) ) + return false; + + g_pMaterialSystem = (IMaterialSystem *)InitializeInterface( MATERIAL_SYSTEM_INTERFACE_VERSION, factoryList, numFactories ); + g_pMatSystemSurface = (IMatSystemSurface *)InitializeInterface( MAT_SYSTEM_SURFACE_INTERFACE_VERSION, factoryList, numFactories ); + g_pMDLCache = (IMDLCache *)InitializeInterface( MDLCACHE_INTERFACE_VERSION, factoryList, numFactories ); + g_pStudioRender = (IStudioRender *)InitializeInterface( STUDIO_RENDER_INTERFACE_VERSION, factoryList, numFactories ); + g_pMaterialSystemHardwareConfig = (IMaterialSystemHardwareConfig *)InitializeInterface( MATERIALSYSTEM_HARDWARECONFIG_INTERFACE_VERSION, factoryList, numFactories ); + + // MDL cache + studiorender are optional + return ( g_pMaterialSystem && g_pMatSystemSurface && g_pMaterialSystemHardwareConfig ); +} + + +} // namespace vgui + + + diff --git a/vgui2/matsys_controls/mdlpanel.cpp b/vgui2/matsys_controls/mdlpanel.cpp new file mode 100644 index 00000000..baa3af33 --- /dev/null +++ b/vgui2/matsys_controls/mdlpanel.cpp @@ -0,0 +1,983 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "matsys_controls/mdlpanel.h" +#include "materialsystem/imaterialsystem.h" +#include "materialsystem/imaterialsystemhardwareconfig.h" +#include "materialsystem/imesh.h" +#include "vgui/IVGui.h" +#include "tier1/KeyValues.h" +#include "vgui_controls/Frame.h" +#include "tier1/convar.h" +#include "tier0/dbg.h" +#include "tier1/fmtstr.h" +#include "istudiorender.h" +#include "matsys_controls/matsyscontrols.h" +#include "vcollide.h" +#include "vcollide_parse.h" +#include "bone_setup.h" +#include "vphysics_interface.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +using namespace vgui; + +DECLARE_BUILD_FACTORY( CMDLPanel ); + +static const int THUMBNAIL_SAFE_ZONE_SIZE = 512; +static const int THUMBNAIL_SAFE_ZONE_HEIGHT = 92; +static const float THUMBNAIL_SAFE_ZONE_HEIGHT_SCALE = (float)THUMBNAIL_SAFE_ZONE_HEIGHT / THUMBNAIL_SAFE_ZONE_SIZE; + +//----------------------------------------------------------------------------- +// Purpose: Keeps a global clock to autoplay sequences to run from +// Also deals with speedScale changes +//----------------------------------------------------------------------------- +float GetAutoPlayTime( void ) +{ + static int g_prevTicks; + static float g_time; + + int ticks = Plat_MSTime(); + + // limit delta so that float time doesn't overflow + if (g_prevTicks == 0) + { + g_prevTicks = ticks; + } + + g_time += ( ticks - g_prevTicks ) / 1000.0f; + g_prevTicks = ticks; + + return g_time; +} + + +//----------------------------------------------------------------------------- +// Constructor, destructor +//----------------------------------------------------------------------------- +CMDLPanel::CMDLPanel( vgui::Panel *pParent, const char *pName ) : BaseClass( pParent, pName ) +{ + SetVisible( true ); + + // Used to poll input + vgui::ivgui()->AddTickSignal( GetVPanel() ); + + // Deal with the default cubemap + ITexture *pCubemapTexture = vgui::MaterialSystem()->FindTexture( "editor/cubemap", NULL, true ); + m_DefaultEnvCubemap.Init( pCubemapTexture ); + pCubemapTexture = vgui::MaterialSystem()->FindTexture( "editor/cubemap.hdr", NULL, true ); + m_DefaultHDREnvCubemap.Init( pCubemapTexture ); + + SetIdentityMatrix( m_RootMDL.m_MDLToWorld ); + m_RootMDL.m_pStudioHdr = NULL; + m_RootMDL.m_unMdlCacheSerial = 0; + m_bDrawCollisionModel = false; + m_bWireFrame = false; + m_bGroundGrid = false; + m_bLockView = false; + m_bLookAtCamera = true; + m_bThumbnailSafeZone = false; + m_nNumSequenceLayers = 0; + ResetAnimationEventState( &m_EventState ); +} + +CMDLPanel::~CMDLPanel() +{ + m_aMergeMDLs.Purge(); + m_DefaultEnvCubemap.Shutdown( ); + m_DefaultHDREnvCubemap.Shutdown(); + if ( m_RootMDL.m_pStudioHdr ) + { + delete m_RootMDL.m_pStudioHdr; + m_RootMDL.m_pStudioHdr = NULL; + } +} + + +//----------------------------------------------------------------------------- +// Scheme settings +//----------------------------------------------------------------------------- +void CMDLPanel::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + SetBackgroundColor( GetBgColor() ); + SetBorder( pScheme->GetBorder( "MenuBorder") ); +} + + +//----------------------------------------------------------------------------- +// Rendering options +//----------------------------------------------------------------------------- +void CMDLPanel::SetCollsionModel( bool bVisible ) +{ + m_bDrawCollisionModel = bVisible; +} + +void CMDLPanel::SetGroundGrid( bool bVisible ) +{ + m_bGroundGrid = bVisible; +} + +void CMDLPanel::SetWireFrame( bool bVisible ) +{ + m_bWireFrame = bVisible; +} + +void CMDLPanel::SetLockView( bool bLocked ) +{ + m_bLockView = bLocked; +} + +void CMDLPanel::SetLookAtCamera( bool bLookAtCamera ) +{ + m_bLookAtCamera = bLookAtCamera; +} + +void CMDLPanel::SetIgnoreDoubleClick( bool bState ) +{ + m_bIgnoreDoubleClick = bState; +} + +void CMDLPanel::SetThumbnailSafeZone( bool bVisible ) +{ + m_bThumbnailSafeZone = bVisible; +} + +//----------------------------------------------------------------------------- +// Stores the clip +//----------------------------------------------------------------------------- +void CMDLPanel::SetMDL( MDLHandle_t handle, void *pProxyData ) +{ + m_RootMDL.m_MDL.SetMDL( handle ); + if ( m_RootMDL.m_pStudioHdr ) + { + delete m_RootMDL.m_pStudioHdr; + } + m_RootMDL.m_pStudioHdr = new CStudioHdr( m_RootMDL.m_MDL.GetStudioHdr(), g_pMDLCache ); + m_RootMDL.m_MDL.m_pProxyData = pProxyData; + + Vector vecMins, vecMaxs; + GetMDLBoundingBox( &vecMins, &vecMaxs, handle, m_RootMDL.m_MDL.m_nSequence ); + + m_RootMDL.m_MDL.m_bWorldSpaceViewTarget = false; + m_RootMDL.m_MDL.m_vecViewTarget.Init( 100.0f, 0.0f, vecMaxs.z ); + + m_RootMDL.m_flCycleStartTime = 0.f; + + // Set the pose parameters to the default for the mdl + SetPoseParameters( NULL, 0 ); + + // Clear any sequence layers + SetSequenceLayers( NULL, 0 ); + + ResetAnimationEventState( &m_EventState ); +} + +//----------------------------------------------------------------------------- +// An MDL was selected +//----------------------------------------------------------------------------- +void CMDLPanel::SetMDL( const char *pMDLName, void *pProxyData ) +{ + MDLHandle_t hMDLFindResult = vgui::MDLCache()->FindMDL( pMDLName ); + MDLHandle_t hMDL = pMDLName ? hMDLFindResult : MDLHANDLE_INVALID; + if ( vgui::MDLCache()->IsErrorModel( hMDL ) ) + { + hMDL = MDLHANDLE_INVALID; + } + + SetMDL( hMDL, pProxyData ); + + // FindMDL takes a reference and the the CMDL will also hold a reference for as long as it sticks around. Release the FindMDL reference. + int nRef = vgui::MDLCache()->Release( hMDLFindResult ); + (void)nRef; // Avoid unreferenced variable warning + AssertMsg( hMDL == MDLHANDLE_INVALID || nRef > 0, "CMDLPanel::SetMDL referenced a model that has a zero ref count." ); +} + +//----------------------------------------------------------------------------- +// Purpose: Returns a model bounding box. +//----------------------------------------------------------------------------- +bool CMDLPanel::GetBoundingBox( Vector &vecBoundsMin, Vector &vecBoundsMax ) +{ + // Check to see if we have a valid model to look at. + if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID ) + return false; + + GetMDLBoundingBox( &vecBoundsMin, &vecBoundsMax, m_RootMDL.m_MDL.GetMDL(), m_RootMDL.m_MDL.m_nSequence ); + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns a more accurate bounding sphere +//----------------------------------------------------------------------------- +bool CMDLPanel::GetBoundingSphere( Vector &vecCenter, float &flRadius ) +{ + // Check to see if we have a valid model to look at. + if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID ) + return false; + + Vector vecEngineCenter; + GetMDLBoundingSphere( &vecEngineCenter, &flRadius, m_RootMDL.m_MDL.GetMDL(), m_RootMDL.m_MDL.m_nSequence ); + VectorTransform( vecEngineCenter, m_RootMDL.m_MDLToWorld, vecCenter ); + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMDLPanel::SetModelAnglesAndPosition( const QAngle &angRot, const Vector &vecPos ) +{ + SetIdentityMatrix( m_RootMDL.m_MDLToWorld ); + AngleMatrix( angRot, vecPos, m_RootMDL.m_MDLToWorld ); +} + +//----------------------------------------------------------------------------- +// Sets the camera to look at the model +//----------------------------------------------------------------------------- +void CMDLPanel::LookAtMDL() +{ + // Check to see if we have a valid model to look at. + if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID ) + return; + + if ( m_bLockView ) + return; + + float flRadius; + Vector vecCenter; + GetBoundingSphere( vecCenter, flRadius ); + LookAt( vecCenter, flRadius ); +} + + +//----------------------------------------------------------------------------- +// FIXME: This should be moved into studiorender +//----------------------------------------------------------------------------- +static ConVar r_showenvcubemap( "r_showenvcubemap", "0", FCVAR_CHEAT ); +static ConVar r_eyegloss ( "r_eyegloss", "1", FCVAR_ARCHIVE ); // wet eyes +static ConVar r_eyemove ( "r_eyemove", "1", FCVAR_ARCHIVE ); // look around +static ConVar r_eyeshift_x ( "r_eyeshift_x", "0", FCVAR_ARCHIVE ); // eye X position +static ConVar r_eyeshift_y ( "r_eyeshift_y", "0", FCVAR_ARCHIVE ); // eye Y position +static ConVar r_eyeshift_z ( "r_eyeshift_z", "0", FCVAR_ARCHIVE ); // eye Z position +static ConVar r_eyesize ( "r_eyesize", "0", FCVAR_ARCHIVE ); // adjustment to iris textures +static ConVar mat_softwareskin( "mat_softwareskin", "0", FCVAR_CHEAT ); +static ConVar r_nohw ( "r_nohw", "0", FCVAR_CHEAT ); +static ConVar r_nosw ( "r_nosw", "0", FCVAR_CHEAT ); +static ConVar r_teeth ( "r_teeth", "1" ); +static ConVar r_drawentities ( "r_drawentities", "1", FCVAR_CHEAT ); +static ConVar r_flex ( "r_flex", "1" ); +static ConVar r_eyes ( "r_eyes", "1" ); +static ConVar r_skin ( "r_skin","0", FCVAR_CHEAT ); +static ConVar r_maxmodeldecal ( "r_maxmodeldecal", "50" ); +static ConVar r_modelwireframedecal ( "r_modelwireframedecal", "0", FCVAR_CHEAT ); +static ConVar mat_normals ( "mat_normals", "0", FCVAR_CHEAT ); +static ConVar r_eyeglintlodpixels ( "r_eyeglintlodpixels", "0", FCVAR_CHEAT ); +static ConVar r_rootlod ( "r_rootlod", "0" ); + +static StudioRenderConfig_t s_StudioRenderConfig; + +void CMDLPanel::UpdateStudioRenderConfig( void ) +{ + memset( &s_StudioRenderConfig, 0, sizeof(s_StudioRenderConfig) ); + + s_StudioRenderConfig.bEyeMove = !!r_eyemove.GetInt(); + s_StudioRenderConfig.fEyeShiftX = r_eyeshift_x.GetFloat(); + s_StudioRenderConfig.fEyeShiftY = r_eyeshift_y.GetFloat(); + s_StudioRenderConfig.fEyeShiftZ = r_eyeshift_z.GetFloat(); + s_StudioRenderConfig.fEyeSize = r_eyesize.GetFloat(); + if( mat_softwareskin.GetInt() || m_bWireFrame ) + { + s_StudioRenderConfig.bSoftwareSkin = true; + } + else + { + s_StudioRenderConfig.bSoftwareSkin = false; + } + s_StudioRenderConfig.bNoHardware = !!r_nohw.GetInt(); + s_StudioRenderConfig.bNoSoftware = !!r_nosw.GetInt(); + s_StudioRenderConfig.bTeeth = !!r_teeth.GetInt(); + s_StudioRenderConfig.drawEntities = r_drawentities.GetInt(); + s_StudioRenderConfig.bFlex = !!r_flex.GetInt(); + s_StudioRenderConfig.bEyes = !!r_eyes.GetInt(); + s_StudioRenderConfig.bWireframe = m_bWireFrame; + s_StudioRenderConfig.bDrawNormals = mat_normals.GetBool(); + s_StudioRenderConfig.skin = r_skin.GetInt(); + s_StudioRenderConfig.maxDecalsPerModel = r_maxmodeldecal.GetInt(); + s_StudioRenderConfig.bWireframeDecals = r_modelwireframedecal.GetInt() != 0; + + s_StudioRenderConfig.fullbright = false; + s_StudioRenderConfig.bSoftwareLighting = false; + + s_StudioRenderConfig.bShowEnvCubemapOnly = r_showenvcubemap.GetInt() ? true : false; + s_StudioRenderConfig.fEyeGlintPixelWidthLODThreshold = r_eyeglintlodpixels.GetFloat(); + + StudioRender()->UpdateConfig( s_StudioRenderConfig ); +} + +void CMDLPanel::DrawCollisionModel() +{ + if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID ) + { + return; + } + + vcollide_t *pCollide = MDLCache()->GetVCollide( m_RootMDL.m_MDL.GetMDL() ); + + if ( !pCollide || pCollide->solidCount <= 0 ) + return; + + static color32 color = {255,0,0,0}; + + IVPhysicsKeyParser *pParser = g_pPhysicsCollision->VPhysicsKeyParserCreate( pCollide->pKeyValues ); + CStudioHdr &studioHdr = *m_RootMDL.m_pStudioHdr; + + matrix3x4_t pBoneToWorld[MAXSTUDIOBONES]; + m_RootMDL.m_MDL.SetUpBones( m_RootMDL.m_MDLToWorld, MAXSTUDIOBONES, pBoneToWorld ); + + // PERFORMANCE: Just parse the script each frame. It's fast enough for tools. If you need + // this to go faster then cache off the bone index mapping in an array like HLMV does + while ( !pParser->Finished() ) + { + const char *pBlock = pParser->GetCurrentBlockName(); + if ( !stricmp( pBlock, "solid" ) ) + { + solid_t solid; + + pParser->ParseSolid( &solid, NULL ); + int boneIndex = Studio_BoneIndexByName( &studioHdr, solid.name ); + Vector *outVerts; + int vertCount = g_pPhysicsCollision->CreateDebugMesh( pCollide->solids[solid.index], &outVerts ); + + if ( vertCount ) + { + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + pRenderContext->CullMode( MATERIAL_CULLMODE_CCW ); + // NOTE: assumes these have been set up already by the model render code + // So this is a little bit of a back door to a cache of the bones + // this code wouldn't work unless you draw the model this frame before calling + // this routine. CMDLPanel always does this, but it's worth noting. + // A better solution would be to move the ragdoll visulization into the CDmeMdl + // and either draw it there or make it queryable and query/draw here. + matrix3x4_t xform; + SetIdentityMatrix( xform ); + if ( boneIndex >= 0 ) + { + MatrixCopy( pBoneToWorld[ boneIndex ], xform ); + } + IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_Wireframe ); + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, vertCount/3 ); + + for ( int j = 0; j < vertCount; j++ ) + { + Vector out; + VectorTransform( outVerts[j].Base(), xform, out.Base() ); + meshBuilder.Position3fv( out.Base() ); + meshBuilder.Color4ub( color.r, color.g, color.b, color.a ); + meshBuilder.TexCoord2f( 0, 0, 0 ); + meshBuilder.AdvanceVertex(); + } + meshBuilder.End(); + pMesh->Draw(); + } + + g_pPhysicsCollision->DestroyDebugMesh( vertCount, outVerts ); + } + else + { + pParser->SkipBlock(); + } + } + g_pPhysicsCollision->VPhysicsKeyParserDestroy( pParser ); +} + +void CMDLPanel::SetupRenderState( int nDisplayWidth, int nDisplayHeight ) +{ + int iWidth = nDisplayWidth; + int iHeight = nDisplayHeight; + if ( m_bThumbnailSafeZone ) + { + iWidth = THUMBNAIL_SAFE_ZONE_SIZE; + iHeight = THUMBNAIL_SAFE_ZONE_SIZE; + } + BaseClass::SetupRenderState( iWidth, iHeight ); +} + +//----------------------------------------------------------------------------- +// paint it! +//----------------------------------------------------------------------------- +void CMDLPanel::OnPaint3D() +{ + if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID ) + return; + + // FIXME: Move this call into DrawModel in StudioRender + StudioRenderConfig_t oldStudioRenderConfig; + StudioRender()->GetCurrentConfig( oldStudioRenderConfig ); + + UpdateStudioRenderConfig(); + + CMatRenderContextPtr pRenderContext( vgui::MaterialSystem() ); + if ( vgui::MaterialSystemHardwareConfig()->GetHDRType() == HDR_TYPE_NONE ) + { + ITexture *pMyCube = HasLightProbe() ? GetLightProbeCubemap( false ) : m_DefaultEnvCubemap; + pRenderContext->BindLocalCubemap( pMyCube ); + } + else + { + ITexture *pMyCube = HasLightProbe() ? GetLightProbeCubemap( true ) : m_DefaultHDREnvCubemap; + pRenderContext->BindLocalCubemap( pMyCube ); + } + + PrePaint3D( pRenderContext ); + + if ( m_bGroundGrid ) + { + DrawGrid(); + } + + if ( m_bLookAtCamera ) + { + matrix3x4_t worldToCamera; + ComputeCameraTransform( &worldToCamera ); + + Vector vecPosition; + MatrixGetColumn( worldToCamera, 3, vecPosition ); + m_RootMDL.m_MDL.m_bWorldSpaceViewTarget = true; + m_RootMDL.m_MDL.m_vecViewTarget = vecPosition; + } + + // Draw the MDL + CStudioHdr &studioHdr = *m_RootMDL.m_pStudioHdr; + + SetupFlexWeights(); + + matrix3x4_t *pBoneToWorld = g_pStudioRender->LockBoneMatrices( studioHdr.numbones() ); + m_RootMDL.m_MDL.SetUpBones( m_RootMDL.m_MDLToWorld, studioHdr.numbones(), pBoneToWorld, m_PoseParameters, m_SequenceLayers, m_nNumSequenceLayers ); + g_pStudioRender->UnlockBoneMatrices(); + + IMaterial* pOverrideMaterial = GetOverrideMaterial( m_RootMDL.m_MDL.GetMDL() ); + if ( pOverrideMaterial != NULL ) + g_pStudioRender->ForcedMaterialOverride( pOverrideMaterial ); + + m_RootMDL.m_MDL.Draw( m_RootMDL.m_MDLToWorld, pBoneToWorld ); + + if ( pOverrideMaterial != NULL ) + g_pStudioRender->ForcedMaterialOverride( NULL ); + + pOverrideMaterial = NULL; + + // Draw the merge MDLs. + matrix3x4_t matMergeBoneToWorld[MAXSTUDIOBONES]; + int nMergeCount = m_aMergeMDLs.Count(); + for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge ) + { + if ( m_aMergeMDLs[iMerge].m_bDisabled ) + continue; + + // Get the merge studio header. + CStudioHdr *pMergeHdr = m_aMergeMDLs[iMerge].m_pStudioHdr; + matrix3x4_t *pMergeBoneToWorld = &matMergeBoneToWorld[0]; + + // If we have a valid mesh, bonemerge it. If we have an invalid mesh we can't bonemerge because + // it'll crash trying to pull data from the missing header. + if ( pMergeHdr != NULL ) + { + CStudioHdr &mergeHdr = *pMergeHdr; + m_aMergeMDLs[iMerge].m_MDL.SetupBonesWithBoneMerge( &mergeHdr, pMergeBoneToWorld, &studioHdr, pBoneToWorld, m_RootMDL.m_MDLToWorld ); + + pOverrideMaterial = GetOverrideMaterial( m_aMergeMDLs[iMerge].m_MDL.GetMDL() ); + if ( pOverrideMaterial != NULL ) + g_pStudioRender->ForcedMaterialOverride( pOverrideMaterial ); + + m_aMergeMDLs[iMerge].m_MDL.Draw( m_aMergeMDLs[iMerge].m_MDLToWorld, pMergeBoneToWorld ); + + if ( pOverrideMaterial != NULL ) + g_pStudioRender->ForcedMaterialOverride( NULL ); + + // Notify of model render + RenderingMergedModel( pRenderContext, &mergeHdr, m_aMergeMDLs[iMerge].m_MDL.GetMDL(), pMergeBoneToWorld ); + } + } + + RenderingRootModel( pRenderContext, &studioHdr, m_RootMDL.m_MDL.GetMDL(), pBoneToWorld ); + + PostPaint3D( pRenderContext ); + + if ( m_bDrawCollisionModel ) + { + DrawCollisionModel(); + } + + pRenderContext->Flush(); + StudioRender()->UpdateConfig( oldStudioRenderConfig ); +} + + +//----------------------------------------------------------------------------- +// Sets the current LOD +//----------------------------------------------------------------------------- +void CMDLPanel::SetLOD( int nLOD ) +{ + m_RootMDL.m_MDL.m_nLOD = nLOD; + + int nMergeCount = m_aMergeMDLs.Count(); + for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge ) + { + m_aMergeMDLs[iMerge].m_MDL.m_nLOD = nLOD; + } +} + + +//----------------------------------------------------------------------------- +// Sets the current sequence +//----------------------------------------------------------------------------- +void CMDLPanel::SetSequence( int nSequence, bool bResetSequence ) +{ + m_RootMDL.m_MDL.m_nSequence = nSequence; + + if ( bResetSequence ) + { + m_RootMDL.m_flCycleStartTime = GetAutoPlayTime(); + } +} + + +//----------------------------------------------------------------------------- +// Set the current pose parameters. If NULL the pose parameters will be reset +// to the default values. +//----------------------------------------------------------------------------- +void CMDLPanel::SetPoseParameters( const float *pPoseParameters, int nCount ) +{ + if ( pPoseParameters ) + { + int nParameters = MIN( MAXSTUDIOPOSEPARAM, nCount ); + for ( int iParam = 0; iParam < nParameters; ++iParam ) + { + m_PoseParameters[ iParam ] = pPoseParameters[ iParam ]; + } + } + else if ( m_RootMDL.m_MDL.GetMDL() != MDLHANDLE_INVALID ) + { + CStudioHdr &studioHdr = *m_RootMDL.m_pStudioHdr; + Studio_CalcDefaultPoseParameters( &studioHdr, m_PoseParameters, MAXSTUDIOPOSEPARAM ); + } +} + + +//----------------------------------------------------------------------------- +// Set a pose parameter by name +//----------------------------------------------------------------------------- +bool CMDLPanel::SetPoseParameterByName( const char *pszName, float fValue ) +{ + if ( !m_RootMDL.m_pStudioHdr ) + return false; + CStudioHdr &studioHdr = *m_RootMDL.m_pStudioHdr; + int nPoseCount = studioHdr.GetNumPoseParameters(); + + for ( int i = 0; i < nPoseCount; ++i ) + { + const mstudioposeparamdesc_t &Pose = studioHdr.pPoseParameter( i ); + if ( V_strcasecmp( pszName, Pose.pszName() ) == 0 ) + { + float ctlValue; + Studio_SetPoseParameter( &studioHdr, i, fValue, ctlValue ); + m_PoseParameters[ i ] = ctlValue; + return true; + } + } + return false; +} + + +//----------------------------------------------------------------------------- +// Set the overlay sequence layers +//----------------------------------------------------------------------------- +void CMDLPanel::SetSequenceLayers( const MDLSquenceLayer_t *pSequenceLayers, int nCount ) +{ + if ( pSequenceLayers ) + { + m_nNumSequenceLayers = MIN( MAX_SEQUENCE_LAYERS, nCount ); + for ( int iLayer = 0; iLayer < m_nNumSequenceLayers; ++iLayer ) + { + m_SequenceLayers[ iLayer ] = pSequenceLayers[ iLayer ]; + ResetAnimationEventState( &m_SequenceLayerEventState[ iLayer ] ); + } + } + else + { + m_nNumSequenceLayers = 0; + V_memset( m_SequenceLayers, 0, sizeof( m_SequenceLayers ) ); + } +} + +//----------------------------------------------------------------------------- +// Set the current skin +//----------------------------------------------------------------------------- +void CMDLPanel::SetSkin( int nSkin ) +{ + m_RootMDL.m_MDL.m_nSkin = nSkin; +} + +//----------------------------------------------------------------------------- +// called when we're ticked... +//----------------------------------------------------------------------------- +void CMDLPanel::OnTick() +{ + BaseClass::OnTick(); + if ( m_RootMDL.m_MDL.GetMDL() != MDLHANDLE_INVALID ) + { + ValidateMDLs(); + + m_RootMDL.m_MDL.m_flTime = ( GetAutoPlayTime() - m_RootMDL.m_flCycleStartTime ); + + DoAnimationEvents(); + } +} + +void CMDLPanel::Paint() +{ + BaseClass::Paint(); + + if ( m_bThumbnailSafeZone ) + { + int iWidth, iHeight; + GetSize( iWidth, iHeight ); + + CMatRenderContextPtr pRenderContext( vgui::MaterialSystem() ); + + IMaterial *safezone = materials->FindMaterial( "vgui/thumbnails_safezone", TEXTURE_GROUP_VGUI, true ); + if ( safezone ) + { + safezone->IncrementReferenceCount(); + } + + int screenposx = 0; + int screenposy = 0; + LocalToScreen( screenposx, screenposy ); + + int iScaledHeight = THUMBNAIL_SAFE_ZONE_HEIGHT_SCALE * iHeight; + int iRemappedHeight = RemapVal( iScaledHeight, 0, THUMBNAIL_SAFE_ZONE_HEIGHT, 0, iScaledHeight ); + + pRenderContext->DrawScreenSpaceRectangle( safezone, screenposx, screenposy, iWidth, iRemappedHeight, + 0, 0, + THUMBNAIL_SAFE_ZONE_SIZE, THUMBNAIL_SAFE_ZONE_HEIGHT, + THUMBNAIL_SAFE_ZONE_SIZE, THUMBNAIL_SAFE_ZONE_SIZE ); + + screenposx = 0; + screenposy = iHeight - iRemappedHeight; + LocalToScreen( screenposx, screenposy ); + pRenderContext->DrawScreenSpaceRectangle( safezone, screenposx, screenposy, iWidth, iRemappedHeight, + 0, 0, + THUMBNAIL_SAFE_ZONE_SIZE, THUMBNAIL_SAFE_ZONE_HEIGHT, + THUMBNAIL_SAFE_ZONE_SIZE, THUMBNAIL_SAFE_ZONE_SIZE ); + + if ( safezone ) + { + safezone->DecrementReferenceCount(); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMDLPanel::DoAnimationEvents() +{ + if ( !m_RootMDL.m_pStudioHdr ) + return; + CStudioHdr &studioHdr = *m_RootMDL.m_pStudioHdr; + + // If we don't have any sequences, don't do anything + if ( studioHdr.GetNumSeq() < 1 ) + { + Assert( studioHdr.GetNumSeq() >= 1 ); + return; + } + + // we're holding onto model data that can be forced reloaded when importing workshop items + // detect the vmodel change here and force an update if so, until we fix the real issue of the studioHdr not being updated itself + if ( studioHdr.GetVirtualModel() != nullptr && studioHdr.GetVirtualModel() != studioHdr.GetRenderHdr()->GetVirtualModel() ) + { + studioHdr.ResetVModel( studioHdr.GetRenderHdr()->GetVirtualModel() ); + } + + DoAnimationEvents( &studioHdr, m_RootMDL.m_MDL.m_nSequence, m_RootMDL.m_MDL.m_flTime, false, &m_EventState ); + + for ( int i = 0; i < m_nNumSequenceLayers; ++i ) + { + float flTime = m_RootMDL.m_MDL.m_flTime - m_SequenceLayers[ i ].m_flCycleBeganAt; + //Plat_DebugString( CFmtStr("Animation: time = %f, started = %f, delta = %f\n",m_RootMDL.m_MDL.m_flTime,m_SequenceLayers[ i ].m_flCycleBeganAt,flTime ) ); + DoAnimationEvents( &studioHdr, m_SequenceLayers[ i ].m_nSequenceIndex, flTime, m_SequenceLayers[ i ].m_bNoLoop, &m_SequenceLayerEventState[ i ] ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMDLPanel::DoAnimationEvents( CStudioHdr *pStudioHdr, int nSeqNum, float flTime, bool bNoLoop, MDLAnimEventState_t *pEventState ) +{ + if ( nSeqNum < 0 || nSeqNum >= pStudioHdr->GetNumSeq() ) + { + return; + } + + mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( nSeqNum ); + if ( seqdesc.numevents == 0 ) + { + return; + } + + mstudioevent_t *pevent = seqdesc.pEvent( 0 ); + + int nFrameCount = Studio_MaxFrame( pStudioHdr, nSeqNum, m_PoseParameters ); + if ( nFrameCount == 0 ) + { + nFrameCount = 1; + } + float flEventCycle = ( flTime * m_RootMDL.m_MDL.m_flPlaybackRate ) / nFrameCount; + //Plat_DebugString( CFmtStr("Event cycle: %f, playback rate: %f, frame count: %d\n", flEventCycle, m_RootMDL.m_MDL.m_flPlaybackRate, nFrameCount ) ); + if ( bNoLoop ) + { + flEventCycle = MIN(flEventCycle, 1.0f); + } + else + { + flEventCycle -= (int)(flEventCycle); + } + + if ( pEventState->m_nEventSequence != nSeqNum ) + { + pEventState->m_nEventSequence = nSeqNum; + flEventCycle = 0.0f; + pEventState->m_flPrevEventCycle = -0.01f; // back up to get 0'th frame animations + } + + if ( flEventCycle == pEventState->m_flPrevEventCycle ) + { + return; + } + + // check for looping + BOOL bLooped = (flEventCycle < pEventState->m_flPrevEventCycle); + + // This makes sure events that occur at the end of a sequence occur are + // sent before events that occur at the beginning of a sequence. + if (bLooped) + { + for (int i = 0; i < (int)seqdesc.numevents; i++) + { + if ( pevent[i].cycle <= pEventState->m_flPrevEventCycle ) + continue; + + FireEvent( pevent[ i ].pszEventName(), pevent[ i ].pszOptions() ); + } + + // Necessary to get the next loop working + pEventState->m_flPrevEventCycle = -0.01f; + } + + for (int i = 0; i < (int)seqdesc.numevents; i++) + { + if ( (pevent[i].cycle > pEventState->m_flPrevEventCycle && pevent[i].cycle <= flEventCycle) ) + { + FireEvent( pevent[ i ].pszEventName(), pevent[ i ].pszOptions() ); + } + } + + pEventState->m_flPrevEventCycle = flEventCycle; +} + +void CMDLPanel::FireEvent( const char *pszEventName, const char *pszEventOptions ) +{ + KeyValues* pKVEvent = new KeyValues( "AnimEvent" ); + pKVEvent->SetString( "name", pszEventName ); + pKVEvent->SetString( "options", pszEventOptions ); + PostActionSignal( pKVEvent ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMDLPanel::ResetAnimationEventState( MDLAnimEventState_t *pEventState ) +{ + pEventState->m_nEventSequence = -1; + pEventState->m_flPrevEventCycle = -0.01f; +} + +//----------------------------------------------------------------------------- +// input +//----------------------------------------------------------------------------- +void CMDLPanel::OnMouseDoublePressed( vgui::MouseCode code ) +{ + if ( m_bIgnoreDoubleClick ) + return; + + float flRadius; + Vector vecCenter; + GetBoundingSphere( vecCenter, flRadius ); + LookAt( vecCenter, flRadius ); + + BaseClass::OnMouseDoublePressed( code ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMDLPanel::SetMergeMDL( MDLHandle_t handle, void *pProxyData, int nSkin /*= -1 */ ) +{ + // Verify that we have a root model to merge to. + if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID ) + return; + + int iIndex = m_aMergeMDLs.AddToTail(); + if ( !m_aMergeMDLs.IsValidIndex( iIndex ) ) + return; + + m_aMergeMDLs[iIndex].m_MDL.SetMDL( handle ); + + if ( nSkin != -1 ) + { + m_aMergeMDLs[iIndex].m_MDL.m_nSkin = nSkin; + } + + m_aMergeMDLs[iIndex].m_MDL.m_nLOD = m_RootMDL.m_MDL.m_nLOD; + + m_aMergeMDLs[iIndex].m_MDL.m_pProxyData = pProxyData; + SetIdentityMatrix( m_aMergeMDLs[iIndex].m_MDLToWorld ); + + m_aMergeMDLs[iIndex].m_bDisabled = false; + + m_aMergeMDLs[iIndex].m_pStudioHdr = new CStudioHdr( m_aMergeMDLs[iIndex].m_MDL.GetStudioHdr(), g_pMDLCache ); + + // Need to invalidate the layout so the panel will adjust is LookAt for the new model. + InvalidateLayout(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +MDLHandle_t CMDLPanel::SetMergeMDL( const char *pMDLName, void *pProxyData, int nSkin /*= -1 */ ) +{ + MDLHandle_t hMDLFindResult = vgui::MDLCache()->FindMDL( pMDLName ); + MDLHandle_t hMDL = pMDLName ? hMDLFindResult : MDLHANDLE_INVALID; + if ( vgui::MDLCache()->IsErrorModel( hMDL ) ) + { + hMDL = MDLHANDLE_INVALID; + } + + SetMergeMDL( hMDL, pProxyData, nSkin ); + + // FindMDL takes a reference and the the CMDL will also hold a reference for as long as it sticks around. Release the FindMDL reference. + int nRef = vgui::MDLCache()->Release( hMDLFindResult ); + (void)nRef; // Avoid unreferenced variable warning + AssertMsg( hMDL == MDLHANDLE_INVALID || nRef > 0, "CMDLPanel::SetMergeMDL referenced a model that has a zero ref count." ); + + return hMDL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CMDLPanel::GetMergeMDLIndex( void *pProxyData ) +{ + int nMergeCount = m_aMergeMDLs.Count(); + for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge ) + { + if ( m_aMergeMDLs[iMerge].m_MDL.m_pProxyData == pProxyData ) + return iMerge; + } + + return -1; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CMDLPanel::GetMergeMDLIndex( MDLHandle_t handle ) +{ + int nMergeCount = m_aMergeMDLs.Count(); + for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge ) + { + if ( m_aMergeMDLs[iMerge].m_MDL.GetMDL() == handle ) + return iMerge; + } + + return -1; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CMDL *CMDLPanel::GetMergeMDL( MDLHandle_t handle ) +{ + int nMergeCount = m_aMergeMDLs.Count(); + for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge ) + { + if ( m_aMergeMDLs[iMerge].m_MDL.GetMDL() == handle ) + return (&m_aMergeMDLs[iMerge].m_MDL); + } + + return NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CStudioHdr *CMDLPanel::GetMergeMDLStudioHdr( MDLHandle_t handle ) +{ + int nMergeCount = m_aMergeMDLs.Count(); + for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge ) + { + if ( m_aMergeMDLs[ iMerge ].m_MDL.GetMDL() == handle ) + return ( m_aMergeMDLs[ iMerge ].m_pStudioHdr ); + } + + return NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMDLPanel::ClearMergeMDLs( void ) +{ + const int nMergeCount = m_aMergeMDLs.Count(); + for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge ) + { + if ( !m_aMergeMDLs[iMerge].m_pStudioHdr ) + { + continue; + } + delete m_aMergeMDLs[iMerge].m_pStudioHdr; + m_aMergeMDLs[iMerge].m_pStudioHdr = NULL; + } + + m_aMergeMDLs.Purge(); +} + +void CMDLPanel::ValidateMDLs() +{ + uint32 uMdlCacheSerial = vgui::ivgui()->GetMdlCacheSerial(); + + if ( m_RootMDL.m_pStudioHdr && m_RootMDL.m_unMdlCacheSerial != uMdlCacheSerial ) + { + m_RootMDL.m_pStudioHdr = new CStudioHdr( m_RootMDL.m_MDL.GetStudioHdr(), g_pMDLCache ); + m_RootMDL.m_unMdlCacheSerial = uMdlCacheSerial; + } + + const int nMergeCount = m_aMergeMDLs.Count(); + for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge ) + { + if ( m_aMergeMDLs[iMerge].m_pStudioHdr && m_aMergeMDLs[iMerge].m_unMdlCacheSerial != uMdlCacheSerial ) + { + m_aMergeMDLs[iMerge].m_pStudioHdr = new CStudioHdr( m_aMergeMDLs[iMerge].m_MDL.GetStudioHdr(), g_pMDLCache ); + m_aMergeMDLs[iMerge].m_unMdlCacheSerial = uMdlCacheSerial; + } + } +} diff --git a/vgui2/matsys_controls/mdlpicker.cpp b/vgui2/matsys_controls/mdlpicker.cpp new file mode 100644 index 00000000..17c5b562 --- /dev/null +++ b/vgui2/matsys_controls/mdlpicker.cpp @@ -0,0 +1,1742 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "matsys_controls/mdlpicker.h" +#include "tier1/KeyValues.h" +#include "tier1/utldict.h" +#include "filesystem.h" +#include "studio.h" +#include "matsys_controls/matsyscontrols.h" +#include "matsys_controls/mdlpanel.h" +#include "vgui_controls/Splitter.h" +#include "vgui_controls/ComboBox.h" +#include "vgui_controls/Button.h" +#include "vgui_controls/PropertySheet.h" +#include "vgui_controls/MessageBox.h" +#include "vgui_controls/PropertyPage.h" +#include "vgui_controls/CheckButton.h" +#include "vgui_controls/DirectorySelectDialog.h" +#include "vgui/IVGui.h" +#include "vgui/IInput.h" +#include "vgui/ISurface.h" +#include "vgui/Cursor.h" +#include "matsys_controls/assetpicker.h" +#include "matsys_controls/colorpickerpanel.h" +#include "dmxloader/dmxloader.h" +#include "tier1/utlbuffer.h" +#include "bitmap/tgawriter.h" +#include "tier3/tier3.h" +#include "istudiorender.h" +#include "../vgui2/src/VPanel.h" +#include "tier2/p4helpers.h" +#include "ivtex.h" +#include "bitmap/tgaloader.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +using namespace vgui; + +static bool SaveTgaAndAddToP4( unsigned char *pImage, ImageFormat imageFormat, int Width, int Height, const char *szDestFilename ) +{ + + // allocate a buffer to write the tga into + int iMaxTGASize = 1024 + (Width * Height * 4); + void *pTGA = malloc( iMaxTGASize ); + CUtlBuffer buffer( pTGA, iMaxTGASize ); + + if( !TGAWriter::WriteToBuffer( pImage, buffer, Width, Height, imageFormat, IMAGE_FORMAT_BGRA8888 ) ) + { + Error( "Couldn't write bitmap data snapshot.\n" ); + return false; + } + + CP4AutoEditAddFile autop4( szDestFilename ); + + // async write to disk (this will take ownership of the memory) + char szDirName[ _MAX_PATH ]; + strcpy( szDirName, szDestFilename ); + V_StripFilename( szDirName ); + g_pFullFileSystem->CreateDirHierarchy( szDirName, "" ); + g_pFullFileSystem->AsyncWrite( szDestFilename, buffer.Base(), buffer.TellPut(), true ); + + return true; +} + +//----------------------------------------------------------------------------- +// +// MDL Picker +// +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// Sort by MDL name +//----------------------------------------------------------------------------- +static int __cdecl MDLBrowserSortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 ) +{ + const char *string1 = item1.kv->GetString("mdl"); + const char *string2 = item2.kv->GetString("mdl"); + return stricmp( string1, string2 ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CMDLPicker::CMDLPicker( vgui::Panel *pParent, int nFlags ) : + BaseClass( pParent, "MDL Files", "mdl", "models", "mdlName" ) +{ + for( int i = 0; i < MAX_SELECTED_MODELS; i++ ) + { + m_hSelectedMDL[ i ] = MDLHANDLE_INVALID; + } + + m_nFlags = nFlags; // remember what we show and what not + + m_pRenderPage = NULL; + m_pSequencesPage = NULL; + m_pActivitiesPage = NULL; + m_pSkinsPage = NULL; + m_pInfoPage = NULL; + m_pScreenCapsPage = NULL; + + m_pSequencesList = NULL; + m_pActivitiesList = NULL; + + m_hDirectorySelectDialog = NULL; + + // Horizontal splitter for mdls + m_pFileBrowserSplitter = new Splitter( this, "FileBrowserSplitter", SPLITTER_MODE_VERTICAL, 1 ); + + float flFractions[] = { 0.33f, 0.67f }; + + m_pFileBrowserSplitter->RespaceSplitters( flFractions ); + + vgui::Panel *pSplitterLeftSide = m_pFileBrowserSplitter->GetChild( 0 ); + vgui::Panel *pSplitterRightSide = m_pFileBrowserSplitter->GetChild( 1 ); + + // Standard browser controls + pSplitterLeftSide->RequestFocus(); + CreateStandardControls( pSplitterLeftSide, false ); + + // property sheet - revisions, changes, etc. + m_pPreviewSplitter = new Splitter( pSplitterRightSide, "PreviewSplitter", SPLITTER_MODE_HORIZONTAL, 1 ); + + vgui::Panel *pSplitterTopSide = m_pPreviewSplitter->GetChild( 0 ); + vgui::Panel *pSplitterBottomSide = m_pPreviewSplitter->GetChild( 1 ); + + // MDL preview + m_pMDLPreview = new CMDLPanel( pSplitterTopSide, "MDLPreview" ); + SetSkipChildDuringPainting( m_pMDLPreview ); + + m_pViewsSheet = new vgui::PropertySheet( pSplitterBottomSide, "ViewsSheet" ); + m_pViewsSheet->AddActionSignalTarget( this ); + + // now add wanted features + if ( nFlags & PAGE_RENDER ) + { + m_pRenderPage = new vgui::PropertyPage( m_pViewsSheet, "RenderPage" ); + + m_pRenderPage->AddActionSignalTarget( this ); + + m_pRenderPage->LoadControlSettingsAndUserConfig( "resource/mdlpickerrender.res" ); + + RefreshRenderSettings(); + + // ground + Button *pSelectProbe = (Button*)m_pRenderPage->FindChildByName( "ChooseLightProbe" ); + pSelectProbe->AddActionSignalTarget( this ); + } + + if ( nFlags & PAGE_SEQUENCES ) + { + m_pSequencesPage = new vgui::PropertyPage( m_pViewsSheet, "SequencesPage" ); + + m_pSequencesList = new vgui::ListPanel( m_pSequencesPage, "SequencesList" ); + m_pSequencesList->AddColumnHeader( 0, "sequence", "sequence", 52, 0 ); + m_pSequencesList->AddActionSignalTarget( this ); + m_pSequencesList->SetSelectIndividualCells( true ); + m_pSequencesList->SetEmptyListText("No .MDL file currently selected."); + m_pSequencesList->SetDragEnabled( true ); + m_pSequencesList->SetAutoResize( Panel::PIN_TOPLEFT, Panel::AUTORESIZE_DOWNANDRIGHT, 6, 6, -6, -6 ); + } + + if ( nFlags & PAGE_ACTIVITIES ) + { + m_pActivitiesPage = new vgui::PropertyPage( m_pViewsSheet, "ActivitiesPage" ); + + m_pActivitiesList = new vgui::ListPanel( m_pActivitiesPage, "ActivitiesList" ); + m_pActivitiesList->AddColumnHeader( 0, "activity", "activity", 52, 0 ); + m_pActivitiesList->AddActionSignalTarget( this ); + m_pActivitiesList->SetSelectIndividualCells( true ); + m_pActivitiesList->SetEmptyListText( "No .MDL file currently selected." ); + m_pActivitiesList->SetDragEnabled( true ); + m_pActivitiesList->SetAutoResize( Panel::PIN_TOPLEFT, Panel::AUTORESIZE_DOWNANDRIGHT, 6, 6, -6, -6 ); + } + + if ( nFlags & PAGE_SKINS ) + { + m_pSkinsPage = new vgui::PropertyPage( m_pViewsSheet, "SkinsPage" ); + + m_pSkinsList = new vgui::ListPanel( m_pSkinsPage, "SkinsList" ); + m_pSkinsList->AddColumnHeader( 0, "skin", "skin", 52, 0 ); + m_pSkinsList->AddActionSignalTarget( this ); + m_pSkinsList->SetSelectIndividualCells( true ); + m_pSkinsList->SetEmptyListText( "No .MDL file currently selected." ); + m_pSkinsList->SetDragEnabled( true ); + m_pSkinsList->SetAutoResize( Panel::PIN_TOPLEFT, Panel::AUTORESIZE_DOWNANDRIGHT, 6, 6, -6, -6 ); + } + + if ( nFlags & PAGE_INFO ) + { + m_pInfoPage = new vgui::PropertyPage( m_pViewsSheet, "InfoPage" ); + + m_pInfoPage->AddActionSignalTarget( this ); + + m_pInfoPage->LoadControlSettingsAndUserConfig( "resource/mdlpickerinfo.res" ); + + CheckButton * pTempCheck = (CheckButton *)m_pInfoPage->FindChildByName( "PhysicsObject" ); + pTempCheck->SetDisabledFgColor1( pTempCheck->GetFgColor()); + pTempCheck->SetDisabledFgColor2( pTempCheck->GetFgColor()); + pTempCheck = (CheckButton *)m_pInfoPage->FindChildByName( "StaticObject" ); + pTempCheck->SetDisabledFgColor1( pTempCheck->GetFgColor()); + pTempCheck->SetDisabledFgColor2( pTempCheck->GetFgColor()); + pTempCheck = (CheckButton *)m_pInfoPage->FindChildByName( "DynamicObject" ); + pTempCheck->SetDisabledFgColor1( pTempCheck->GetFgColor()); + pTempCheck->SetDisabledFgColor2( pTempCheck->GetFgColor()); + + m_pPropDataList = new vgui::ListPanel( m_pInfoPage, "PropData" ); + m_pPropDataList->AddColumnHeader( 0, "key", "key", 250, ListPanel::COLUMN_FIXEDSIZE ); + m_pPropDataList->AddColumnHeader( 1, "value", "value", 52, 0 ); + m_pPropDataList->AddActionSignalTarget( this ); + m_pPropDataList->SetSelectIndividualCells( false ); + m_pPropDataList->SetEmptyListText( "No prop_data available." ); + m_pPropDataList->SetDragEnabled( true ); + m_pPropDataList->SetAutoResize( Panel::PIN_TOPLEFT, Panel::AUTORESIZE_DOWNANDRIGHT, 6, 72, -6, -6 ); + + RefreshRenderSettings(); + } + + if ( nFlags & PAGE_SCREEN_CAPS ) + { + m_pScreenCapsPage = new vgui::PropertyPage( m_pViewsSheet, "ScreenCapsPage" ); + +// not sure why we have to do this for the color picker + CColorPickerButton *m_pBackgroundColor; + m_pBackgroundColor = new CColorPickerButton( m_pScreenCapsPage, "BackgroundColor", this ); + + m_pScreenCapsPage->LoadControlSettingsAndUserConfig( "resource/mdlpickerscreencaps.res" ); + + TextEntry *pTempValue; + pTempValue = ( TextEntry * )m_pScreenCapsPage->FindChildByName( "WidthText" ); + pTempValue->SetText( "256" ); + pTempValue = ( TextEntry * )m_pScreenCapsPage->FindChildByName( "HeightText" ); + pTempValue->SetText( "256" ); + +// not sure why this doesn't work +// m_pBackgroundColor = ( CColorPickerButton * )m_pScreenCapsPage->FindChildByName( "BackgroundColor" ); + m_pBackgroundColor->SetColor( 255, 0, 0, 255 ); + + Label *m_pOutputDirectory; + m_pOutputDirectory = ( Label * )m_pScreenCapsPage->FindChildByName( "OutputDirectory" ); + m_pOutputDirectory->SetText( "c:\\" ); + + Button *pSelectProbe = ( Button * )m_pScreenCapsPage->FindChildByName( "Capture" ); + pSelectProbe->AddActionSignalTarget( this ); + pSelectProbe = ( Button * )m_pScreenCapsPage->FindChildByName( "OutputDirectorySelect" ); + pSelectProbe->AddActionSignalTarget( this ); + pSelectProbe = ( Button * )m_pScreenCapsPage->FindChildByName( "SaveCaps" ); + pSelectProbe->AddActionSignalTarget( this ); + pSelectProbe = ( Button * )m_pScreenCapsPage->FindChildByName( "RestoreCaps" ); + pSelectProbe->AddActionSignalTarget( this ); + pSelectProbe = ( Button * )m_pScreenCapsPage->FindChildByName( "GenerateBackpackIcons" ); + pSelectProbe->AddActionSignalTarget( this ); + } + + // Load layout settings; has to happen before pinning occurs in code + LoadControlSettingsAndUserConfig( "resource/mdlpicker.res" ); + + // Pages must be added after control settings are set up + if ( m_pRenderPage ) + { + m_pViewsSheet->AddPage( m_pRenderPage, "Render" ); + } + if ( m_pSequencesPage ) + { + m_pViewsSheet->AddPage( m_pSequencesPage, "Sequences" ); + } + if ( m_pActivitiesPage ) + { + m_pViewsSheet->AddPage( m_pActivitiesPage, "Activities" ); + } + if ( m_pSkinsPage ) + { + m_pViewsSheet->AddPage( m_pSkinsPage, "Skins" ); + } + if ( m_pInfoPage ) + { + m_pViewsSheet->AddPage( m_pInfoPage, "Info" ); + } + if ( m_pScreenCapsPage ) + { + m_pViewsSheet->AddPage( m_pScreenCapsPage, "Screen Caps" ); + } +} + +void CMDLPicker::RefreshRenderSettings() +{ + vgui::CheckButton *pToggle; + + if ( !m_pRenderPage ) + return; + + // ground + pToggle = (vgui::CheckButton*)m_pRenderPage->FindChildByName("NoGround"); + pToggle->AddActionSignalTarget( this ); + m_pMDLPreview->SetGroundGrid( !pToggle->IsSelected() ); + + // collision + pToggle = (vgui::CheckButton*)m_pRenderPage->FindChildByName("Collision"); + pToggle->AddActionSignalTarget( this ); + m_pMDLPreview->SetCollsionModel( pToggle->IsSelected() ); + + // wireframe + pToggle = (vgui::CheckButton*)m_pRenderPage->FindChildByName("Wireframe"); + pToggle->AddActionSignalTarget( this ); + m_pMDLPreview->SetWireFrame( pToggle->IsSelected() ); + + // lockview + pToggle = (vgui::CheckButton*)m_pRenderPage->FindChildByName("LockView"); + pToggle->AddActionSignalTarget( this ); + m_pMDLPreview->SetLockView( pToggle->IsSelected() ); + + // look at camera + pToggle = (vgui::CheckButton*)m_pRenderPage->FindChildByName("LookAtCamera"); + pToggle->AddActionSignalTarget( this ); + m_pMDLPreview->SetLookAtCamera( pToggle->IsSelected() ); + + // thumbnail safe zone + pToggle = (vgui::CheckButton*)m_pRenderPage->FindChildByName("ThumbnailSafeZone"); + pToggle->AddActionSignalTarget( this ); + m_pMDLPreview->SetThumbnailSafeZone( pToggle->IsSelected() ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Destructor +//----------------------------------------------------------------------------- +CMDLPicker::~CMDLPicker() +{ +} + + +//----------------------------------------------------------------------------- +// Performs layout +//----------------------------------------------------------------------------- +void CMDLPicker::PerformLayout() +{ + // NOTE: This call should cause auto-resize to occur + // which should fix up the width of the panels + BaseClass::PerformLayout(); + + int w, h; + GetSize( w, h ); + + // Layout the mdl splitter + m_pFileBrowserSplitter->SetBounds( 0, 0, w, h ); +} + + +//----------------------------------------------------------------------------- +// Buttons on various pages +//----------------------------------------------------------------------------- +void CMDLPicker::OnAssetSelected( KeyValues *pParams ) +{ + const char *pAsset = pParams->GetString( "asset" ); + + char pProbeBuf[MAX_PATH]; + Q_snprintf( pProbeBuf, sizeof(pProbeBuf), "materials/lightprobes/%s", pAsset ); + + BeginDMXContext(); + CDmxElement *pLightProbe = NULL; + bool bOk = UnserializeDMX( pProbeBuf, "GAME", true, &pLightProbe ); + if ( !pLightProbe || !bOk ) + { + char pBuf[1024]; + Q_snprintf( pBuf, sizeof(pBuf), "Error loading lightprobe file '%s'!\n", pProbeBuf ); + vgui::MessageBox *pMessageBox = new vgui::MessageBox( "Error Loading File!\n", pBuf, GetParent() ); + pMessageBox->DoModal( ); + + EndDMXContext( true ); + return; + } + + m_pMDLPreview->SetLightProbe( pLightProbe ); + EndDMXContext( true ); +} + + +//----------------------------------------------------------------------------- +// Buttons on various pages +//----------------------------------------------------------------------------- +void CMDLPicker::OnCommand( const char *pCommand ) +{ + if ( !Q_stricmp( pCommand, "ChooseLightProbe" ) ) + { + CAssetPickerFrame *pPicker = new CAssetPickerFrame( this, "Select Light Probe (.prb) File", + "Light Probe", "prb", "materials/lightprobes", "lightprobe" ); + pPicker->DoModal(); + return; + } + else if ( !Q_stricmp( pCommand, "OutputDirectorySelect" ) ) + { + if ( !m_hDirectorySelectDialog.Get() ) + { + m_hDirectorySelectDialog = new DirectorySelectDialog( this, "Choose Screen Caps output folder" ); + } + + Label *m_pOutputDirectory; + char temp[ MAX_PATH ]; + m_pOutputDirectory = ( Label * )m_pScreenCapsPage->FindChildByName( "OutputDirectory" ); + m_pOutputDirectory->GetText( temp, sizeof( temp ) ); + + m_hDirectorySelectDialog->MakeReadyForUse(); + m_hDirectorySelectDialog->SetStartDirectory( temp ); + m_hDirectorySelectDialog->DoModal(); + return; + } + else if ( !Q_stricmp( pCommand, "Capture" ) ) + { + CaptureScreenCaps(); + return; + } + else if ( !Q_stricmp( pCommand, "GenerateBackpackIcons" ) ) + { + // shut off the ground grid + vgui::CheckButton *pGroundToggle = (vgui::CheckButton *)m_pRenderPage->FindChildByName( "NoGround" ); + bool bOriginalGridState = pGroundToggle->IsSelected(); + + vgui::CheckButton *pSafeZoneToggle = (vgui::CheckButton *)m_pRenderPage->FindChildByName( "ThumbnailSafeZone" ); + bool bOriginalSafeZoneState = pSafeZoneToggle->IsSelected(); + + m_pMDLPreview->SetGroundGrid( false ); + m_pMDLPreview->SetThumbnailSafeZone( false ); + + // make the icons + GenerateBackpackIcons(); + + // return the ground grid to its original state + m_pMDLPreview->SetGroundGrid( !bOriginalGridState ); + m_pMDLPreview->SetThumbnailSafeZone( bOriginalSafeZoneState ); + + return; + } + else if ( !Q_stricmp( pCommand, "SaveCaps" ) ) + { + SaveCaps( NULL ); + return; + } + else if ( !Q_stricmp( pCommand, "RestoreCaps" ) ) + { + if ( input()->IsKeyDown( KEY_RCONTROL ) || input()->IsKeyDown( KEY_LCONTROL ) ) + { + int nCount = m_AssetList.Count(); + for ( int i = 0; i < nCount; ++i ) + { + if ( m_pAssetBrowser->IsItemVisible( m_AssetList[ i ].m_nItemId ) && + m_pAssetBrowser->IsItemSelected( m_AssetList[ i ].m_nItemId ) ) + { + KeyValues *pItemKeyValues = m_pAssetBrowser->GetItem( m_AssetList[ i ].m_nItemId ); + const char *pSelectedAsset = pItemKeyValues->GetString( "asset" ); + + char szBathPath[ _MAX_PATH ]; + Label *m_pOutputDirectory; + + m_pOutputDirectory = ( Label * )m_pScreenCapsPage->FindChildByName( "OutputDirectory" ); + m_pOutputDirectory->GetText( szBathPath, sizeof( szBathPath ) ); + + char szPathedFileName[ _MAX_PATH ]; + V_sprintf_safe( szPathedFileName, "%sbackpack\\%s", szBathPath, pSelectedAsset ); + + Label *m_pResults = ( Label * )m_pScreenCapsPage->FindChildByName( "CaptureResults" ); + if ( RestoreCaps( szPathedFileName ) ) + { + m_pResults->SetText( "Prefs Restored" ); + } + else + { + m_pResults->SetText( "Prefs NOT FOUND" ); + } + break; + } + } + } + else + { + RestoreCaps( NULL ); + } + return; + } + + BaseClass::OnCommand( pCommand ); +} + + +//----------------------------------------------------------------------------- +// Handles the directory selection for screen caps +//----------------------------------------------------------------------------- +void CMDLPicker::OnDirectorySelected( char const *dir ) +{ + if ( m_hDirectorySelectDialog != 0 ) + { + m_hDirectorySelectDialog->MarkForDeletion(); + } + + Label *m_pOutputDirectory; + m_pOutputDirectory = ( Label * )m_pScreenCapsPage->FindChildByName( "OutputDirectory" ); + m_pOutputDirectory->SetText( dir ); +} + + +//----------------------------------------------------------------------------- +// Screen captures the specific model and writes out a .tga. Assumes the MDLPreview +// panel has been properly adjusted to 0,0 in screen space and that width / height +// have been set. +//----------------------------------------------------------------------------- +const char *CMDLPicker::CaptureModel( int nModIndex, const char *AssetName, const char *OutputPath, int Width, int Height, Color BackgroundColor, bool bSelectedOnly ) +{ + char pBuf[ MAX_PATH ]; + Q_snprintf( pBuf, sizeof( pBuf ), "%s\\%s\\%s", GetModPath( nModIndex ), m_pAssetSubDir, AssetName ); + Q_FixSlashes( pBuf ); + + if ( !bSelectedOnly ) + { + SelectMDL( pBuf, false, -1 ); + } + + CMatRenderContextPtr pRenderContext( materials ); + + g_pMaterialSystem->BeginFrame( 0 ); + g_pStudioRender->BeginFrame(); + +// pRenderContext->ClearColor4ub( 0, 0, 0, 0 ); +// pRenderContext->ClearBuffers( true, true ); + + Color NewPanelColor; + + NewPanelColor.SetColor( 0, 0, 0, 0 ); + m_pMDLPreview->SetBackgroundColor( NewPanelColor ); + + g_pVGuiSurface->PaintTraverseEx( m_pMDLPreview->GetVPanel(), false ); + + g_pStudioRender->EndFrame(); + g_pMaterialSystem->EndFrame( ); + + // get the data from the backbuffer and save to disk + // bitmap bits + unsigned char *pImageBlack = ( unsigned char * )malloc( Width * 4 * Height ); + + // Get Bits from the material system + pRenderContext->ReadPixels( 0, 0, Width, Height, pImageBlack, IMAGE_FORMAT_BGRA8888 ); + + + g_pMaterialSystem->BeginFrame( 0 ); + g_pStudioRender->BeginFrame(); + +// pRenderContext->ClearColor4ub( 255, 255, 255, 0 ); +// pRenderContext->ClearBuffers( true, true ); + + NewPanelColor.SetColor( 255, 255, 255, 0 ); + m_pMDLPreview->SetBackgroundColor( NewPanelColor ); + + g_pVGuiSurface->PaintTraverseEx( m_pMDLPreview->GetVPanel(), false ); + + g_pStudioRender->EndFrame(); + g_pMaterialSystem->EndFrame( ); + + // get the data from the backbuffer and save to disk + // bitmap bits + unsigned char *pImageWhite = ( unsigned char * )malloc( Width * 4 * Height ); + + // Get Bits from the material system + pRenderContext->ReadPixels( 0, 0, Width, Height, pImageWhite, IMAGE_FORMAT_BGRA8888 ); + + unsigned char *pBlackPos = pImageBlack; + unsigned char *pWhitePos = pImageWhite; + for( int y = 0; y < Height; y++ ) + { + for( int x = 0; x < Width; x++, pBlackPos += 4, pWhitePos += 4 ) + { + if ( ( *( pBlackPos + 0 ) ) != ( *( pWhitePos + 0 ) ) || // blue + ( *( pBlackPos + 1 ) ) != ( *( pWhitePos + 1 ) ) || // green + ( *( pBlackPos + 2 ) ) != ( *( pWhitePos + 2 ) ) ) // red + { + unsigned char nBlueDiff = ( *( pBlackPos + 0 ) ); + unsigned char nGreenDiff = ( *( pBlackPos + 1 ) ); + unsigned char nRedDiff = ( *( pBlackPos + 2 ) ); + + unsigned char nMax = nBlueDiff; + if ( nGreenDiff > nMax ) + { + nMax = nGreenDiff; + } + if ( nRedDiff > nMax ) + { + nMax = nRedDiff; + } + + *( pBlackPos + 3 ) = nMax; + } + else + { + *( pBlackPos + 3 ) = 0xff; + } + } + } + + static char szPathedFileName[ _MAX_PATH ]; + V_sprintf_safe( szPathedFileName, "%s%s", OutputPath, AssetName ); + V_SetExtension( szPathedFileName, ".tga", sizeof( szPathedFileName ) ); + + bool bResult = SaveTgaAndAddToP4( pImageBlack, IMAGE_FORMAT_BGRA8888, Width, Height, szPathedFileName ); + + free( pImageBlack ); + free( pImageWhite ); + + if ( !bResult) return NULL; + + if ( bSelectedOnly ) + { + SaveCaps( szPathedFileName ); + } + + return szPathedFileName; +} + + +//----------------------------------------------------------------------------- +// Will go through the asset browser and capture each visible item. +//----------------------------------------------------------------------------- +void CMDLPicker::CaptureScreenCaps( void ) +{ + char temp[ 256 ]; + TextEntry *pTempValue; + int width; + int height; + char szBathPath[ _MAX_PATH ]; + Label *m_pOutputDirectory; + + m_pOutputDirectory = ( Label * )m_pScreenCapsPage->FindChildByName( "OutputDirectory" ); + m_pOutputDirectory->GetText( szBathPath, sizeof( szBathPath ) ); + + pTempValue = ( TextEntry * )m_pScreenCapsPage->FindChildByName( "WidthText" ); + pTempValue->GetText( temp, sizeof( temp ) ); + width = atoi( temp ); + pTempValue = ( TextEntry * )m_pScreenCapsPage->FindChildByName( "HeightText" ); + pTempValue->GetText( temp, sizeof( temp ) ); + height = atoi( temp ); + + int PanelX, PanelY, PanelWidth, PanelHeight; + Color PanelColor; + + Panel *pParent = m_pMDLPreview->GetParent(); + m_pMDLPreview->GetPos( PanelX, PanelY ); + m_pMDLPreview->GetSize( PanelWidth, PanelHeight ); + PanelColor = m_pMDLPreview->GetBackgroundColor(); + + m_pMDLPreview->SetParent( ( vgui::Panel * )NULL ); + m_pMDLPreview->SetPos( 0, 0 ); + m_pMDLPreview->SetSize( width, height ); + + CColorPickerButton *m_pBackgroundColor; + m_pBackgroundColor = ( CColorPickerButton * )m_pScreenCapsPage->FindChildByName( "BackgroundColor" ); + + Color NewPanelColor = m_pBackgroundColor->GetColor(); + NewPanelColor[3] = 0; + m_pMDLPreview->SetBackgroundColor( NewPanelColor ); + ((VPanel *)m_pMDLPreview->GetVPanel())->Solve(); + + bool bSelectedOnly = false; + if ( input()->IsKeyDown( KEY_RCONTROL ) || input()->IsKeyDown( KEY_LCONTROL ) ) + { + bSelectedOnly = true; + } + + int nCount = m_AssetList.Count(); + int nNumItems = 0; + for ( int i = 0; i < nCount; ++i ) + { + if ( m_pAssetBrowser->IsItemVisible( m_AssetList[ i ].m_nItemId ) && + ( !bSelectedOnly || m_pAssetBrowser->IsItemSelected( m_AssetList[ i ].m_nItemId ) ) ) + { + KeyValues *pItemKeyValues = m_pAssetBrowser->GetItem( m_AssetList[ i ].m_nItemId ); + const char *pSelectedAsset = pItemKeyValues->GetString( "asset" ); + int nModIndex = pItemKeyValues->GetInt( "modIndex" ); + + CaptureModel( nModIndex, pSelectedAsset, szBathPath, width, height, NewPanelColor, bSelectedOnly ); + nNumItems++; + } + } + + m_pMDLPreview->SetParent( pParent ); + m_pMDLPreview->SetPos( PanelX, PanelY ); + m_pMDLPreview->SetSize( PanelWidth, PanelHeight ); + m_pMDLPreview->SetBackgroundColor( PanelColor ); + ((VPanel *)m_pMDLPreview->GetVPanel())->Solve(); + + Label *m_pResults; + + V_sprintf_safe( temp, "Captured %d items", nNumItems ); + m_pResults = ( Label * )m_pScreenCapsPage->FindChildByName( "CaptureResults" ); + m_pResults->SetText( temp ); +} + + +//----------------------------------------------------------------------------- +// Stub for XBox360 compiles +//----------------------------------------------------------------------------- +#if defined( _X360 ) +const char *getenv( const char *varname ) +{ + return NULL; +} +#endif + + +//----------------------------------------------------------------------------- +// Writes two very simple .vmt file, one for the passed in asset, +// and the other for _large. +//----------------------------------------------------------------------------- +void CMDLPicker::WriteBackbackVMTFiles( const char *pAssetName ) +{ + const char *pVProject = getenv( "VPROJECT" ); + if ( !pVProject ) + return; + + char pStrippedAssetName[ MAX_PATH ]; + V_StripExtension( pAssetName, pStrippedAssetName, sizeof( pStrippedAssetName ) ); + V_strcat_safe( pStrippedAssetName, GetOutputFileSuffix().Get() ); + + char pVMTFilename[ MAX_PATH ]; + Q_snprintf( pVMTFilename, sizeof( pVMTFilename ), "%s\\materials\\backpack\\%s.vmt", pVProject, pStrippedAssetName ); + Q_FixSlashes( pVMTFilename ); + + char pBaseTextureName[ MAX_PATH ]; + Q_snprintf( pBaseTextureName, sizeof( pBaseTextureName ), "backpack\\%s", pStrippedAssetName ); + Q_FixSlashes( pBaseTextureName ); + + { + CP4AutoEditAddFile autop4( pVMTFilename ); + FileHandle_t fileHandle = g_pFullFileSystem->Open( pVMTFilename, "w" ); + if ( fileHandle ) + { + + g_pFullFileSystem->FPrintf( fileHandle, "\"UnlitGeneric\"\n" ); + g_pFullFileSystem->FPrintf( fileHandle, "{\n" ); + g_pFullFileSystem->FPrintf( fileHandle, " \"$baseTexture\" \"%s\"\n", pBaseTextureName ); + g_pFullFileSystem->FPrintf( fileHandle, " $translucent 1\n" ); + g_pFullFileSystem->FPrintf( fileHandle, " $vertexcolor 1\n" ); + g_pFullFileSystem->FPrintf( fileHandle, "}\n" ); + + g_pFullFileSystem->Close( fileHandle ); + } + } + + // now write the _large version + Q_snprintf( pVMTFilename, sizeof( pVMTFilename ), "%s\\materials\\backpack\\%s_large", pVProject, pStrippedAssetName ); + V_SetExtension( pVMTFilename, ".vmt", sizeof( pVMTFilename ) ); + Q_FixSlashes( pVMTFilename ); + + Q_snprintf( pBaseTextureName, sizeof( pBaseTextureName ), "backpack\\%s_large", pStrippedAssetName ); + Q_FixSlashes( pBaseTextureName ); + + { + CP4AutoEditAddFile autop4( pVMTFilename ); + FileHandle_t fileHandle = g_pFullFileSystem->Open( pVMTFilename, "w" ); + if ( fileHandle ) + { + g_pFullFileSystem->FPrintf( fileHandle, "\"UnlitGeneric\"\n" ); + g_pFullFileSystem->FPrintf( fileHandle, "{\n" ); + g_pFullFileSystem->FPrintf( fileHandle, " \"$baseTexture\" \"%s\"\n", pBaseTextureName ); + g_pFullFileSystem->FPrintf( fileHandle, " $translucent 1\n" ); + g_pFullFileSystem->FPrintf( fileHandle, "}\n" ); + + g_pFullFileSystem->Close( fileHandle ); + } + } +} + + +//----------------------------------------------------------------------------- +void *VTexFilesystemFactory( const char *pName, int *pReturnCode ) +{ + return g_pFullFileSystem; +} + + +void* MdlPickerFSFactory( const char *pName, int *pReturnCode ) +{ + if ( IsX360() ) + return NULL; + + if ( Q_stricmp( pName, FILESYSTEM_INTERFACE_VERSION ) == 0 ) + return g_pFullFileSystem; + + return NULL; +} + + +//----------------------------------------------------------------------------- +// Creates the two required icons for the TF2 store/backpack system +//----------------------------------------------------------------------------- +void CMDLPicker::GenerateBackpackIcons( void ) +{ + if ( !g_pVTex ) + return; + + int width; + int height; + + // find the index of the item we are currently viewing + int selectedItemIndex; + for ( selectedItemIndex = 0; selectedItemIndex < m_AssetList.Count(); ++selectedItemIndex ) + { + if ( m_pAssetBrowser->IsItemVisible( m_AssetList[ selectedItemIndex ].m_nItemId ) && + m_pAssetBrowser->IsItemSelected( m_AssetList[ selectedItemIndex ].m_nItemId ) ) + { + break; + } + } + + if ( selectedItemIndex >= m_AssetList.Count() ) + return; + + // + // Fetch and check environment variables + // + const char *pVContent = getenv( "VCONTENT" ); + if ( !pVContent ) + { + Error( "VCONTENT environment variable not set" ); + return; + } + + const char *pVMod = getenv( "VMOD" ); + if ( !pVMod ) + { + Error( "VMOD environment variable not set" ); + return; + } + + const char *pVProject = getenv( "VPROJECT" ); + if ( !pVProject ) + { + Error( "VPROJECT environment variable not set" ); + return; + } + + // extract the filename of the model + KeyValues *pItemKeyValues = m_pAssetBrowser->GetItem( m_AssetList[ selectedItemIndex ].m_nItemId ); + const char *pSelectedAsset = pItemKeyValues->GetString( "asset" ); + + // set the P4 changelist label to refer to this set of icons + char pChangelistLabel[ MAX_PATH ]; + V_strcpy_safe( pChangelistLabel, pSelectedAsset ); + V_FileBase( pChangelistLabel, pChangelistLabel, sizeof( pChangelistLabel ) ); + V_strcat_safe( pChangelistLabel, " Auto Checkout", sizeof( pChangelistLabel ) ); + g_p4factory->SetOpenFileChangeList( pChangelistLabel ); + + // generate .VMT files for normal and _large icons + WriteBackbackVMTFiles( pSelectedAsset ); + + // store original state of model preview panel + int PanelX, PanelY, PanelWidth, PanelHeight; + Color PanelColor; + + Panel *pParent = m_pMDLPreview->GetParent(); + m_pMDLPreview->GetPos( PanelX, PanelY ); + m_pMDLPreview->GetSize( PanelWidth, PanelHeight ); + PanelColor = m_pMDLPreview->GetBackgroundColor(); + + // slam preview panel to desired TGA size for large icon, and write it out + width = 512; + height = 512; + m_pMDLPreview->SetParent( ( vgui::Panel * )NULL ); + m_pMDLPreview->SetPos( 0, 0 ); + m_pMDLPreview->SetSize( width, height ); + + CColorPickerButton *m_pBackgroundColor; + m_pBackgroundColor = ( CColorPickerButton * )m_pScreenCapsPage->FindChildByName( "BackgroundColor" ); + + Color NewPanelColor = m_pBackgroundColor->GetColor(); + NewPanelColor[3] = 0; + m_pMDLPreview->SetBackgroundColor( NewPanelColor ); + ((VPanel *)m_pMDLPreview->GetVPanel())->Solve(); + + char pLargeAssetName[ MAX_PATH ]; + V_strcpy_safe( pLargeAssetName, pSelectedAsset ); + V_StripExtension( pLargeAssetName, pLargeAssetName, ARRAYSIZE( pLargeAssetName ) ); + + CUtlString strExtention = GetOutputFileSuffix(); + strExtention += "_large.mdl"; + + V_strcat_safe( pLargeAssetName, strExtention.String() ); + + char pOutputPath[ MAX_PATH ]; + Q_snprintf( pOutputPath, sizeof( pOutputPath ), "%s\\%s\\materialsrc\\backpack\\", pVContent, pVMod ); + Q_FixSlashes( pOutputPath ); + + int nModIndex = pItemKeyValues->GetInt( "modIndex" ); + const char *pLargeTGAName = CaptureModel( nModIndex, pLargeAssetName, pOutputPath, width, height, NewPanelColor, true ); + if ( !pLargeTGAName ) + return; + + // write corresponding .txt file with vtex options + char pVTexOptionsFileName[ MAX_PATH ]; + V_strcpy_safe( pVTexOptionsFileName, pLargeTGAName ); + V_SetExtension( pVTexOptionsFileName, ".txt", sizeof( pVTexOptionsFileName ) ); + + { + CP4AutoEditAddFile autop4( pVTexOptionsFileName ); + FileHandle_t hVTexOptionsFile = g_pFullFileSystem->Open( pVTexOptionsFileName, "w" ); + if ( hVTexOptionsFile ) + { + g_pFullFileSystem->FPrintf( hVTexOptionsFile, "nomip 1\n" ); + g_pFullFileSystem->FPrintf( hVTexOptionsFile, "nolod 1\n" ); + g_pFullFileSystem->Close( hVTexOptionsFile ); + } + } + + // !KLUDGE! Everybody I've talked to says that vtex is *supposed* to + // use VPROJECT. But it doesn't. I don't think I can safely change vtex + // without breaking tons of stuff. So just force the output directory. + // Determine the proper output directory based on VPROJECT + char pOutputPathGame[ MAX_PATH ]; + Q_strncpy( pOutputPathGame, pVProject, sizeof( pOutputPathGame ) ); + Q_StripTrailingSlash( pOutputPathGame ); + Q_strncat( pOutputPathGame, "/materials/", sizeof( pOutputPathGame ) ); + const char *pBackpack = Q_stristr( pLargeTGAName, "backpack" ); + if ( pBackpack ) + { + Q_strncat( pOutputPathGame, pBackpack, sizeof( pOutputPathGame ) ); + Q_StripFilename( pOutputPathGame ); + } + Q_FixSlashes( pOutputPathGame ); + + // run vtex on the TGA and .txt file to create .VTF and add it to our Perforce changelist + char *vTexArgv[64]; + int vTexArgc = 0; + vTexArgv[ vTexArgc++ ] = ""; + vTexArgv[ vTexArgc++ ] = "-quiet"; + vTexArgv[ vTexArgc++ ] = "-UseStandardError"; + vTexArgv[ vTexArgc++ ] = "-WarningsAsErrors"; + vTexArgv[ vTexArgc++ ] = "-p4skip"; + vTexArgv[ vTexArgc++ ] = "-outdir"; + vTexArgv[ vTexArgc++ ] = pOutputPathGame; + vTexArgv[ vTexArgc++ ] = (char *)pLargeTGAName; + + g_pVTex->VTex( MdlPickerFSFactory, pOutputPathGame, vTexArgc, vTexArgv ); + + // Generale small TGA name, by removing the "large" part + char pSmallTGAName[ MAX_PATH ]; + strcpy( pSmallTGAName, pLargeTGAName ); + char *_large = Q_stristr( pSmallTGAName, "_large"); + Assert(_large); + strcpy(_large, _large+6); + + // Load up the large icon + int nCheckWidth, nCheckHeight; + ImageFormat largeFmt; + float gamma; + CUtlBuffer largeTGAFileData; + CUtlMemory largeTGAImageData; + + if ( !g_pFullFileSystem->ReadFile( pLargeTGAName, NULL, largeTGAFileData ) + || !TGALoader::GetInfo( largeTGAFileData, &nCheckWidth, &nCheckHeight, &largeFmt, &gamma ) + || nCheckWidth != width || nCheckHeight != height ) + { + Error( "Failed to reload image header %s", pLargeTGAName ); + Assert( false ); + return; + } + + largeTGAFileData.SeekGet( CUtlBuffer::SEEK_HEAD, 0 ); + if ( !TGALoader::LoadRGBA8888( largeTGAFileData, largeTGAImageData, nCheckWidth, nCheckHeight ) + || nCheckWidth != width || nCheckHeight != height ) + { + Error( "Failed to reload image data %s", pLargeTGAName ); + Assert( false ); + return; + } + + // + // Perform a downsample. This is better than just re-rendering at the smaller size, + // which essentially just point-samples the image. + // + CUtlMemory smallTGAImageData; + const int kSmallSize = 128; + smallTGAImageData.EnsureCapacity(kSmallSize*kSmallSize*4); + ImageLoader::ResampleInfo_t resampleInfo; + resampleInfo.m_nSrcWidth = width; + resampleInfo.m_nSrcHeight = height; + resampleInfo.m_flSrcGamma = gamma; + resampleInfo.m_pSrc = (unsigned char *)largeTGAImageData.Base(); + + resampleInfo.m_nDestWidth = kSmallSize; + resampleInfo.m_nDestHeight = kSmallSize; + resampleInfo.m_flDestGamma = gamma; + resampleInfo.m_pDest = (unsigned char *)smallTGAImageData.Base(); + + resampleInfo.m_nFlags = ImageLoader::RESAMPLE_CLAMPS | ImageLoader::RESAMPLE_CLAMPT; + //resampleInfo.m_nFlags |= ImageLoader::RESAMPLE_NICE_FILTER; // Turn this off. It has some sort of edge enhancement or something. Causes edges to ring. + + if ( !ImageLoader::ResampleRGBA8888( resampleInfo ) ) + { + Error( "Failed to resample %s", pLargeTGAName ); + Assert( false ); + return; + } + + // Save it + if ( !SaveTgaAndAddToP4( resampleInfo.m_pDest, IMAGE_FORMAT_RGBA8888, resampleInfo.m_nDestWidth, resampleInfo.m_nDestHeight, pSmallTGAName ) ) + { + return; + } + + // Save the .cfg file. + SaveCaps( pSmallTGAName ); + + // write corresponding .txt file with vtex options + V_strcpy_safe( pVTexOptionsFileName, pSmallTGAName ); + V_SetExtension( pVTexOptionsFileName, ".txt", sizeof( pVTexOptionsFileName ) ); + + { + CP4AutoEditAddFile autop4( pVTexOptionsFileName ); + FileHandle_t hVTexOptionsFile = g_pFullFileSystem->Open( pVTexOptionsFileName, "w" ); + if ( hVTexOptionsFile ) + { + g_pFullFileSystem->FPrintf( hVTexOptionsFile, "nomip 1\n" ); + g_pFullFileSystem->FPrintf( hVTexOptionsFile, "nolod 1\n" ); + g_pFullFileSystem->Close( hVTexOptionsFile ); + } + } + + // run vtex on the TGA and .txt file to create .VTF and add it to our Perforce changelist + vTexArgc = 0; + vTexArgv[ vTexArgc++ ] = ""; + vTexArgv[ vTexArgc++ ] = "-quiet"; + vTexArgv[ vTexArgc++ ] = "-UseStandardError"; + vTexArgv[ vTexArgc++ ] = "-WarningsAsErrors"; + vTexArgv[ vTexArgc++ ] = "-p4skip"; + vTexArgv[ vTexArgc++ ] = "-outdir"; + vTexArgv[ vTexArgc++ ] = pOutputPathGame; + vTexArgv[ vTexArgc++ ] = (char *)pSmallTGAName; + g_pVTex->VTex( MdlPickerFSFactory, pOutputPathGame, vTexArgc, vTexArgv ); + + + // restore the preview panel to its original state + m_pMDLPreview->SetParent( pParent ); + m_pMDLPreview->SetPos( PanelX, PanelY ); + m_pMDLPreview->SetSize( PanelWidth, PanelHeight ); + m_pMDLPreview->SetBackgroundColor( PanelColor ); + ((VPanel *)m_pMDLPreview->GetVPanel())->Solve(); +} + + +CUtlString CMDLPicker::GetOutputFileSuffix() +{ + char temp[256]; + TextEntry *pTempValue = ( TextEntry * )m_pScreenCapsPage->FindChildByName( "SuffixText" ); + if ( pTempValue ) + { + pTempValue->GetText( temp, sizeof( temp ) ); + } + return temp; +} + + +//----------------------------------------------------------------------------- +// Saves the screen cap information and camera position +//----------------------------------------------------------------------------- +void CMDLPicker::SaveCaps( const char *szFileName ) +{ + char temp[ _MAX_PATH ]; + + KeyValues *CaptureData = new KeyValues( "ScreenCaps" ); + + Vector vecPos; + QAngle angDir; + m_pMDLPreview->GetCameraPositionAndAngles( vecPos, angDir ); + V_sprintf_safe( temp, "%g %g %g", vecPos.x, vecPos.y, vecPos.z ); + CaptureData->SetString( "CameraPosition", temp ); + V_sprintf_safe( temp, "%g %g %g", angDir.x, angDir.y, angDir.z ); + CaptureData->SetString( "CameraAngles", temp ); + + Vector vecOffset; + m_pMDLPreview->GetCameraOffset( vecOffset ); + V_sprintf_safe( temp, "%g %g %g", vecOffset.x, vecOffset.y, vecOffset.z ); + CaptureData->SetString( "CameraOffset", temp ); + + CColorPickerButton *m_pBackgroundColor; + m_pBackgroundColor = ( CColorPickerButton * )m_pScreenCapsPage->FindChildByName( "BackgroundColor" ); + Color color = m_pBackgroundColor->GetColor(); + + V_sprintf_safe( temp, "%d %d %d %d", color.r(), color.g(), color.b(), color.a() ); + CaptureData->SetString( "BackgroundColor", temp ); + + TextEntry *pTempValue; + pTempValue = ( TextEntry * )m_pScreenCapsPage->FindChildByName( "WidthText" ); + pTempValue->GetText( temp, sizeof( temp ) ); + CaptureData->SetString( "Width", temp ); + + pTempValue = ( TextEntry * )m_pScreenCapsPage->FindChildByName( "HeightText" ); + pTempValue->GetText( temp, sizeof( temp ) ); + CaptureData->SetString( "Height", temp ); + + vgui::CheckButton *pToggle; + pToggle = (vgui::CheckButton*)m_pRenderPage->FindChildByName( "NoGround" ); + CaptureData->SetInt( "NoGround", pToggle->IsSelected() ? 1 : 0 ); + + pToggle = (vgui::CheckButton*)m_pRenderPage->FindChildByName( "Collision" ); + CaptureData->SetInt( "Collision", pToggle->IsSelected() ? 1 : 0 ); + + pToggle = (vgui::CheckButton*)m_pRenderPage->FindChildByName( "Wireframe" ); + CaptureData->SetInt( "Wifeframe", pToggle->IsSelected() ? 1 : 0 ); + + pToggle = (vgui::CheckButton*)m_pRenderPage->FindChildByName( "LockView" ); + CaptureData->SetInt( "LockView", pToggle->IsSelected() ? 1 : 0 ); + + pToggle = (vgui::CheckButton*)m_pRenderPage->FindChildByName( "LookAtCamera" ); + CaptureData->SetInt( "LookAtCamera", pToggle->IsSelected() ? 1 : 0 ); + + for( int i = 1; i < MAX_SELECTED_MODELS; i++ ) + { + if ( m_hSelectedMDL[ i ] != MDLHANDLE_INVALID ) + { + const char *MergedModelName = vgui::MDLCache()->GetModelName( m_hSelectedMDL[ i ] ); + V_sprintf_safe( temp, "Merged_%d", i ); + CaptureData->SetString( temp, MergedModelName ); + } + } + + if ( szFileName != NULL ) + { + strcpy( temp, szFileName ); + V_SetExtension( temp, ".cfg", sizeof( temp ) ); + } + else + { + Label *m_pOutputDirectory = ( Label * )m_pScreenCapsPage->FindChildByName( "OutputDirectory" ); + m_pOutputDirectory->GetText( temp, sizeof( temp ) ); + + strcat( temp, "ScreenCaps.cfg" ); + } + + CaptureData->SaveToFile( g_pFullFileSystem, temp ); + CP4AutoAddFile autop4( temp ); +} + + +//----------------------------------------------------------------------------- +// Restores the screen cap information and camera position +//----------------------------------------------------------------------------- +bool CMDLPicker::RestoreCaps( const char *szFileName ) +{ + char temp[ _MAX_PATH ]; + + if ( szFileName != NULL ) + { + strcpy( temp, szFileName ); + V_SetExtension( temp, ".cfg", sizeof( temp ) ); + } + else + { + Label *m_pOutputDirectory = ( Label * )m_pScreenCapsPage->FindChildByName( "OutputDirectory" ); + m_pOutputDirectory->GetText( temp, sizeof( temp ) ); + strcat( temp, "ScreenCaps.cfg" ); + } + + KeyValues *CaptureData = new KeyValues( "ScreenCaps" ); + + if ( !CaptureData->LoadFromFile( g_pFullFileSystem, temp ) ) + { + return false; + } + + Vector vecPos; + QAngle angDir; + Vector vecOffset; + sscanf( CaptureData->GetString( "CameraPosition" ), "%g %g %g", &vecPos.x, &vecPos.y, &vecPos.z ); + sscanf( CaptureData->GetString( "CameraAngles" ), "%g %g %g", &angDir.x, &angDir.y, &angDir.z ); + sscanf( CaptureData->GetString( "CameraOffset" ), "%g %g %g", &vecOffset.x, &vecOffset.y, &vecOffset.z ); + + m_pMDLPreview->SetCameraOffset( vecOffset ); + m_pMDLPreview->SetCameraPositionAndAngles( vecPos, angDir ); + + CColorPickerButton *m_pBackgroundColor; + int r, g, b, a; + m_pBackgroundColor = ( CColorPickerButton * )m_pScreenCapsPage->FindChildByName( "BackgroundColor" ); + sscanf( CaptureData->GetString( "BackgroundColor" ), "%d %d %d %d", &r, &g, &b, &a ); + m_pBackgroundColor->SetColor( r, g, b, a ); + + TextEntry *pTempValue; + pTempValue = ( TextEntry * )m_pScreenCapsPage->FindChildByName( "WidthText" ); + pTempValue->SetText( CaptureData->GetString( "Width" ) ); + + pTempValue = ( TextEntry * )m_pScreenCapsPage->FindChildByName( "HeightText" ); + pTempValue->SetText( CaptureData->GetString( "Height" ) ); + + + vgui::CheckButton *pToggle; + pToggle = (vgui::CheckButton*)m_pRenderPage->FindChildByName( "NoGround" ); + pToggle->SetSelected( ( CaptureData->GetInt( "NoGround" ) == 1 ) ); + + pToggle = (vgui::CheckButton*)m_pRenderPage->FindChildByName( "Collision" ); + pToggle->SetSelected( ( CaptureData->GetInt( "Collision" ) == 1 ) ); + + pToggle = (vgui::CheckButton*)m_pRenderPage->FindChildByName( "Wireframe" ); + pToggle->SetSelected( ( CaptureData->GetInt( "Wireframe" ) == 1 ) ); + + pToggle = (vgui::CheckButton*)m_pRenderPage->FindChildByName( "LockView" ); + pToggle->SetSelected( ( CaptureData->GetInt( "LockView" ) == 1 ) ); + + pToggle = (vgui::CheckButton*)m_pRenderPage->FindChildByName( "LookAtCamera" ); + pToggle->SetSelected( ( CaptureData->GetInt( "LookAtCamera" ) == 1 ) ); + + for( int i = 1; i < MAX_SELECTED_MODELS; i++ ) + { + V_sprintf_safe( temp, "Merged_%d", i ); + const char *MergedModelName = CaptureData->GetString( temp, NULL ); + if ( MergedModelName ) + { + SelectMDL( MergedModelName, false, i ); + } + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: rebuilds the list of activities +//----------------------------------------------------------------------------- +void CMDLPicker::RefreshActivitiesAndSequencesList() +{ + m_pActivitiesList->RemoveAll(); + m_pSequencesList->RemoveAll(); + m_pMDLPreview->SetSequence( 0 ); + + if ( m_hSelectedMDL[ 0 ] == MDLHANDLE_INVALID ) + { + m_pActivitiesList->SetEmptyListText("No .MDL file currently selected"); + m_pSequencesList->SetEmptyListText("No .MDL file currently selected"); + return; + } + + m_pActivitiesList->SetEmptyListText(".MDL file contains no activities"); + m_pSequencesList->SetEmptyListText(".MDL file contains no sequences"); + + studiohdr_t *hdr = vgui::MDLCache()->GetStudioHdr( m_hSelectedMDL[ 0 ] ); + + CUtlDict activityNames( true, 0, hdr->GetNumSeq() ); + + for (int j = 0; j < hdr->GetNumSeq(); j++) + { + if ( /*g_viewerSettings.showHidden ||*/ !(hdr->pSeqdesc(j).flags & STUDIO_HIDDEN)) + { + const char *pActivityName = hdr->pSeqdesc(j).pszActivityName(); + if ( pActivityName && pActivityName[0] ) + { + // Multiple sequences can have the same activity name; only add unique activity names + if ( activityNames.Find( pActivityName ) == activityNames.InvalidIndex() ) + { + KeyValues *pkv = new KeyValues("node", "activity", pActivityName ); + int nItemID = m_pActivitiesList->AddItem( pkv, 0, false, false ); + + KeyValues *pDrag = new KeyValues( "drag", "text", pActivityName ); + pDrag->SetString( "texttype", "activityName" ); + pDrag->SetString( "mdl", vgui::MDLCache()->GetModelName( m_hSelectedMDL[ 0 ] ) ); + m_pActivitiesList->SetItemDragData( nItemID, pDrag ); + + activityNames.Insert( pActivityName, j ); + } + } + + const char *pSequenceName = hdr->pSeqdesc(j).pszLabel(); + if ( pSequenceName && pSequenceName[0] ) + { + KeyValues *pkv = new KeyValues("node", "sequence", pSequenceName); + int nItemID = m_pSequencesList->AddItem( pkv, 0, false, false ); + + KeyValues *pDrag = new KeyValues( "drag", "text", pSequenceName ); + pDrag->SetString( "texttype", "sequenceName" ); + pDrag->SetString( "mdl", vgui::MDLCache()->GetModelName( m_hSelectedMDL[ 0 ] ) ); + m_pSequencesList->SetItemDragData( nItemID, pDrag ); + } + } + } +} + +//----------------------------------------------------------------------------- +// A MDL was selected +//----------------------------------------------------------------------------- +void CMDLPicker::OnSelectedAssetPicked( const char *pMDLName ) +{ + char pRelativePath[MAX_PATH]; + + int nSelectSecondary = -1; + if ( input()->IsKeyDown( KEY_RCONTROL ) || input()->IsKeyDown( KEY_LCONTROL ) ) + { + nSelectSecondary = 0; + } + else if ( input()->IsMouseDown(MOUSE_RIGHT) ) + { + nSelectSecondary = 1; + } + + if ( pMDLName ) + { + Q_snprintf( pRelativePath, sizeof(pRelativePath), "models\\%s", pMDLName ); + SelectMDL( pRelativePath, true, nSelectSecondary ); + } + else + { + SelectMDL( NULL, true, nSelectSecondary ); + } +} + + +//----------------------------------------------------------------------------- +// Allows external apps to select a MDL +//----------------------------------------------------------------------------- +void CMDLPicker::SelectMDL( const char *pRelativePath, bool bDoLookAt, int nSelectSecondary ) +{ + MDLHandle_t hSelectedMDL = pRelativePath ? vgui::MDLCache()->FindMDL( pRelativePath ) : MDLHANDLE_INVALID; + int index = ( nSelectSecondary > 0 ? nSelectSecondary : 0 ); + + // We didn't change models after all... + if ( hSelectedMDL == m_hSelectedMDL[ index ] ) + { + // vgui::MDLCache()->FindMDL adds a reference by default we don't use, release it again + if ( hSelectedMDL != MDLHANDLE_INVALID ) + { + vgui::MDLCache()->Release( hSelectedMDL ); + } + return; + } + + m_hSelectedMDL[ index ] = hSelectedMDL; + + if ( vgui::MDLCache()->IsErrorModel( m_hSelectedMDL[ index ] ) ) + { + m_hSelectedMDL[ index ] = MDLHANDLE_INVALID; + } + if ( nSelectSecondary != -1 ) + { + m_pMDLPreview->ClearMergeMDLs(); + for( int i = 1; i < MAX_SELECTED_MODELS; i++ ) + { + if ( i != index ) + { + m_hSelectedMDL[ i ] = MDLHANDLE_INVALID; + } + } + } + + if ( index > 0 ) + { + m_pMDLPreview->SetMergeMDL( m_hSelectedMDL[ index ] ); + } + else + { + m_pMDLPreview->SetMDL( m_hSelectedMDL[ index ] ); + + if ( bDoLookAt ) + { + m_pMDLPreview->LookAtMDL(); + } + + if ( m_nFlags & ( PAGE_SKINS ) ) + { + UpdateSkinsList(); + } + + if ( m_nFlags & ( PAGE_INFO ) ) + { + UpdateInfoTab(); + } + + if ( m_nFlags & (PAGE_ACTIVITIES|PAGE_SEQUENCES) ) + { + RefreshActivitiesAndSequencesList(); + } + } + + // vgui::MDLCache()->FindMDL adds a reference by default we don't use, release it again + if ( hSelectedMDL != MDLHANDLE_INVALID ) + { + vgui::MDLCache()->Release( hSelectedMDL ); + } + + PostActionSignal( new KeyValues( "MDLPreviewChanged", "mdl", pRelativePath ? pRelativePath : "" ) ); +} + + +//----------------------------------------------------------------------------- +// Purpose: updates revision view on a file being selected +//----------------------------------------------------------------------------- +void CMDLPicker::OnCheckButtonChecked(KeyValues *kv) +{ +// RefreshMDLList(); + BaseClass::OnCheckButtonChecked( kv ); + RefreshRenderSettings(); +} + + +void CMDLPicker::GetSelectedMDLName( char *pBuffer, int nMaxLen ) +{ + Assert( nMaxLen > 0 ); + if ( GetSelectedAssetCount() > 0 ) + { + Q_snprintf( pBuffer, nMaxLen, "models\\%s", GetSelectedAsset( ) ); + } + else + { + pBuffer[0] = 0; + } +} + +//----------------------------------------------------------------------------- +// Gets the selected activity/sequence +//----------------------------------------------------------------------------- +int CMDLPicker::GetSelectedPage( ) +{ + if ( m_pSequencesPage && ( m_pViewsSheet->GetActivePage() == m_pSequencesPage ) ) + return PAGE_SEQUENCES; + + if ( m_pActivitiesPage && ( m_pViewsSheet->GetActivePage() == m_pActivitiesPage ) ) + return PAGE_ACTIVITIES; + + return PAGE_NONE; +} + +const char *CMDLPicker::GetSelectedSequenceName() +{ + if ( !m_pSequencesPage ) + return NULL; + + int nIndex = m_pSequencesList->GetSelectedItem( 0 ); + if ( nIndex >= 0 ) + { + KeyValues *pkv = m_pSequencesList->GetItem( nIndex ); + return pkv->GetString( "sequence", NULL ); + } + + return NULL; +} + +const char *CMDLPicker::GetSelectedActivityName() +{ + if ( !m_pActivitiesPage ) + return NULL; + + int nIndex = m_pActivitiesList->GetSelectedItem( 0 ); + if ( nIndex >= 0 ) + { + KeyValues *pkv = m_pActivitiesList->GetItem( nIndex ); + return pkv->GetString( "activity", NULL ); + } + return NULL; +} + +int CMDLPicker::GetSelectedSkin() +{ + if ( !m_pSkinsPage ) + return 0; + + int nIndex = m_pSkinsList->GetSelectedItem( 0 ); + if ( nIndex >= 0 ) + { + return nIndex; + } + return 0; +} + +//----------------------------------------------------------------------------- +// Plays the selected activity +//----------------------------------------------------------------------------- +void CMDLPicker::SelectActivity( const char *pActivityName ) +{ + studiohdr_t *pstudiohdr = vgui::MDLCache()->GetStudioHdr( m_hSelectedMDL[ 0 ] ); + for ( int i = 0; i < pstudiohdr->GetNumSeq(); i++ ) + { + mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i ); + if ( stricmp( seqdesc.pszActivityName(), pActivityName ) == 0 ) + { + // FIXME: Add weighted sequence selection logic? + m_pMDLPreview->SetSequence( i ); + break; + } + } + + PostActionSignal( new KeyValues( "SequenceSelectionChanged", "activity", pActivityName ) ); +} + + +//----------------------------------------------------------------------------- +// Plays the selected sequence +//----------------------------------------------------------------------------- +void CMDLPicker::SelectSequence( const char *pSequenceName ) +{ + studiohdr_t *pstudiohdr = vgui::MDLCache()->GetStudioHdr( m_hSelectedMDL[ 0 ] ); + for (int i = 0; i < pstudiohdr->GetNumSeq(); i++) + { + mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i ); + if ( !Q_stricmp( seqdesc.pszLabel(), pSequenceName ) ) + { + m_pMDLPreview->SetSequence( i ); + break; + } + } + + PostActionSignal( new KeyValues( "SequenceSelectionChanged", "sequence", pSequenceName ) ); +} + +void CMDLPicker::SelectSkin( int nSkin ) +{ + m_pMDLPreview->SetSkin( nSkin ); + PostActionSignal( new KeyValues( "SkinSelectionChanged", "skin", nSkin)); +} + + +//----------------------------------------------------------------------------- +// Purpose: Updates preview when an item is selected +//----------------------------------------------------------------------------- +void CMDLPicker::OnItemSelected( KeyValues *kv ) +{ + Panel *pPanel = (Panel *)kv->GetPtr("panel", NULL); + if ( m_pSequencesList && (pPanel == m_pSequencesList ) ) + { + const char *pSequenceName = GetSelectedSequenceName(); + if ( pSequenceName ) + { + SelectSequence( pSequenceName ); + } + return; + } + + if ( m_pActivitiesList && ( pPanel == m_pActivitiesList ) ) + { + const char *pActivityName = GetSelectedActivityName(); + if ( pActivityName ) + { + SelectActivity( pActivityName ); + } + return; + } + + if ( m_pSkinsList && ( pPanel == m_pSkinsList ) ) + { + int nSelectedSkin = GetSelectedSkin(); + SelectSkin( nSelectedSkin ); + + return; + } + + BaseClass::OnItemSelected( kv ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Called when a page is shown +//----------------------------------------------------------------------------- +void CMDLPicker::OnPageChanged( ) +{ + if ( m_pSequencesPage && ( m_pViewsSheet->GetActivePage() == m_pSequencesPage ) ) + { + m_pSequencesList->RequestFocus(); + + const char *pSequenceName = GetSelectedSequenceName(); + + if ( pSequenceName ) + { + SelectSequence( pSequenceName ); + } + return; + } + + if ( m_pActivitiesPage && ( m_pViewsSheet->GetActivePage() == m_pActivitiesPage ) ) + { + m_pActivitiesList->RequestFocus(); + + const char *pActivityName = GetSelectedActivityName(); + + if ( pActivityName ) + { + SelectActivity( pActivityName ); + } + return; + } +} + + +//----------------------------------------------------------------------------- +// +// Purpose: Modal picker frame +// +//----------------------------------------------------------------------------- +CMDLPickerFrame::CMDLPickerFrame( vgui::Panel *pParent, const char *pTitle, int nFlags ) : + BaseClass( pParent ) +{ + SetAssetPicker( new CMDLPicker( this, nFlags ) ); + LoadControlSettingsAndUserConfig( "resource/mdlpickerframe.res" ); + SetTitle( pTitle, false ); +} + +CMDLPickerFrame::~CMDLPickerFrame() +{ +} + + +//----------------------------------------------------------------------------- +// Allows external apps to select a MDL +//----------------------------------------------------------------------------- +void CMDLPickerFrame::SelectMDL( const char *pRelativePath ) +{ + static_cast( GetAssetPicker() )->SelectMDL( pRelativePath ); +} + +int CMDLPicker::UpdateSkinsList() +{ + int nNumSkins = 0; + + if ( m_pSkinsList ) + { + m_pSkinsList->RemoveAll(); + + studiohdr_t *hdr = vgui::MDLCache()->GetStudioHdr( m_hSelectedMDL[ 0 ] ); + if ( hdr ) + { + nNumSkins = hdr->numskinfamilies; + for ( int i = 0; i < nNumSkins; i++ ) + { + char skinText[25] = ""; + V_sprintf_safe( skinText, "skin%i", i ); + KeyValues *pkv = new KeyValues("node", "skin", skinText ); + m_pSkinsList->AddItem( pkv, 0, false, false ); + } + } + } + + return nNumSkins; +} + +void CMDLPicker::UpdateInfoTab() +{ + studiohdr_t *hdr = vgui::MDLCache()->GetStudioHdr( m_hSelectedMDL[ 0 ] ); + if ( !hdr ) + return; + + int nMass = hdr->mass; + Panel *pTempPanel = m_pInfoPage->FindChildByName("MassValue"); + char massBuff[10]; + Q_snprintf( massBuff, 10, "%d", nMass ); + ((vgui::Label *)pTempPanel)->SetText( massBuff ); + bool bIsStatic = hdr->flags & STUDIOHDR_FLAGS_STATIC_PROP; + bool bIsPhysics = false; + const char* buf = hdr->KeyValueText(); + Label * pTempLabel = (Label *)m_pInfoPage->FindChildByName("StaticText"); + pTempLabel->SetVisible( false ); + if( buf ) + { + buf = Q_strstr( buf, "prop_data" ); + if ( buf ) + { + int iPropDataCount = UpdatePropDataList( buf, bIsStatic ); + if( iPropDataCount ) + { + bIsPhysics = true; + } + } + else + { + m_pPropDataList->RemoveAll(); + } + } + else + { + m_pPropDataList->RemoveAll(); + } + + CheckButton * pTempCheck = (CheckButton *)m_pInfoPage->FindChildByName("StaticObject"); + pTempCheck->SetCheckButtonCheckable( true ); + pTempCheck->SetSelected( bIsStatic ); + pTempCheck->SetCheckButtonCheckable( false ); + pTempCheck = (CheckButton *)m_pInfoPage->FindChildByName("PhysicsObject"); + pTempCheck->SetCheckButtonCheckable( true ); + pTempCheck->SetSelected( bIsPhysics ); + pTempCheck->SetCheckButtonCheckable( false ); + pTempCheck = (CheckButton *)m_pInfoPage->FindChildByName("DynamicObject"); + pTempCheck->SetCheckButtonCheckable( true ); + pTempCheck->SetSelected( !bIsPhysics ); + pTempCheck->SetCheckButtonCheckable( false ); + + +} + +int CMDLPicker::UpdatePropDataList( const char* pszPropData, bool &bIsStatic ) +{ + int iCount = 0; + + if ( m_pPropDataList ) + { + m_pPropDataList->RemoveAll(); + + const char * endPropData = strchr( pszPropData, '}' ); + char keyText[255] = ""; + char valueText[255] = ""; + const char *beginChunk = strchr( pszPropData, '\"' ); + if ( !beginChunk ) + { + return 0; + } + beginChunk++; + const char *endChunk = strchr( beginChunk, '\"' ); + while( endChunk ) + { + Q_memcpy( keyText, beginChunk, endChunk - beginChunk ); + beginChunk = endChunk + 1; + beginChunk = strchr( beginChunk, '\"' ) + 1; + endChunk = strchr( beginChunk, '\"' ); + Q_memcpy( valueText, beginChunk, endChunk - beginChunk ); + if( !Q_strcmp( keyText, "allowstatic" ) && !Q_strcmp( valueText , "1" ) ) + { + if ( !bIsStatic ) + { + Label * pTempLabel = (Label *)m_pInfoPage->FindChildByName("StaticText"); + pTempLabel->SetVisible( true ); + } + bIsStatic &= true; + } + KeyValues *pkv = new KeyValues("node", "key", keyText, "value", valueText ); + m_pPropDataList->AddItem( pkv, 0, false, false ); + Q_memset( keyText, 0, 255 ); + Q_memset( valueText, 0, 255 ); + iCount++; + beginChunk = endChunk + 1; + beginChunk = strchr( beginChunk, '\"' ); + if ( !beginChunk || beginChunk > endPropData ) + { + return iCount; + } + beginChunk++; + endChunk = strchr( beginChunk, '\"' ); + } + } + return iCount; +} diff --git a/vgui2/matsys_controls/mdlsequencepicker.cpp b/vgui2/matsys_controls/mdlsequencepicker.cpp new file mode 100644 index 00000000..8e4443b0 --- /dev/null +++ b/vgui2/matsys_controls/mdlsequencepicker.cpp @@ -0,0 +1,539 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "matsys_controls/mdlsequencepicker.h" +#include "tier1/KeyValues.h" +#include "tier1/utldict.h" +#include "datacache/imdlcache.h" +#include "filesystem.h" +#include "studio.h" +#include "vgui/IVGui.h" +#include "vgui/Cursor.h" +#include "vgui/ISurface.h" +#include "vgui_controls/Splitter.h" +#include "vgui_controls/ComboBox.h" +#include "vgui_controls/PropertySheet.h" +#include "vgui_controls/PropertyPage.h" +#include "vgui_controls/ToolWindow.h" +#include "vgui_controls/Button.h" +#include "matsys_controls/gamefiletreeview.h" +#include "matsys_controls/matsyscontrols.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +using namespace vgui; + + +//----------------------------------------------------------------------------- +// +// MDL Sequence Picker +// +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CMDLSequencePicker::CMDLSequencePicker( vgui::Panel *pParent ) : BaseClass(pParent, "MDLSequencePicker"), m_Images(false) +{ + vgui::ivgui()->AddTickSignal( GetVPanel() ); + + m_hSelectedMDL = MDLHANDLE_INVALID; + + // Horizontal splitter for mdls + m_pMDLSplitter = new Splitter( this, "MDLSplitter", SPLITTER_MODE_VERTICAL, 1 ); + + vgui::Panel *pSplitterLeftSide = m_pMDLSplitter->GetChild( 0 ); + vgui::Panel *pSplitterRightSide = m_pMDLSplitter->GetChild( 1 ); + + // filter selection + m_pFilterList = new ComboBox( pSplitterLeftSide, "FilterList", 16, true ); + m_pFilterList->AddActionSignalTarget( this ); + + // file browser tree controls + m_pFileTree = new CGameFileTreeView( pSplitterLeftSide, "FileTree", "All .MDLs", "models", "mdl" ); + + // build our list of images + m_Images.AddImage( scheme()->GetImage( "resource/icon_folder", false ) ); + m_Images.AddImage( scheme()->GetImage( "resource/icon_folder_selected", false ) ); + m_Images.AddImage( scheme()->GetImage( "resource/icon_file", false ) ); + m_pFileTree->SetImageList( &m_Images, false ); + m_pFileTree->AddActionSignalTarget( this ); + + // property sheet - revisions, changes, etc. + m_pSequenceSplitter = new Splitter( pSplitterRightSide, "SequenceSplitter", SPLITTER_MODE_HORIZONTAL, 1 ); + + vgui::Panel *pSplitterTopSide = m_pSequenceSplitter->GetChild( 0 ); + vgui::Panel *pSplitterBottomSide = m_pSequenceSplitter->GetChild( 1 ); + + // MDL preview + m_pMDLPreview = new CMDLPanel( pSplitterTopSide, "MDLPreview" ); + SetSkipChildDuringPainting( m_pMDLPreview ); + + m_pViewsSheet = new vgui::PropertySheet( pSplitterBottomSide, "ViewsSheet" ); + m_pViewsSheet->AddActionSignalTarget( this ); + + // sequences + m_pSequencesPage = new PropertyPage( m_pViewsSheet, "SequencesPage" ); + m_pViewsSheet->AddPage( m_pSequencesPage, "Sequences" ); + m_pSequencesList = new ListPanel( m_pSequencesPage, "SequencesList" ); + m_pSequencesList->AddColumnHeader( 0, "sequence", "sequence", 52, 0 ); + m_pSequencesList->AddActionSignalTarget( this ); + m_pSequencesList->SetSelectIndividualCells( true ); + m_pSequencesList->SetEmptyListText("No .MDL file currently selected."); + m_pSequencesList->SetDragEnabled( true ); + m_pSequencesList->SetAutoResize( Panel::PIN_TOPLEFT, Panel::AUTORESIZE_DOWNANDRIGHT, 0, 0, 0, 0 ); + + // Activities + m_pActivitiesPage = new PropertyPage( m_pViewsSheet, "ActivitiesPage" ); + m_pViewsSheet->AddPage( m_pActivitiesPage, "Activities" ); + m_pActivitiesList = new ListPanel( m_pActivitiesPage, "ActivitiesList" ); + m_pActivitiesList->AddColumnHeader( 0, "activity", "activity", 52, 0 ); + m_pActivitiesList->AddActionSignalTarget( this ); + m_pActivitiesList->SetSelectIndividualCells( true ); + m_pActivitiesList->SetEmptyListText( "No .MDL file currently selected." ); + m_pActivitiesList->SetDragEnabled( true ); + m_pActivitiesList->SetAutoResize( Panel::PIN_TOPLEFT, Panel::AUTORESIZE_DOWNANDRIGHT, 0, 0, 0, 0 ); + + // Load layout settings; has to happen before pinning occurs in code + LoadControlSettingsAndUserConfig( "resource/mdlsequencepicker.res" ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Destructor +//----------------------------------------------------------------------------- +CMDLSequencePicker::~CMDLSequencePicker() +{ +} + + +//----------------------------------------------------------------------------- +// Purpose: This is a bit of a hack to make sure that the ToolWindow containing this picker punches +// a hold for the rendering viewport, too +// Input : - +//----------------------------------------------------------------------------- +void CMDLSequencePicker::OnTick() +{ + BaseClass::OnTick(); + if ( GetParent() ) + { + ToolWindow *tw = dynamic_cast< ToolWindow * >( GetParent()->GetParent() ); + + if ( tw ) + { + tw->SetSkipChildDuringPainting( IsVisible() ? m_pMDLPreview : NULL ); + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: stops app on close +//----------------------------------------------------------------------------- +void CMDLSequencePicker::OnClose() +{ + BaseClass::OnClose(); +} + +//----------------------------------------------------------------------------- +// Purpose: called to open +//----------------------------------------------------------------------------- +void CMDLSequencePicker::Activate() +{ + RefreshFileList(); + RefreshActivitiesAndSequencesList(); +} + + +//----------------------------------------------------------------------------- +// Performs layout +//----------------------------------------------------------------------------- +void CMDLSequencePicker::PerformLayout() +{ + // NOTE: This call should cause auto-resize to occur + // which should fix up the width of the panels + BaseClass::PerformLayout(); + + int w, h; + GetSize( w, h ); + + // Layout the mdl splitter + m_pMDLSplitter->SetBounds( 0, 0, w, h ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Refreshes the active file list +//----------------------------------------------------------------------------- +void CMDLSequencePicker::RefreshFileList() +{ + m_pFileTree->RefreshFileList(); +} + + +//----------------------------------------------------------------------------- +// Purpose: rebuilds the list of activities +//----------------------------------------------------------------------------- +void CMDLSequencePicker::RefreshActivitiesAndSequencesList() +{ + m_pActivitiesList->RemoveAll(); + m_pSequencesList->RemoveAll(); + m_pMDLPreview->SetSequence( 0 ); + + if ( m_hSelectedMDL == MDLHANDLE_INVALID ) + { + m_pActivitiesList->SetEmptyListText("No .MDL file currently selected"); + m_pSequencesList->SetEmptyListText("No .MDL file currently selected"); + return; + } + + m_pActivitiesList->SetEmptyListText(".MDL file contains no activities"); + m_pSequencesList->SetEmptyListText(".MDL file contains no sequences"); + + studiohdr_t *hdr = vgui::MDLCache()->GetStudioHdr( m_hSelectedMDL ); + + CUtlDict activityNames( true, 0, hdr->GetNumSeq() ); + + for (int j = 0; j < hdr->GetNumSeq(); j++) + { + if ( /*g_viewerSettings.showHidden ||*/ !(hdr->pSeqdesc(j).flags & STUDIO_HIDDEN)) + { + const char *pActivityName = hdr->pSeqdesc(j).pszActivityName(); + if ( pActivityName && pActivityName[0] ) + { + // Multiple sequences can have the same activity name; only add unique activity names + if ( activityNames.Find( pActivityName ) == activityNames.InvalidIndex() ) + { + KeyValues *pkv = new KeyValues("node", "activity", pActivityName ); + int nItemID = m_pActivitiesList->AddItem( pkv, 0, false, false ); + + KeyValues *pDrag = new KeyValues( "drag", "text", pActivityName ); + pDrag->SetString( "texttype", "activityName" ); + pDrag->SetString( "mdl", vgui::MDLCache()->GetModelName( m_hSelectedMDL ) ); + m_pActivitiesList->SetItemDragData( nItemID, pDrag ); + + activityNames.Insert( pActivityName, j ); + } + } + + const char *pSequenceName = hdr->pSeqdesc(j).pszLabel(); + if ( pSequenceName && pSequenceName[0] ) + { + KeyValues *pkv = new KeyValues("node", "sequence", pSequenceName); + pkv->SetInt( "seqindex", j ); + + int nItemID = m_pSequencesList->AddItem( pkv, 0, false, false ); + + KeyValues *pDrag = new KeyValues( "drag", "text", pSequenceName ); + pDrag->SetString( "texttype", "sequenceName" ); + pDrag->SetString( "mdl", vgui::MDLCache()->GetModelName( m_hSelectedMDL ) ); + m_pSequencesList->SetItemDragData( nItemID, pDrag ); + } + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: refreshes dialog on text changing +//----------------------------------------------------------------------------- +void CMDLSequencePicker::OnTextChanged( vgui::Panel *pPanel, const char *pText ) +{ +// m_pFileTree->SetFilter( pText ); + RefreshFileList(); +} + + +/* +//----------------------------------------------------------------------------- +// Purpose: Selects an sequence based on an activity +//----------------------------------------------------------------------------- +int SelectWeightedSequence( studiohdr_t *pstudiohdr, int activity, int curSequence ) +{ + if (! pstudiohdr) + return 0; + + VerifySequenceIndex( pstudiohdr ); + + int weighttotal = 0; + int seq = ACTIVITY_NOT_AVAILABLE; + int weight = 0; + for (int i = 0; i < pstudiohdr->GetNumSeq(); i++) + { + int curActivity = GetSequenceActivity( pstudiohdr, i, &weight ); + if (curActivity == activity) + { + if ( curSequence == i && weight < 0 ) + { + seq = i; + break; + } + weighttotal += iabs(weight); + + int randomValue; + if ( IsInPrediction() ) + randomValue = SharedRandomInt( "SelectWeightedSequence", 0, weighttotal - 1, i ); + else + randomValue = RandomInt( 0, weighttotal - 1 ); + + if (!weighttotal || randomValue < iabs(weight)) + seq = i; + } + } + + return seq; +} +*/ + +//----------------------------------------------------------------------------- +// Plays the selected activity +//----------------------------------------------------------------------------- +void CMDLSequencePicker::PlaySelectedActivity( ) +{ + int nIndex = m_pActivitiesList->GetSelectedItem( 0 ); + if ( nIndex < 0 ) + return; + + KeyValues *pkv = m_pActivitiesList->GetItem( nIndex ); + const char *pActivityName = pkv->GetString( "activity", NULL ); + if ( !pActivityName ) + return; + + studiohdr_t *pstudiohdr = vgui::MDLCache()->GetStudioHdr( m_hSelectedMDL ); + for ( int i = 0; i < pstudiohdr->GetNumSeq(); i++ ) + { + mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i ); + if ( stricmp( seqdesc.pszActivityName(), pActivityName ) == 0 ) + { + // FIXME: Add weighted sequence selection logic? + m_pMDLPreview->SetSequence( i ); + break; + } + } +} + + +//----------------------------------------------------------------------------- +// Plays the selected sequence +//----------------------------------------------------------------------------- +void CMDLSequencePicker::PlaySelectedSequence( ) +{ + int nIndex = m_pSequencesList->GetSelectedItem( 0 ); + if ( nIndex < 0 ) + return; + + KeyValues *pkv = m_pSequencesList->GetItem( nIndex ); + const char *pSequenceName = pkv->GetString( "sequence", NULL ); + if ( !pSequenceName ) + return; + + studiohdr_t *pstudiohdr = vgui::MDLCache()->GetStudioHdr( m_hSelectedMDL ); + for (int i = 0; i < pstudiohdr->GetNumSeq(); i++) + { + mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i ); + if ( !Q_stricmp( seqdesc.pszLabel(), pSequenceName ) ) + { + m_pMDLPreview->SetSequence( i ); + break; + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Called when a page is shown +//----------------------------------------------------------------------------- +void CMDLSequencePicker::OnPageChanged( ) +{ + if ( m_pViewsSheet->GetActivePage() == m_pSequencesPage ) + { + PlaySelectedSequence(); + return; + } + + if ( m_pViewsSheet->GetActivePage() == m_pActivitiesPage ) + { + PlaySelectedActivity(); + return; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: refreshes dialog on text changing +//----------------------------------------------------------------------------- +void CMDLSequencePicker::OnItemSelected( KeyValues *kv ) +{ + Panel *pPanel = (Panel *)kv->GetPtr("panel", NULL); + if ( pPanel == m_pSequencesList ) + { + PlaySelectedSequence(); + return; + } + + if ( pPanel == m_pActivitiesList ) + { + PlaySelectedActivity(); + return; + } +} + + +//----------------------------------------------------------------------------- +// An MDL was selected +//----------------------------------------------------------------------------- +void CMDLSequencePicker::SelectMDL( const char *pMDLName ) +{ + m_hSelectedMDL = pMDLName ? vgui::MDLCache()->FindMDL( pMDLName ) : MDLHANDLE_INVALID; + if ( vgui::MDLCache()->IsErrorModel( m_hSelectedMDL ) ) + { + m_hSelectedMDL = MDLHANDLE_INVALID; + } + m_pMDLPreview->SetMDL( m_hSelectedMDL ); + m_pMDLPreview->LookAtMDL(); + RefreshActivitiesAndSequencesList(); +} + + +//----------------------------------------------------------------------------- +// Purpose: updates revision view on a file being selected +//----------------------------------------------------------------------------- +void CMDLSequencePicker::OnFileSelected() +{ + // update list + int iItem = m_pFileTree->GetFirstSelectedItem(); + if ( iItem < 0 ) + return; + + // Don't bother to change if a directory was selected + KeyValues *pkv = m_pFileTree->GetItemData(iItem); + if ( pkv->GetInt("dir") || pkv->GetInt("root") ) + return; + + surface()->SetCursor(dc_waitarrow); + + const char *pFullPathName = pkv->GetString( "path" ); + + char pRelativePathName[MAX_PATH]; + g_pFullFileSystem->FullPathToRelativePath( pFullPathName, pRelativePathName, sizeof(pRelativePathName) ); + + // FIXME: Check that we're not actually opening the wrong file!! + SelectMDL( pRelativePathName ); +} + +char const *CMDLSequencePicker::GetModelName() +{ + if ( MDLHANDLE_INVALID == m_hSelectedMDL ) + { + return ""; + } + + return vgui::MDLCache()->GetModelName( m_hSelectedMDL ); +} + +char const *CMDLSequencePicker::GetSequenceName() +{ + int nIndex = m_pSequencesList->GetSelectedItem( 0 ); + if ( nIndex < 0 ) + return ""; + + KeyValues *pkv = m_pSequencesList->GetItem( nIndex ); + const char *pSequenceName = pkv->GetString( "sequence", NULL ); + if ( !pSequenceName ) + return ""; + + return pSequenceName; +} + +int CMDLSequencePicker::GetSequenceNumber() +{ + int nIndex = m_pSequencesList->GetSelectedItem( 0 ); + if ( nIndex < 0 ) + return -1; + KeyValues *pkv = m_pSequencesList->GetItem( nIndex ); + return pkv->GetInt( "seqindex", -1 ); +} + +//----------------------------------------------------------------------------- +// Sequence picker frame +//----------------------------------------------------------------------------- +CMDLSequencePickerFrame::CMDLSequencePickerFrame( vgui::Panel *parent, char const *title ) : + BaseClass( parent, "MDLSequencePickerFrame" ) +{ + m_pMDLSequencePicker = new CMDLSequencePicker( this ); + SetTitle( title, true ); + SetSizeable( false ); + SetCloseButtonVisible( false ); + SetMoveable( true ); + SetMinimumSize( 640, 480 ); + Activate(); + m_pMDLSequencePicker->Activate(); + + m_pOK = new Button( this, "OK", "#vgui_ok", this ); + m_pOK->SetCommand( new KeyValues( "OnOK" ) ); + m_pCancel= new Button( this, "Cancel", "#vgui_cancel", this ); + m_pOK->SetCommand( new KeyValues( "OnCancel" ) ); + m_pOK->SetEnabled( false ); + + vgui::ivgui()->AddTickSignal( GetVPanel(), 0 ); +} + +CMDLSequencePickerFrame::~CMDLSequencePickerFrame() +{ +} + +void CMDLSequencePickerFrame::OnTick() +{ + BaseClass::OnTick(); + + bool bHasModel = m_pMDLSequencePicker->GetModelName()[ 0 ] != 0 ? true : false; + bool bHasSequence = m_pMDLSequencePicker->GetSequenceNumber() != -1 ? true : false; + + m_pOK->SetEnabled( bHasModel && bHasSequence ); +} + +void CMDLSequencePickerFrame::PerformLayout() +{ + BaseClass::PerformLayout(); + + int x, y, w, h; + GetClientArea( x, y, w, h ); + h -= 24; + m_pMDLSequencePicker->SetBounds( x, y, w, h ); + + h += 5; + + + int bw = 120; + int bwwithGap = 2 * bw + 10; + + x = ( w - bwwithGap ) / 2; + m_pOK->SetBounds( x, y + h, bw, 16 ); + x += bw + 10; + m_pCancel->SetBounds( x, y + h, bw, 16 ); +} + +void CMDLSequencePickerFrame::OnCancel() +{ + KeyValues *pActionKeys = new KeyValues( "AssetSelected" ); + pActionKeys->SetString( "ModelName", m_pMDLSequencePicker->GetModelName() ); + pActionKeys->SetString( "SequenceName", m_pMDLSequencePicker->GetSequenceName() ); + pActionKeys->SetInt( "SequenceNumber", m_pMDLSequencePicker->GetSequenceNumber() ); + + PostActionSignal( pActionKeys ); + + CloseModal(); +} + +void CMDLSequencePickerFrame::OnOK() +{ + CloseModal(); +} + + diff --git a/vgui2/matsys_controls/picker.cpp b/vgui2/matsys_controls/picker.cpp new file mode 100644 index 00000000..63622134 --- /dev/null +++ b/vgui2/matsys_controls/picker.cpp @@ -0,0 +1,318 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "filesystem.h" +#include "matsys_controls/picker.h" +#include "tier1/KeyValues.h" +#include "vgui_controls/ListPanel.h" +#include "vgui_controls/TextEntry.h" +#include "vgui_controls/Button.h" +#include "vgui/ISurface.h" +#include "vgui/IInput.h" + + +using namespace vgui; + + +//----------------------------------------------------------------------------- +// +// Base asset Picker +// +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// Sort by asset name +//----------------------------------------------------------------------------- +static int __cdecl PickerBrowserSortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 ) +{ + const char *string1 = item1.kv->GetString("choice"); + const char *string2 = item2.kv->GetString("choice"); + return stricmp( string1, string2 ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CPicker::CPicker( vgui::Panel *pParent, const char *pColumnHeader, const char *pTextType ) : + BaseClass( pParent, "Picker" ) +{ + m_pPickerType = pColumnHeader; + m_pPickerTextType = pTextType; + + // FIXME: Make this an image browser + m_pPickerBrowser = new vgui::ListPanel( this, "Browser" ); + m_pPickerBrowser->AddColumnHeader( 0, "choice", m_pPickerType, 52, 0 ); + m_pPickerBrowser->SetSelectIndividualCells( true ); + m_pPickerBrowser->SetEmptyListText( "Nothing to pick" ); + m_pPickerBrowser->SetDragEnabled( true ); + m_pPickerBrowser->AddActionSignalTarget( this ); + m_pPickerBrowser->SetSortFunc( 0, PickerBrowserSortFunc ); + m_pPickerBrowser->SetSortColumn( 0 ); + + // filter selection + m_pFilterList = new TextEntry( this, "FilterList" ); + m_pFilterList->AddActionSignalTarget( this ); + m_pFilterList->RequestFocus(); + + LoadControlSettingsAndUserConfig( "resource/picker.res" ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Destructor +//----------------------------------------------------------------------------- +CPicker::~CPicker() +{ +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CPicker::OnKeyCodePressed( KeyCode code ) +{ + if (( code == KEY_UP ) || ( code == KEY_DOWN ) || ( code == KEY_PAGEUP ) || ( code == KEY_PAGEDOWN )) + { + KeyValues *pMsg = new KeyValues("KeyCodePressed", "code", code); + vgui::ipanel()->SendMessage( m_pPickerBrowser->GetVPanel(), pMsg, GetVPanel()); + pMsg->deleteThis(); + } + else + { + BaseClass::OnKeyCodePressed( code ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: refreshes the asset list +//----------------------------------------------------------------------------- +void CPicker::SetStringList( const PickerList_t &list ) +{ + m_Type = list.m_Type; + m_pPickerBrowser->RemoveAll(); + + int nCount = list.Count(); + for ( int i = 0; i < nCount; ++i ) + { + const char *pPickerName = list[i].m_pChoiceString; + KeyValues *kv = new KeyValues( "node", "choice", pPickerName ); + if ( m_Type == PICKER_CHOICE_STRING ) + { + kv->SetString( "value", list[i].m_pChoiceValue ); + } + else + { + kv->SetPtr( "value", list[i].m_pChoiceValuePtr ); + } + int nItemID = m_pPickerBrowser->AddItem( kv, 0, false, false ); + + if ( m_Type == PICKER_CHOICE_STRING ) + { + KeyValues *pDrag = new KeyValues( "drag", "text", list[i].m_pChoiceValue ); + if ( m_pPickerTextType ) + { + pDrag->SetString( "texttype", m_pPickerTextType ); + } + m_pPickerBrowser->SetItemDragData( nItemID, pDrag ); + } + } + RefreshChoiceList(); +} + + +//----------------------------------------------------------------------------- +// Purpose: refreshes the choice list +//----------------------------------------------------------------------------- +void CPicker::RefreshChoiceList( ) +{ + // Check the filter matches + int nMatchingCount = 0; + int nTotalCount = 0; + for ( int nItemID = m_pPickerBrowser->FirstItem(); nItemID != m_pPickerBrowser->InvalidItemID(); nItemID = m_pPickerBrowser->NextItem( nItemID ) ) + { + KeyValues *kv = m_pPickerBrowser->GetItem( nItemID ); + const char *pPickerName = kv->GetString( "choice" ); + bool bVisible = !m_Filter.Length() || Q_stristr( pPickerName, m_Filter.Get() ); + m_pPickerBrowser->SetItemVisible( nItemID, bVisible ); + if ( bVisible ) + { + ++nMatchingCount; + } + ++nTotalCount; + } + + char pColumnTitle[512]; + Q_snprintf( pColumnTitle, sizeof(pColumnTitle), "%s (%d/%d)", + m_pPickerType, nMatchingCount, nTotalCount ); + m_pPickerBrowser->SetColumnHeaderText( 0, pColumnTitle ); + + m_pPickerBrowser->SortList(); + if ( ( m_pPickerBrowser->GetSelectedItemsCount() == 0 ) && ( m_pPickerBrowser->GetItemCount() > 0 ) ) + { + int nItemID = m_pPickerBrowser->GetItemIDFromRow( 0 ); + m_pPickerBrowser->SetSelectedCell( nItemID, 0 ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: refreshes dialog on text changing +//----------------------------------------------------------------------------- +void CPicker::OnTextChanged( ) +{ + int nLength = m_pFilterList->GetTextLength(); + m_Filter.SetLength( nLength ); + if ( nLength > 0 ) + { + m_pFilterList->GetText( m_Filter.GetForModify(), nLength+1 ); + } + RefreshChoiceList(); +} + + +//----------------------------------------------------------------------------- +// Returns the selected string +//----------------------------------------------------------------------------- +PickerChoiceType_t CPicker::GetSelectionType() const +{ + return m_Type; +} + +const char *CPicker::GetSelectedString( ) const +{ + if ( m_pPickerBrowser->GetSelectedItemsCount() == 0 ) + return NULL; + + if ( m_Type != PICKER_CHOICE_STRING ) + return NULL; + + int nIndex = m_pPickerBrowser->GetSelectedItem( 0 ); + KeyValues *pItemKeyValues = m_pPickerBrowser->GetItem( nIndex ); + return pItemKeyValues->GetString( "value" ); +} + +void *CPicker::GetSelectedPtr( ) const +{ + if ( m_pPickerBrowser->GetSelectedItemsCount() == 0 ) + return NULL; + + if ( m_Type != PICKER_CHOICE_PTR ) + return NULL; + + int nIndex = m_pPickerBrowser->GetSelectedItem( 0 ); + KeyValues *pItemKeyValues = m_pPickerBrowser->GetItem( nIndex ); + return pItemKeyValues->GetPtr( "value" ); +} + + +//----------------------------------------------------------------------------- +// Returns the index of the selected string +//----------------------------------------------------------------------------- +int CPicker::GetSelectedIndex() +{ + if ( m_pPickerBrowser->GetSelectedItemsCount() == 0 ) + return -1; + + return m_pPickerBrowser->GetSelectedItem( 0 ); +} + + +//----------------------------------------------------------------------------- +// +// Purpose: Modal picker frame +// +//----------------------------------------------------------------------------- +CPickerFrame::CPickerFrame( vgui::Panel *pParent, const char *pTitle, const char *pPickerType, const char *pTextType ) : + BaseClass( pParent, "PickerFrame" ) +{ + m_pContextKeyValues = NULL; + SetDeleteSelfOnClose( true ); + m_pPicker = new CPicker( this, pPickerType, pTextType ); + m_pPicker->AddActionSignalTarget( this ); + m_pOpenButton = new Button( this, "OpenButton", "#FileOpenDialog_Open", this, "Open" ); + m_pCancelButton = new Button( this, "CancelButton", "#FileOpenDialog_Cancel", this, "Cancel" ); + SetBlockDragChaining( true ); + + LoadControlSettingsAndUserConfig( "resource/pickerframe.res" ); + + SetTitle( pTitle, false ); +} + +CPickerFrame::~CPickerFrame() +{ + CleanUpMessage(); +} + + +//----------------------------------------------------------------------------- +// Deletes the message +//----------------------------------------------------------------------------- +void CPickerFrame::CleanUpMessage() +{ + if ( m_pContextKeyValues ) + { + m_pContextKeyValues->deleteThis(); + m_pContextKeyValues = NULL; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Activate the dialog +//----------------------------------------------------------------------------- +void CPickerFrame::DoModal( const PickerList_t &list, KeyValues *pContextKeyValues ) +{ + CleanUpMessage(); + m_pContextKeyValues = pContextKeyValues; + m_pPicker->SetStringList( list ); + BaseClass::DoModal(); +} + + +//----------------------------------------------------------------------------- +// On command +//----------------------------------------------------------------------------- +void CPickerFrame::OnCommand( const char *pCommand ) +{ + if ( !Q_stricmp( pCommand, "Open" ) ) + { + KeyValues *pActionKeys = new KeyValues( "Picked" ); + pActionKeys->SetInt( "choiceIndex", m_pPicker->GetSelectedIndex( ) ); + + if ( m_pPicker->GetSelectionType() == PICKER_CHOICE_STRING ) + { + const char *pPickerName = m_pPicker->GetSelectedString( ); + pActionKeys->SetString( "choice", pPickerName ); + } + else + { + void *pPickerPtr = m_pPicker->GetSelectedPtr( ); + pActionKeys->SetPtr( "choice", pPickerPtr ); + } + + if ( m_pContextKeyValues ) + { + pActionKeys->AddSubKey( m_pContextKeyValues ); + m_pContextKeyValues = NULL; + } + PostActionSignal( pActionKeys ); + CloseModal(); + return; + } + + if ( !Q_stricmp( pCommand, "Cancel" ) ) + { + CloseModal(); + return; + } + + BaseClass::OnCommand( pCommand ); +} + + diff --git a/vgui2/matsys_controls/potterywheelpanel.cpp b/vgui2/matsys_controls/potterywheelpanel.cpp new file mode 100644 index 00000000..250fb64c --- /dev/null +++ b/vgui2/matsys_controls/potterywheelpanel.cpp @@ -0,0 +1,1231 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "matsys_controls/potterywheelpanel.h" +#include "matsys_controls/manipulator.h" +#include "vgui/ISystem.h" +#include "vgui/Cursor.h" +#include "vgui/IVGui.h" +#include "vgui/ISurface.h" +#include "vgui/IInput.h" +#include "VGuiMatSurface/IMatSystemSurface.h" +#include "dmxloader/dmxelement.h" +#include "vgui_controls/Frame.h" +#include "convar.h" +#include "tier0/dbg.h" +#include "matsys_controls/matsyscontrols.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/imaterialsystem.h" +#include "istudiorender.h" +#include "materialsystem/imaterialsystemhardwareconfig.h" +#include "tier2/renderutils.h" +#include "tier1/KeyValues.h" +#include "materialsystem/imesh.h" + +#include "inputsystem/iinputsystem.h" + +#include "renderparm.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +using namespace vgui; + + +//----------------------------------------------------------------------------- +// Translation manipulator +//----------------------------------------------------------------------------- +class CTranslationManipulator : public CTransformManipulator +{ +public: + CTranslationManipulator( matrix3x4_t *pTransform ); + + // Methods of IManipulator + virtual void OnMousePressed( vgui::MouseCode code, int x, int y ); + virtual void OnCursorMoved( int x, int y ); + +protected: + int m_lastx, m_lasty; +}; + + +CTranslationManipulator::CTranslationManipulator( matrix3x4_t *pTransform ) : CTransformManipulator( pTransform ) +{ + m_lastx = m_lasty = 0; +} + +void CTranslationManipulator::OnMousePressed( vgui::MouseCode code, int x, int y ) +{ + m_lasty = y; + m_lastx = x; +} + +void CTranslationManipulator::OnCursorMoved( int x, int y ) +{ + if ( !m_pTransform ) + return; + + Vector vPosition; + QAngle quakeEuler; + MatrixAngles( *m_pTransform, quakeEuler, vPosition ); + + Vector forward, right, up; + AngleVectors( quakeEuler, &forward, &right, &up ); + + int dy = y - m_lasty; + int dx = x - m_lastx; + + right *= -0.2f * dx; + up *= 0.2f * dy; + vPosition += up + right; + + m_lastx = x; + m_lasty = y; + + PositionMatrix( vPosition, *m_pTransform ); +} + + +//----------------------------------------------------------------------------- +// Zoom manipulator +//----------------------------------------------------------------------------- +class CZoomManipulator : public CBaseManipulator +{ +public: + CZoomManipulator( float *pDistance ); + + // Methods of IManipulator + virtual void OnMousePressed( vgui::MouseCode code, int x, int y ); + virtual void OnCursorMoved( int x, int y ); + +protected: + int m_lasty; + float *m_pDistance; +}; + +CZoomManipulator::CZoomManipulator( float *pDistance ) +{ + m_lasty = 0; + m_pDistance = pDistance; +} + +void CZoomManipulator::OnMousePressed( vgui::MouseCode code, int x, int y ) +{ + m_lasty = y; +} + +void CZoomManipulator::OnCursorMoved( int x, int y ) +{ + float delta = 0.2f * ( y - m_lasty ); + m_lasty = y; + *m_pDistance *= pow( 1.01f, delta ); +} + + +//----------------------------------------------------------------------------- +// Rotation manipulator +//----------------------------------------------------------------------------- +class CRotationManipulator : public CTransformManipulator +{ +public: + CRotationManipulator( matrix3x4_t *pTransform ); + + // Inherited from IManipulator + virtual void OnMousePressed( vgui::MouseCode code, int x, int y ); + virtual void OnCursorMoved( int x, int y ); + virtual void UpdateTransform(); + + void UpdateFromMatrix( void ); + +private: + int m_lastx, m_lasty; + float m_altitude, m_azimuth, m_roll; + bool m_bDoRoll; +}; + + +CRotationManipulator::CRotationManipulator( matrix3x4_t *pTransform ) : CTransformManipulator( pTransform ) +{ + m_lastx = m_lasty = 0; + m_altitude = M_PI/6; + m_azimuth = -3*M_PI/4; + m_roll = 0.0f; + m_bDoRoll = false; + UpdateTransform(); +} + +void CRotationManipulator::OnMousePressed( vgui::MouseCode code, int x, int y ) +{ + if ( input()->IsKeyDown( KEY_LALT ) || input()->IsKeyDown( KEY_RALT ) ) + { + m_bDoRoll = true; + } + else + { + m_bDoRoll = false; + } + m_lasty = y; + m_lastx = x; +} + +void CRotationManipulator::OnCursorMoved( int x, int y ) +{ + if ( m_bDoRoll ) + { + m_roll += 0.002f * ( m_lastx - x ); + } + else + { + m_azimuth += 0.002f * ( m_lastx - x ); + m_altitude -= 0.002f * ( m_lasty - y ); + m_altitude = max( (float)-M_PI/2, min( (float)M_PI/2, m_altitude ) ); + } + + m_lastx = x; + m_lasty = y; + + UpdateTransform(); +} + +void CRotationManipulator::UpdateTransform() +{ + if ( !m_pTransform ) + return; + + QAngle angles( RAD2DEG( m_altitude ), RAD2DEG( m_azimuth ), RAD2DEG( m_roll ) ); + Vector vecPosition; + MatrixGetColumn( *m_pTransform, 3, vecPosition ); + AngleMatrix( angles, vecPosition, *m_pTransform ); +} + +void CRotationManipulator::UpdateFromMatrix( void ) +{ + if ( !m_pTransform ) + return; + + QAngle angDir; + Vector vecPos; + + MatrixAngles( *m_pTransform, angDir, vecPos ); + + m_altitude = DEG2RAD( angDir.x ); + m_azimuth = DEG2RAD( angDir.y ); + m_roll = DEG2RAD( angDir.z ); +} + + + +//----------------------------------------------------------------------------- +// Constructor, destructor +//----------------------------------------------------------------------------- +CPotteryWheelPanel::CPotteryWheelPanel( vgui::Panel *pParent, const char *pName ) : + BaseClass( pParent, pName ), + m_pCameraRotate( NULL ), + m_pCameraTranslate( NULL ), + m_pCameraZoom( NULL ), + m_pLightManip( NULL ), + m_pCurrentManip( NULL ), + m_nCaptureMouseCode( vgui::MouseCode( -1 ) ), + m_xoffset( 0 ), m_yoffset( 0 ), + m_bRenderToTexture( true ) +{ + m_bHasLightProbe = false; + + SetPaintBackgroundEnabled( false ); + SetPaintBorderEnabled( false ); + m_ClearColor.SetColor( 76, 88, 68, 255 ); + + SetIdentityMatrix( m_CameraPivot ); + + CreateDefaultLights(); + + m_nManipStartX = m_nManipStartY = 0; + + m_vecCameraOffset.Init( 100.0f, 0.0f, 0.0f ); + + m_Camera.m_flZNear = 3.0f; + m_Camera.m_flZFar = 16384.0f * 1.73205080757f; + m_Camera.m_flFOV = 30.0f; + + m_pCameraRotate = new CRotationManipulator( &m_CameraPivot ); + m_pCameraTranslate = new CTranslationManipulator( &m_CameraPivot ); + m_pCameraZoom = new CZoomManipulator( &m_vecCameraOffset.x ); + + KeyValues *pMaterialKeys = new KeyValues( "Wireframe", "$model", "1" ); + + pMaterialKeys->SetString( "$vertexcolor", "1" ); + m_Wireframe.Init( "potterywheelpanelwireframe", pMaterialKeys ); + + SetKeyBoardInputEnabled( true ); + UpdateCameraTransform(); +} + +void CPotteryWheelPanel::ApplySettings( KeyValues *inResourceData ) +{ + BaseClass::ApplySettings( inResourceData ); + + KeyValues *pLights = inResourceData->FindKey( "lights" ); + if ( pLights ) + { + ParseLightsFromKV( pLights ); + } +} + +void CPotteryWheelPanel::Init( int x, int y, int wide, int tall ) +{ + BaseClass::Init( x, y, wide, tall ); + + // Used to poll input + vgui::ivgui()->AddTickSignal( GetVPanel() ); +} + + +CPotteryWheelPanel::~CPotteryWheelPanel() +{ + m_Wireframe.Shutdown(); + m_LightProbeBackground.Shutdown(); + m_LightProbeHDRBackground.Shutdown(); + m_LightProbeCubemap.Shutdown(); + m_LightProbeHDRCubemap.Shutdown(); + + if ( m_pCameraRotate ) + { + delete m_pCameraRotate; + m_pCameraRotate = NULL; + } + + if ( m_pCameraZoom ) + { + delete m_pCameraZoom; + m_pCameraZoom = NULL; + } + + if ( m_pCameraTranslate ) + { + delete m_pCameraTranslate; + m_pCameraTranslate = NULL; + } + + DestroyLights(); +} + +void CPotteryWheelPanel::CreateDefaultLights() +{ + for ( int i = 0; i < 6; ++i ) + { + m_vecAmbientCube[i].Init( 0.4f, 0.4f, 0.4f, 1.0f ); + } + + memset( &m_Lights[0].m_Desc, 0, sizeof(LightDesc_t) ); + SetIdentityMatrix( m_Lights[0].m_LightToWorld ); + m_Lights[0].m_Desc.m_Type = MATERIAL_LIGHT_DIRECTIONAL; + m_Lights[0].m_Desc.m_Color.Init( 1.0f, 1.0f, 1.0f ); + m_Lights[0].m_Desc.m_Direction.Init( 0.0f, 0.0f, -1.0f ); + m_Lights[0].m_Desc.m_Range=0.0; + m_Lights[0].m_Desc.m_Attenuation0 = 1.0; + m_Lights[0].m_Desc.m_Attenuation1 = 0; + m_Lights[0].m_Desc.m_Attenuation2 = 0; + m_Lights[0].m_Desc.RecalculateDerivedValues(); + m_nLightCount = 1; + + m_pLightManip = new CPotteryWheelManip( &m_Lights[0].m_LightToWorld ); +} + + +void CPotteryWheelPanel::DestroyLights() +{ + if ( m_pLightManip ) + { + delete m_pLightManip; + m_pLightManip = NULL; + } + + m_nLightCount = 0; +} + + +void StringToFloatArray( float *pVector, int count, const char *pString ) +{ + char *pstr, *pfront, tempString[128]; + int j; + + Q_strncpy( tempString, pString, sizeof(tempString) ); + pstr = pfront = tempString; + + for ( j = 0; j < count; j++ ) // lifted from pr_edict.c + { + pVector[j] = atof( pfront ); + + // skip any leading whitespace + while ( *pstr && *pstr <= ' ' ) + pstr++; + + // skip to next whitespace + while ( *pstr && *pstr > ' ' ) + pstr++; + + if (!*pstr) + break; + + pstr++; + pfront = pstr; + } + for ( j++; j < count; j++ ) + { + pVector[j] = 0; + } +} + +void StringToVector( float *pVector, const char *pString ) +{ + StringToFloatArray( pVector, 3, pString ); +} + + +//----------------------------------------------------------------------------- +// Sets initialize lights from KeyValues +//----------------------------------------------------------------------------- +void CPotteryWheelPanel::ParseLightsFromKV( KeyValues *pLightsKV ) +{ + int nLightCount = 0; + FOR_EACH_SUBKEY( pLightsKV, pLocalLight ) + { + Assert( nLightCount < MAX_LIGHT_COUNT ); + if ( nLightCount >= MAX_LIGHT_COUNT ) + break; + + LightDesc_t *pDesc = &m_Lights[nLightCount].m_Desc; + const char *pType = pLocalLight->GetString( "name" ); + Vector vecColor; + StringToVector( vecColor.Base(), pLocalLight->GetString( "color" ) ); + + if ( !Q_stricmp( pType, "directional" ) ) + { + Vector vecDirection; + StringToVector( vecDirection.Base(), pLocalLight->GetString( "direction" ) ); + pDesc->InitDirectional( vecDirection.Normalized(), vecColor ); + ++nLightCount; + continue; + } + + if ( !Q_stricmp( pType, "point" ) ) + { + Vector vecAtten; + StringToVector( vecAtten.Base(), pLocalLight->GetString( "attenuation" ) ); + Vector vecOrigin; + StringToVector( vecOrigin.Base(), pLocalLight->GetString( "origin" ) ); + pDesc->InitPoint( vecOrigin, vecColor ); + pDesc->m_Attenuation0 = vecAtten.x; + pDesc->m_Attenuation1 = vecAtten.y; + pDesc->m_Attenuation2 = vecAtten.z; + pDesc->m_Range = pLocalLight->GetFloat( "maxDistance" ); + pDesc->RecalculateDerivedValues(); + ++nLightCount; + continue; + } + + if ( !Q_stricmp( pType, "spot" ) ) + { + Vector vecAtten; + StringToVector( vecAtten.Base(), pLocalLight->GetString( "attenuation" ) ); + Vector vecOrigin; + StringToVector( vecOrigin.Base(), pLocalLight->GetString( "origin" ) ); + pDesc->InitSpot( vecOrigin, vecColor, vec3_origin, + pLocalLight->GetFloat( "inner_cone_angle" ), + pLocalLight->GetFloat( "outer_cone_angle" ) ); + + Vector vecDirection; + StringToVector( vecDirection.Base(), pLocalLight->GetString( "direction" ) ); + pDesc->m_Direction = vecDirection.Normalized(); + pDesc->m_Attenuation0 = vecAtten.x; + pDesc->m_Attenuation1 = vecAtten.y; + pDesc->m_Attenuation2 = vecAtten.z; + pDesc->m_Range = pLocalLight->GetFloat( "maxDistance" ); + pDesc->m_Falloff = pLocalLight->GetFloat( "exponent" ); + pDesc->RecalculateDerivedValues(); + ++nLightCount; + continue; + } + + AssertMsg1( 0, "Failed to initialize light with type '%s'", pType ); + } + + AssertMsg( nLightCount > 0, "Must specify at least one valid light" ); + + m_nLightCount = nLightCount; +} + + +//----------------------------------------------------------------------------- +// Sets the background color +//----------------------------------------------------------------------------- +void CPotteryWheelPanel::SetBackgroundColor( int r, int g, int b ) +{ + m_ClearColor.SetColor( r, g, b, 255 ); +} + +void CPotteryWheelPanel::SetBackgroundColor( const Color& c ) +{ + m_ClearColor = c; +} + +const Color& CPotteryWheelPanel::GetBackgroundColor() const +{ + return m_ClearColor; +} + + +//----------------------------------------------------------------------------- +// Light probe +//----------------------------------------------------------------------------- +void CPotteryWheelPanel::SetLightProbe( CDmxElement *pLightProbe ) +{ + m_LightProbeBackground.Shutdown(); + m_LightProbeHDRBackground.Shutdown(); + m_LightProbeCubemap.Shutdown(); + m_LightProbeHDRCubemap.Shutdown(); + + DestroyLights(); + + m_bHasLightProbe = ( pLightProbe != NULL ); + if ( !m_bHasLightProbe ) + { + CreateDefaultLights(); + return; + } + + const char *pCubemap = pLightProbe->GetValueString( "cubemap" ); + m_LightProbeCubemap.Init( pCubemap, TEXTURE_GROUP_OTHER ); + + const char *pCubemapHDR = pLightProbe->HasAttribute( "cubemapHdr" ) ? pLightProbe->GetValueString( "cubemapHdr" ) : pCubemap; + m_LightProbeHDRCubemap.Init( pCubemapHDR, TEXTURE_GROUP_OTHER ); + + KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" ); + pVMTKeyValues->SetInt( "$ignorez", 1 ); + pVMTKeyValues->SetString( "$envmap", pCubemap ); + pVMTKeyValues->SetInt( "$no_fullbright", 1 ); + pVMTKeyValues->SetInt( "$nocull", 1 ); + m_LightProbeBackground.Init( "SPWP_LightProbeBackground", pVMTKeyValues ); + m_LightProbeBackground->Refresh(); + + pVMTKeyValues = new KeyValues( "UnlitGeneric" ); + pVMTKeyValues->SetInt( "$ignorez", 1 ); + pVMTKeyValues->SetString( "$envmap", pCubemapHDR ); + pVMTKeyValues->SetInt( "$no_fullbright", 1 ); + pVMTKeyValues->SetInt( "$nocull", 1 ); + m_LightProbeHDRBackground.Init( "SPWP_LightProbeBackground_HDR", pVMTKeyValues ); + m_LightProbeHDRBackground->Refresh(); + + const CUtlVector< Vector >& ambientCube = pLightProbe->GetArray( "ambientCube" ); + if ( ambientCube.Count() == 6 ) + { + for ( int i = 0; i < 6; ++i ) + { + m_vecAmbientCube[i].Init( ambientCube[i].x, ambientCube[i].y, ambientCube[i].z, 0.0f ); + } + } + + const CUtlVector< CDmxElement* >& localLights = pLightProbe->GetArray< CDmxElement* >( "localLights" ); + int nLightCount = localLights.Count(); + for ( int i = 0; i < nLightCount; ++i ) + { + if ( m_nLightCount == MAX_LIGHT_COUNT ) + break; + + LightDesc_t *pDesc = &m_Lights[m_nLightCount].m_Desc; + CDmxElement *pLocalLight = localLights[ i ]; + const char *pType = pLocalLight->GetValueString( "name" ); + const Vector& vecColor = pLocalLight->GetValue( "color" ); + + if ( !Q_stricmp( pType, "directional" ) ) + { + pDesc->InitDirectional( pLocalLight->GetValue( "direction" ), vecColor ); + ++m_nLightCount; + continue; + } + + if ( !Q_stricmp( pType, "point" ) ) + { + const Vector& vecAtten = pLocalLight->GetValue( "attenuation" ); + pDesc->InitPoint( pLocalLight->GetValue( "origin" ), vecColor ); + pDesc->m_Attenuation0 = vecAtten.x; + pDesc->m_Attenuation1 = vecAtten.y; + pDesc->m_Attenuation2 = vecAtten.z; + pDesc->m_Range = pLocalLight->GetValue( "maxDistance" ); + pDesc->RecalculateDerivedValues(); + ++m_nLightCount; + continue; + } + + if ( !Q_stricmp( pType, "spot" ) ) + { + const Vector& vecAtten = pLocalLight->GetValue( "attenuation" ); + pDesc->InitSpot( pLocalLight->GetValue( "origin" ), vecColor, vec3_origin, + RAD2DEG ( pLocalLight->GetValue( "theta" ) ), + RAD2DEG ( pLocalLight->GetValue( "phi" ) ) ); + + pDesc->m_Direction = pLocalLight->GetValue( "direction" ); + pDesc->m_Attenuation0 = vecAtten.x; + pDesc->m_Attenuation1 = vecAtten.y; + pDesc->m_Attenuation2 = vecAtten.z; + pDesc->m_Range = pLocalLight->GetValue( "maxDistance" ); + pDesc->m_Falloff = pLocalLight->GetValue( "exponent" ); + pDesc->RecalculateDerivedValues(); + ++m_nLightCount; + continue; + } + } + + if ( nLightCount > 0 ) + { + m_pLightManip = new CPotteryWheelManip( &m_Lights[0].m_LightToWorld ); + } +} + +bool CPotteryWheelPanel::HasLightProbe() const +{ + return m_bHasLightProbe; +} + +ITexture *CPotteryWheelPanel::GetLightProbeCubemap( bool bHDR ) +{ + if ( !m_bHasLightProbe ) + return NULL; + + return bHDR ? m_LightProbeHDRCubemap : m_LightProbeCubemap; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CPotteryWheelPanel::GetCameraFOV( void ) +{ + return m_Camera.m_flFOV; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CPotteryWheelPanel::SetCameraFOV( float flFOV ) +{ + m_Camera.m_flFOV = flFOV; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CPotteryWheelPanel::SetCameraOffset( const Vector &vecOffset ) +{ + m_vecCameraOffset = vecOffset; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CPotteryWheelPanel::GetCameraOffset( Vector &vecOffset ) +{ + vecOffset = m_vecCameraOffset; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CPotteryWheelPanel::SetCameraPositionAndAngles( const Vector &vecPos, const QAngle &angDir, bool syncManipulators ) +{ + SetIdentityMatrix( m_CameraPivot ); + AngleMatrix( angDir, vecPos, m_CameraPivot ); + + UpdateCameraTransform(); + if ( syncManipulators ) + { + SyncManipulation(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CPotteryWheelPanel::GetCameraPositionAndAngles( Vector &vecPos, QAngle &angDir ) +{ + MatrixAngles( m_CameraPivot, angDir, vecPos ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CPotteryWheelPanel::ResetCameraPivot( void ) +{ + SetIdentityMatrix( m_CameraPivot ); +} + +//----------------------------------------------------------------------------- +// Sets the camera to look at the the thing we're spinning around +//----------------------------------------------------------------------------- +void CPotteryWheelPanel::LookAt( float flRadius ) +{ + // Compute the distance to the camera for the object based on its + // radius and fov. + + // since tan( fov/2 ) = f/d + // cos( fov/2 ) = r / r' where r = sphere radius, r' = perp distance from sphere center to max extent of camera + // d/f = r'/d' where d' is distance of camera to sphere + // d' = r' / tan( fov/2 ) * r' = r / ( cos (fov/2) * tan( fov/2 ) ) = r / sin( fov/2 ) + float flFOVx = m_Camera.m_flFOV; + + // Compute fov/2 in radians + flFOVx *= M_PI / 360.0f; + + // Compute an effective fov based on the aspect ratio + // if the height is smaller than the width + int w, h; + GetSize( w, h ); + if ( h < w ) + { + flFOVx = atan( h * tan( flFOVx ) / w ); + } + + m_vecCameraOffset.x = -( flRadius / sin( flFOVx ) ); + UpdateCameraTransform(); +} + + +void CPotteryWheelPanel::LookAt( const Vector &vecCenter, float flRadius ) +{ + MatrixSetColumn( vecCenter, 3, m_CameraPivot ); + LookAt( flRadius ); +} + + +//----------------------------------------------------------------------------- +// Sets up render state in the material system for rendering +//----------------------------------------------------------------------------- +void CPotteryWheelPanel::SetupRenderState( int nDisplayWidth, int nDisplayHeight ) +{ + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + + VMatrix view, projection; + ComputeViewMatrix( &view, m_Camera ); + ComputeProjectionMatrix( &projection, m_Camera, nDisplayWidth, nDisplayHeight ); + + pRenderContext->MatrixMode( MATERIAL_MODEL ); + pRenderContext->LoadIdentity( ); + + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->LoadMatrix( view ); + + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->LoadMatrix( projection ); + + LightDesc_t *pDesc = (LightDesc_t*)stackalloc( m_nLightCount * sizeof(LightDesc_t) ); + for ( int i = 0; i < m_nLightCount; ++i ) + { + pDesc[i] = m_Lights[i].m_Desc; + VectorTransform( m_Lights[i].m_Desc.m_Position, m_Lights[i].m_LightToWorld, pDesc->m_Position ); + VectorRotate( m_Lights[i].m_Desc.m_Direction, m_Lights[i].m_LightToWorld, pDesc->m_Direction ); + VectorNormalize( pDesc->m_Direction ); + pRenderContext->SetLight( i, pDesc[i] ); + } + + LightDesc_t desc; + desc.m_Type = MATERIAL_LIGHT_DISABLE; + int nMaxLightCount = g_pMaterialSystemHardwareConfig->MaxNumLights(); + for ( int i = m_nLightCount; i < nMaxLightCount; ++i ) + { + pRenderContext->SetLight( i, desc ); + } + + pRenderContext->SetAmbientLightCube( m_vecAmbientCube ); + + // FIXME: Remove this! This should automatically happen in DrawModel + // in studiorender. + if ( !g_pStudioRender ) + return; + + VMatrix worldToCamera; + MatrixInverseTR( view, worldToCamera ); + Vector vecOrigin, vecRight, vecUp, vecForward; + MatrixGetColumn( worldToCamera, 0, &vecRight ); + MatrixGetColumn( worldToCamera, 1, &vecUp ); + MatrixGetColumn( worldToCamera, 2, &vecForward ); + MatrixGetColumn( worldToCamera, 3, &vecOrigin ); + g_pStudioRender->SetViewState( vecOrigin, vecRight, vecUp, vecForward ); + + g_pStudioRender->SetLocalLights( m_nLightCount, pDesc ); + g_pStudioRender->SetAmbientLightColors( m_vecAmbientCube ); +} + + +//----------------------------------------------------------------------------- +// Compute the camera world position +//----------------------------------------------------------------------------- +void CPotteryWheelPanel::UpdateCameraTransform( ) +{ + // Set up the render state for the camera + light + matrix3x4_t offset, worldToCamera; + SetIdentityMatrix( offset ); + MatrixSetColumn( m_vecCameraOffset, 3, offset ); + ConcatTransforms( m_CameraPivot, offset, worldToCamera ); + MatrixAngles( worldToCamera, m_Camera.m_angles, m_Camera.m_origin ); +} + +void CPotteryWheelPanel::ComputeCameraTransform( matrix3x4_t *pWorldToCamera ) +{ + AngleMatrix( m_Camera.m_angles, m_Camera.m_origin, *pWorldToCamera ); +} + + +//----------------------------------------------------------------------------- +// Computes the position in the panel of a particular 3D point +//----------------------------------------------------------------------------- +void CPotteryWheelPanel::ComputePanelPosition( const Vector &vecPosition, Vector2D *pPanelPos ) +{ + int w, h; + GetSize( w, h ); + + matrix3x4_t worldToCamera; + ComputeCameraTransform( &worldToCamera ); + MatrixAngles( worldToCamera, m_Camera.m_angles, m_Camera.m_origin ); + ComputeScreenSpacePosition( pPanelPos, vecPosition, m_Camera, w, h ); +} + + +//----------------------------------------------------------------------------- +// Utility method to draw a grid at the 'ground' +//----------------------------------------------------------------------------- +void CPotteryWheelPanel::DrawGrid() +{ + CMatRenderContextPtr pRenderContext( MaterialSystem() ); + pRenderContext->MatrixMode( MATERIAL_MODEL ); + pRenderContext->LoadIdentity( ); + + pRenderContext->Bind( m_Wireframe ); + + IMesh *pMesh = pRenderContext->GetDynamicMesh(); + + int nGridDim = 10; + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_LINES, 2 * nGridDim + 2 ); + + float bounds = 100.0f; + float delta = 2 * bounds / nGridDim; + for ( int i = 0; i < nGridDim + 1; ++i ) + { + float xy = -bounds + delta * i; + + meshBuilder.Position3f( xy, -bounds, 0 ); + meshBuilder.Color4ub( 255, 255, 255, 255 ); + meshBuilder.AdvanceVertex(); + meshBuilder.Position3f( xy, bounds, 0 ); + meshBuilder.Color4ub( 255, 255, 255, 255 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3f( -bounds, xy, 0 ); + meshBuilder.Color4ub( 255, 255, 255, 255 ); + meshBuilder.AdvanceVertex(); + meshBuilder.Position3f( bounds, xy, 0 ); + meshBuilder.Color4ub( 255, 255, 255, 255 ); + meshBuilder.AdvanceVertex(); + } + + meshBuilder.End(); + pMesh->Draw(); +} + + +//----------------------------------------------------------------------------- +// paint it! +//----------------------------------------------------------------------------- +void CPotteryWheelPanel::Paint() +{ + int iWidth, iHeight; + GetSize( iWidth, iHeight ); + + int screenw, screenh; + vgui::surface()->GetScreenSize( screenw, screenh ); + + int windowposx = 0, windowposy = 0; + GetPos( windowposx, windowposy ); + + int startx = 0, starty = 0; + if( windowposx < 0 ) + { + startx = -windowposx; + iWidth -= startx; + } + if ( windowposy < 0 ) + { + starty = -windowposy; + iHeight -= starty; + } + + int w, h; + GetSize( w, h ); + + vgui::MatSystemSurface()->Begin3DPaint( 0, 0, w, h, m_bRenderToTexture ); + + if ( m_pCurrentManip ) + { + m_pCurrentManip->SetViewportSize( iWidth, iHeight ); + } + + // Set up the render state for the camera + light + SetupRenderState( iWidth, iHeight ); + + CMatRenderContextPtr pRenderContext( vgui::MaterialSystem() ); + + if ( m_bUseParentBG && GetParent() ) + { + Color bgCol = GetParent()->GetBgColor(); + pRenderContext->ClearColor4ub( bgCol.r(), bgCol.g(), bgCol.b(), bgCol.a() ); + } + else + { + pRenderContext->ClearColor4ub( m_ClearColor.r(), m_ClearColor.g(), m_ClearColor.b(), m_ClearColor.a() ); + } + pRenderContext->ClearBuffers( m_bRenderToTexture, true ); + + pRenderContext->CullMode( MATERIAL_CULLMODE_CCW ); + pRenderContext->SetIntRenderingParameter( INT_RENDERPARM_WRITE_DEPTH_TO_DESTALPHA, false ); + + if ( HasLightProbe() ) + { + IMaterial *pMaterial = ( vgui::MaterialSystemHardwareConfig()->GetHDRType() == HDR_TYPE_NONE ) ? + m_LightProbeBackground : m_LightProbeHDRBackground; + + RenderBox( m_Camera.m_origin, vec3_angle, Vector( -100, -100, -100 ), Vector( 100, 100, 100 ), + Color( 255, 255, 255, 255 ), pMaterial, true ); + } + + OnPaint3D(); + + pRenderContext->CullMode( MATERIAL_CULLMODE_CW ); + + vgui::MatSystemSurface()->End3DPaint( ); +} + + +//----------------------------------------------------------------------------- +// called when we're ticked... +//----------------------------------------------------------------------------- +void CPotteryWheelPanel::OnTick() +{ + BaseClass::OnTick(); + if ( m_pCurrentManip ) + { + m_pCurrentManip->OnTick(); + UpdateCameraTransform(); + } +} + + +//----------------------------------------------------------------------------- +// input +//----------------------------------------------------------------------------- +void CPotteryWheelPanel::OnKeyCodePressed(KeyCode code) +{ + if ( m_pCurrentManip ) + { + switch( code ) + { + case KEY_RSHIFT: + case KEY_LSHIFT: + // start translate mode + AcceptManipulation( false ); + EnterManipulationMode( CAMERA_TRANSLATE, false ); + break; + + case KEY_RCONTROL: + case KEY_LCONTROL: + // start light mode + AcceptManipulation( false ); + EnterManipulationMode( LIGHT_MODE, false ); + break; + } + } + + BaseClass::OnKeyCodePressed( code ); +} + + + +//----------------------------------------------------------------------------- +// Purpose: soaks up any remaining messages +//----------------------------------------------------------------------------- +void CPotteryWheelPanel::OnKeyCodeReleased(KeyCode code) +{ + if ( m_pCurrentManip ) + { + switch( code ) + { + case KEY_RSHIFT: + case KEY_LSHIFT: + case KEY_RCONTROL: + case KEY_LCONTROL: + { + // stop manipulation mode + AcceptManipulation( false ); + switch ( m_nCaptureMouseCode ) + { + default: + case MOUSE_LEFT: + EnterManipulationMode( CAMERA_ROTATE, false ); + break; + + case MOUSE_MIDDLE: + EnterManipulationMode( CAMERA_TRANSLATE, false ); + break; + + case MOUSE_RIGHT: + EnterManipulationMode( CAMERA_ZOOM, false ); + break; + } + } + break; + } + } + BaseClass::OnKeyCodeReleased( code ); +} + +void CPotteryWheelPanel::OnMousePressed( vgui::MouseCode code ) +{ + if ( m_pCurrentManip ) + return; + + RequestFocus(); + + if ( input()->IsKeyDown( KEY_RSHIFT ) || input()->IsKeyDown( KEY_LSHIFT ) ) + { + EnterManipulationMode( CAMERA_TRANSLATE, true, code ); + } + else if ( input()->IsKeyDown( KEY_RCONTROL ) || input()->IsKeyDown( KEY_LCONTROL ) ) + { + EnterManipulationMode( LIGHT_MODE, true, code ); + } + else + { + switch ( code ) + { + case MOUSE_LEFT: + EnterManipulationMode( CAMERA_ROTATE, true, code ); + break; + + case MOUSE_MIDDLE: + EnterManipulationMode( CAMERA_TRANSLATE, true, code ); + break; + + case MOUSE_RIGHT: + EnterManipulationMode( CAMERA_ZOOM, true, code ); + break; + } + } + + BaseClass::OnMousePressed( code ); +} + +void CPotteryWheelPanel::OnMouseReleased( vgui::MouseCode code ) +{ + int x, y; + input()->GetCursorPos( x, y ); + ScreenToLocal( x, y ); + + AcceptManipulation(); + + BaseClass::OnMouseReleased( code ); +} + +void CPotteryWheelPanel::OnCursorMoved( int x, int y ) +{ + if ( m_pCurrentManip ) + { + if ( WarpMouse( x, y ) ) + { + m_pCurrentManip->OnCursorMoved( x, y ); + } + } + + BaseClass::OnCursorMoved( x, y ); +} + +void CPotteryWheelPanel::OnMouseWheeled( int delta ) +{ + if ( m_pCurrentManip ) + { + m_pCurrentManip->OnMouseWheeled( delta ); + } + + BaseClass::OnMouseWheeled( delta ); +} + + +void CPotteryWheelPanel::EnterManipulationMode( ManipulationMode_t manipMode, bool bMouseCapture, vgui::MouseCode mouseCode /* = -1 */ ) +{ + switch ( manipMode ) + { + case CAMERA_ROTATE: + m_pCurrentManip = m_pCameraRotate; + break; + + case CAMERA_TRANSLATE: + m_pCurrentManip = m_pCameraTranslate; + break; + + case CAMERA_ZOOM: + m_pCurrentManip = m_pCameraZoom; + break; + + case LIGHT_MODE: + m_pCurrentManip = m_pLightManip; + break; + } + + if ( !m_pCurrentManip ) + return; + + m_pCurrentManip->OnBeginManipulation(); + + m_xoffset = m_yoffset = 0; + + // Warp the mouse to the center of the screen + int width, height; + GetSize( width, height ); + int x = width / 2; + int y = height / 2; + + if ( bMouseCapture ) + { + input()->GetCursorPos( m_nManipStartX, m_nManipStartY ); + EnableMouseCapture( true, mouseCode ); + + int xpos = x; + int ypos = y; + LocalToScreen( xpos, ypos ); + input()->SetCursorPos( xpos, ypos ); + } + + m_pCurrentManip->OnMousePressed( mouseCode, x, y ); +} + +void CPotteryWheelPanel::AcceptManipulation( bool bReleaseMouseCapture ) +{ + if ( m_pCurrentManip ) + { + m_pCurrentManip->OnAcceptManipulation(); + + if ( bReleaseMouseCapture ) + { + EnableMouseCapture( false ); + input()->SetCursorPos( m_nManipStartX, m_nManipStartY ); + } + + m_pCurrentManip = NULL; + } +} + +void CPotteryWheelPanel::CancelManipulation() +{ + if ( m_pCurrentManip ) + { + m_pCurrentManip->OnCancelManipulation(); + + EnableMouseCapture( false ); + input()->SetCursorPos( m_nManipStartX, m_nManipStartY ); + + m_pCurrentManip = NULL; + } + +} + +void CPotteryWheelPanel::ApplyManipulation() +{ + if ( dynamic_cast< CRotationManipulator * >( m_pCameraRotate ) ) + { + dynamic_cast< CRotationManipulator * >( m_pCameraRotate )->UpdateTransform(); + } + UpdateCameraTransform(); +} + +void CPotteryWheelPanel::SyncManipulation() +{ + if ( dynamic_cast< CRotationManipulator * >( m_pCameraRotate ) ) + { + dynamic_cast< CRotationManipulator * >( m_pCameraRotate )->UpdateFromMatrix(); + } +} + +void CPotteryWheelPanel::OnMouseCaptureLost() +{ + SetCursor( vgui::dc_arrow ); + m_nCaptureMouseCode = vgui::MouseCode( -1 ); +} + +void CPotteryWheelPanel::EnableMouseCapture( bool enable, vgui::MouseCode mouseCode /* = -1 */ ) +{ + if ( enable ) + { + m_nCaptureMouseCode = mouseCode; + SetCursor( vgui::dc_none ); + input()->SetMouseCaptureEx( GetVPanel(), m_nCaptureMouseCode ); + } + else + { + m_nCaptureMouseCode = vgui::MouseCode( -1 ); + input()->SetMouseCapture( (VPANEL)0 ); + SetCursor( vgui::dc_arrow ); + } +} + +bool CPotteryWheelPanel::WarpMouse( int &x, int &y ) +{ + // Re-force capture if it was lost... + if ( input()->GetMouseCapture() != GetVPanel() ) + { + input()->GetCursorPos( m_nManipStartX, m_nManipStartY ); + EnableMouseCapture( true, m_nCaptureMouseCode ); + } + + int width, height; + GetSize( width, height ); + + int centerx = width / 2; + int centery = height / 2; + + // skip this event + if ( x == centerx && y == centery ) + return false; + + int xpos = centerx; + int ypos = centery; + LocalToScreen( xpos, ypos ); + +#if defined( DX_TO_GL_ABSTRACTION ) + // + // Really reset the cursor to the center for the PotteryWheel Control + // + // In TF2's edit loadout dialog there is a character model that you can rotate + // around using the mouse. This control resets the cursor to the center of the window + // after each mouse move. Except the input()->SetCursorPos results (after a lot of redirection) to + // vgui/matsurface/Cursor.cpp function CursorSetPos but it has a (needed) test to not move the + // cursor if it's currently hidden. Rather than change all the levels between here and there + // to support a flag, we are just jumping to the chase and directly calling the inputsystem + // SetCursorPosition on OpenGL platforms + // + g_pInputSystem->SetCursorPosition( xpos, ypos ); +#else + input()->SetCursorPos( xpos, ypos ); +#endif + + int dx = x - centerx; + int dy = y - centery; + + x += m_xoffset; + y += m_yoffset; + + m_xoffset += dx; + m_yoffset += dy; + + return true; +} diff --git a/vgui2/matsys_controls/proceduraltexturepanel.cpp b/vgui2/matsys_controls/proceduraltexturepanel.cpp new file mode 100644 index 00000000..a198dd5f --- /dev/null +++ b/vgui2/matsys_controls/proceduraltexturepanel.cpp @@ -0,0 +1,239 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#include "matsys_controls/proceduraltexturepanel.h" +#include "matsys_controls/matsyscontrols.h" +#include "materialsystem/imaterialsystem.h" +#include "materialsystem/itexture.h" +#include "VGuiMatSurface/IMatSystemSurface.h" +#include "tier1/KeyValues.h" +#include "pixelwriter.h" + + +using namespace vgui; + + +//----------------------------------------------------------------------------- +// constructor +//----------------------------------------------------------------------------- +CProceduralTexturePanel::CProceduralTexturePanel( vgui::Panel *pParent, const char *pName ) : BaseClass( pParent, pName ) +{ + m_pImageBuffer = NULL; + m_bMaintainProportions = false; + m_bUsePaintRect = false; + m_PaintRect.x = m_PaintRect.y = 0; + m_PaintRect.width = m_PaintRect.height = 0; +} + +CProceduralTexturePanel::~CProceduralTexturePanel() +{ + CleanUp(); +} + + +//----------------------------------------------------------------------------- +// initialization, shutdown +//----------------------------------------------------------------------------- +bool CProceduralTexturePanel::Init( int nWidth, int nHeight, bool bAllocateImageBuffer ) +{ + m_nWidth = nWidth; + m_nHeight = nHeight; + if ( bAllocateImageBuffer ) + { + m_pImageBuffer = new BGRA8888_t[nWidth * nHeight]; + } + + m_TextureSubRect.x = m_TextureSubRect.y = 0; + m_TextureSubRect.width = nWidth; + m_TextureSubRect.height = nHeight; + + char pTemp[512]; + Q_snprintf( pTemp, 512, "__%s", GetName() ); + + ITexture *pTex = MaterialSystem()->CreateProceduralTexture( pTemp, TEXTURE_GROUP_VGUI, + m_nWidth, m_nHeight, IMAGE_FORMAT_BGRX8888, + TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT | TEXTUREFLAGS_NOMIP | + TEXTUREFLAGS_NOLOD | TEXTUREFLAGS_PROCEDURAL | TEXTUREFLAGS_SINGLECOPY ); + pTex->SetTextureRegenerator( this ); + m_ProceduralTexture.Init( pTex ); + + KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" ); + pVMTKeyValues->SetString( "$basetexture", pTemp ); + pVMTKeyValues->SetInt( "$nocull", 1 ); + pVMTKeyValues->SetInt( "$nodebug", 1 ); + m_ProceduralMaterial.Init( MaterialSystem()->CreateMaterial( pTemp, pVMTKeyValues )); + + m_nTextureID = MatSystemSurface()->CreateNewTextureID( false ); + MatSystemSurface()->DrawSetTextureMaterial( m_nTextureID, m_ProceduralMaterial ); + return true; +} + +void CProceduralTexturePanel::Shutdown() +{ + CleanUp(); +} + + +//----------------------------------------------------------------------------- +// Maintain proportions when drawing +//----------------------------------------------------------------------------- +void CProceduralTexturePanel::MaintainProportions( bool bEnable ) +{ + m_bMaintainProportions = bEnable; +} + + +//----------------------------------------------------------------------------- +// Returns the image buffer + dimensions +//----------------------------------------------------------------------------- +void CProceduralTexturePanel::CleanUp() +{ + if ( (ITexture*)m_ProceduralTexture ) + { + m_ProceduralTexture->SetTextureRegenerator( NULL ); + } + m_ProceduralTexture.Shutdown(); + m_ProceduralMaterial.Shutdown(); + + if ( m_pImageBuffer ) + { + delete[] m_pImageBuffer; + m_pImageBuffer = NULL; + } +} + + +//----------------------------------------------------------------------------- +// Default implementation of regenerate texture bits +//----------------------------------------------------------------------------- +void CProceduralTexturePanel::RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect ) +{ + Assert( m_pImageBuffer ); + Assert( pVTFTexture->FrameCount() == 1 ); + Assert( pVTFTexture->FaceCount() == 1 ); + Assert( !pTexture->IsMipmapped() ); + + int nWidth, nHeight, nDepth; + pVTFTexture->ComputeMipLevelDimensions( 0, &nWidth, &nHeight, &nDepth ); + Assert( nDepth == 1 ); + Assert( nWidth == m_nWidth && nHeight == m_nHeight ); + + CPixelWriter pixelWriter; + pixelWriter.SetPixelMemory( pVTFTexture->Format(), + pVTFTexture->ImageData( 0, 0, 0 ), pVTFTexture->RowSizeInBytes( 0 ) ); + + for ( int y = 0; y < nHeight; ++y ) + { + pixelWriter.Seek( 0, y ); + BGRA8888_t *pTexel = &m_pImageBuffer[y * m_nWidth]; + for ( int x = 0; x < nWidth; ++x, ++pTexel ) + { + pixelWriter.WritePixel( pTexel->r, pTexel->g, pTexel->b, pTexel->a ); + } + } +} + + +//----------------------------------------------------------------------------- +// Returns the image buffer + dimensions +//----------------------------------------------------------------------------- +BGRA8888_t *CProceduralTexturePanel::GetImageBuffer() +{ + Assert( m_pImageBuffer ); + return m_pImageBuffer; +} + +int CProceduralTexturePanel::GetImageWidth() const +{ + return m_nWidth; +} + +int CProceduralTexturePanel::GetImageHeight() const +{ + return m_nHeight; +} + + +//----------------------------------------------------------------------------- +// Sets the paint rect +//----------------------------------------------------------------------------- +void CProceduralTexturePanel::SetPaintRect( const Rect_t *pPaintRect ) +{ + m_bUsePaintRect = ( pPaintRect != NULL ); + if ( m_bUsePaintRect ) + { + m_PaintRect = *pPaintRect; + } +} + + +//----------------------------------------------------------------------------- +// Sets the draw rect +//----------------------------------------------------------------------------- +void CProceduralTexturePanel::SetTextureSubRect( const Rect_t &subRect ) +{ + m_TextureSubRect = subRect; +} + + +//----------------------------------------------------------------------------- +// Redownloads the procedural texture +//----------------------------------------------------------------------------- +void CProceduralTexturePanel::DownloadTexture() +{ + m_ProceduralTexture->Download(); +} + + +//----------------------------------------------------------------------------- +// Paints the texture +//----------------------------------------------------------------------------- +void CProceduralTexturePanel::Paint( void ) +{ + vgui::surface()->DrawSetTexture( m_nTextureID ); + vgui::surface()->DrawSetColor( 255, 255, 255, 255 ); + + int x = 0; + int y = 0; + int w, h; + GetSize( w, h ); + if ( m_bUsePaintRect ) + { + x = m_PaintRect.x; + y = m_PaintRect.y; + w = m_PaintRect.width; + h = m_PaintRect.height; + } + + if ( m_bMaintainProportions ) + { + if ( m_TextureSubRect.width > m_TextureSubRect.height ) + { + h = w * m_TextureSubRect.height / m_TextureSubRect.width; + } + else + { + w = h * m_TextureSubRect.width / m_TextureSubRect.height; + } + } + + // Rotated version of the bitmap! + // Rotate about the center of the bitmap + vgui::Vertex_t verts[4]; + verts[0].m_Position.Init( x, y ); + verts[0].m_TexCoord.Init( (float)m_TextureSubRect.x / m_nWidth, (float)m_TextureSubRect.y / m_nHeight ); + + verts[1].m_Position.Init( w+x, y ); + verts[1].m_TexCoord.Init( (float)(m_TextureSubRect.x + m_TextureSubRect.width) / m_nWidth, (float)m_TextureSubRect.y / m_nHeight ); + + verts[2].m_Position.Init( w+x, h+y ); + verts[2].m_TexCoord.Init( (float)(m_TextureSubRect.x + m_TextureSubRect.width) / m_nWidth, (float)(m_TextureSubRect.y + m_TextureSubRect.height) / m_nHeight ); + + verts[3].m_Position.Init( x, h+y ); + verts[3].m_TexCoord.Init( (float)m_TextureSubRect.x / m_nWidth, (float)(m_TextureSubRect.y + m_TextureSubRect.height) / m_nHeight ); + + vgui::surface()->DrawTexturedPolygon( 4, verts ); +} diff --git a/vgui2/matsys_controls/sequencepicker.cpp b/vgui2/matsys_controls/sequencepicker.cpp new file mode 100644 index 00000000..7cc7b034 --- /dev/null +++ b/vgui2/matsys_controls/sequencepicker.cpp @@ -0,0 +1,485 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "matsys_controls/sequencepicker.h" + +#include "tier1/utldict.h" +#include "tier1/KeyValues.h" +#include "studio.h" +#include "vgui/IInput.h" +#include "vgui/ISurface.h" +#include "vgui_controls/Splitter.h" +#include "vgui_controls/PropertyPage.h" +#include "vgui_controls/PropertySheet.h" +#include "vgui_controls/ListPanel.h" +#include "vgui_controls/Button.h" +#include "matsys_controls/matsyscontrols.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +using namespace vgui; + + +//----------------------------------------------------------------------------- +// +// Sequence Picker +// +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// Sort by sequence name +//----------------------------------------------------------------------------- +static int __cdecl SequenceSortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 ) +{ + const char *string1 = item1.kv->GetString("sequence"); + const char *string2 = item2.kv->GetString("sequence"); + return stricmp( string1, string2 ); +} + +static int __cdecl ActivitySortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 ) +{ + const char *string1 = item1.kv->GetString("activity"); + const char *string2 = item2.kv->GetString("activity"); + return stricmp( string1, string2 ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CSequencePicker::CSequencePicker( vgui::Panel *pParent, int nFlags ) : BaseClass( pParent, "SequencePicker" ) +{ + m_hSelectedMDL = MDLHANDLE_INVALID; + + // property sheet - revisions, changes, etc. + m_pPreviewSplitter = new Splitter( this, "PreviewSplitter", SPLITTER_MODE_HORIZONTAL, 1 ); + + vgui::Panel *pSplitterTopSide = m_pPreviewSplitter->GetChild( 0 ); + vgui::Panel *pSplitterBottomSide = m_pPreviewSplitter->GetChild( 1 ); + + // MDL preview + m_pMDLPreview = new CMDLPanel( pSplitterTopSide, "MDLPreview" ); + SetSkipChildDuringPainting( m_pMDLPreview ); + + m_pViewsSheet = new vgui::PropertySheet( pSplitterBottomSide, "ViewsSheet" ); + m_pViewsSheet->AddActionSignalTarget( this ); + + // sequences + m_pSequencesPage = NULL; + m_pSequencesList = NULL; + if ( nFlags & PICK_SEQUENCES ) + { + m_pSequencesPage = new PropertyPage( m_pViewsSheet, "SequencesPage" ); + m_pViewsSheet->AddPage( m_pSequencesPage, "Sequences" ); + m_pSequencesList = new ListPanel( m_pSequencesPage, "SequencesList" ); + m_pSequencesList->AddColumnHeader( 0, "sequence", "sequence", 52, 0 ); + m_pSequencesList->AddActionSignalTarget( this ); + m_pSequencesList->SetSelectIndividualCells( true ); + m_pSequencesList->SetEmptyListText(".MDL file contains no activities"); + m_pSequencesList->SetDragEnabled( true ); + m_pSequencesList->SetAutoResize( Panel::PIN_TOPLEFT, Panel::AUTORESIZE_DOWNANDRIGHT, 0, 0, 0, 0 ); + m_pSequencesList->SetSortFunc( 0, SequenceSortFunc ); + m_pSequencesList->SetSortColumn( 0 ); + } + + // Activities + m_pActivitiesPage = NULL; + m_pActivitiesList = NULL; + if ( nFlags & PICK_ACTIVITIES ) + { + m_pActivitiesPage = new PropertyPage( m_pViewsSheet, "ActivitiesPage" ); + m_pViewsSheet->AddPage( m_pActivitiesPage, "Activities" ); + m_pActivitiesList = new ListPanel( m_pActivitiesPage, "ActivitiesList" ); + m_pActivitiesList->AddColumnHeader( 0, "activity", "activity", 52, 0 ); + m_pActivitiesList->AddActionSignalTarget( this ); + m_pActivitiesList->SetSelectIndividualCells( true ); + m_pActivitiesList->SetEmptyListText( ".MDL file contains no activities" ); + m_pActivitiesList->SetDragEnabled( true ); + m_pActivitiesList->SetAutoResize( Panel::PIN_TOPLEFT, Panel::AUTORESIZE_DOWNANDRIGHT, 0, 0, 0, 0 ); + m_pActivitiesList->SetSortFunc( 0, ActivitySortFunc ); + m_pActivitiesList->SetSortColumn( 0 ); + } + + // Load layout settings; has to happen before pinning occurs in code + LoadControlSettingsAndUserConfig( "resource/sequencepicker.res" ); + + SETUP_PANEL( this ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Destructor +//----------------------------------------------------------------------------- +CSequencePicker::~CSequencePicker() +{ +} + + +//----------------------------------------------------------------------------- +// Performs layout +//----------------------------------------------------------------------------- +void CSequencePicker::PerformLayout() +{ + // NOTE: This call should cause auto-resize to occur + // which should fix up the width of the panels + BaseClass::PerformLayout(); + + int w, h; + GetSize( w, h ); + + // Layout the mdl splitter + m_pPreviewSplitter->SetBounds( 0, 0, w, h ); +} + + +//----------------------------------------------------------------------------- +// Purpose: rebuilds the list of activities + sequences +//----------------------------------------------------------------------------- +void CSequencePicker::RefreshActivitiesAndSequencesList() +{ + if ( m_pActivitiesList ) + { + m_pActivitiesList->RemoveAll(); + } + + if ( m_pSequencesList ) + { + m_pSequencesList->RemoveAll(); + } + + m_pMDLPreview->SetSequence( 0 ); + + if ( m_hSelectedMDL == MDLHANDLE_INVALID ) + return; + + studiohdr_t *hdr = vgui::MDLCache()->GetStudioHdr( m_hSelectedMDL ); + + CUtlDict activityNames( true, 0, hdr->GetNumSeq() ); + + for (int j = 0; j < hdr->GetNumSeq(); j++) + { + if ( /*g_viewerSettings.showHidden ||*/ !(hdr->pSeqdesc(j).flags & STUDIO_HIDDEN)) + { + const char *pActivityName = hdr->pSeqdesc(j).pszActivityName(); + if ( m_pActivitiesList && pActivityName && pActivityName[0] ) + { + // Multiple sequences can have the same activity name; only add unique activity names + if ( activityNames.Find( pActivityName ) == activityNames.InvalidIndex() ) + { + KeyValues *pkv = new KeyValues("node", "activity", pActivityName ); + int nItemID = m_pActivitiesList->AddItem( pkv, 0, false, false ); + + KeyValues *pDrag = new KeyValues( "drag", "text", pActivityName ); + pDrag->SetString( "texttype", "activityName" ); + pDrag->SetString( "mdl", vgui::MDLCache()->GetModelName( m_hSelectedMDL ) ); + m_pActivitiesList->SetItemDragData( nItemID, pDrag ); + + activityNames.Insert( pActivityName, j ); + } + } + + const char *pSequenceName = hdr->pSeqdesc(j).pszLabel(); + if ( m_pSequencesList && pSequenceName && pSequenceName[0] ) + { + KeyValues *pkv = new KeyValues("node", "sequence", pSequenceName); + int nItemID = m_pSequencesList->AddItem( pkv, 0, false, false ); + + KeyValues *pDrag = new KeyValues( "drag", "text", pSequenceName ); + pDrag->SetString( "texttype", "sequenceName" ); + pDrag->SetString( "mdl", vgui::MDLCache()->GetModelName( m_hSelectedMDL ) ); + m_pSequencesList->SetItemDragData( nItemID, pDrag ); + } + } + } + + if ( m_pSequencesList ) + { + m_pSequencesList->SortList(); + } + + if ( m_pActivitiesList ) + { + m_pActivitiesList->SortList(); + } +} + + +/* +//----------------------------------------------------------------------------- +// Purpose: Selects an sequence based on an activity +//----------------------------------------------------------------------------- +int SelectWeightedSequence( studiohdr_t *pstudiohdr, int activity, int curSequence ) +{ + if (! pstudiohdr) + return 0; + + VerifySequenceIndex( pstudiohdr ); + + int weighttotal = 0; + int seq = ACTIVITY_NOT_AVAILABLE; + int weight = 0; + for (int i = 0; i < pstudiohdr->GetNumSeq(); i++) + { + int curActivity = GetSequenceActivity( pstudiohdr, i, &weight ); + if (curActivity == activity) + { + if ( curSequence == i && weight < 0 ) + { + seq = i; + break; + } + weighttotal += iabs(weight); + + int randomValue; + if ( IsInPrediction() ) + randomValue = SharedRandomInt( "SelectWeightedSequence", 0, weighttotal - 1, i ); + else + randomValue = RandomInt( 0, weighttotal - 1 ); + + if (!weighttotal || randomValue < iabs(weight)) + seq = i; + } + } + + return seq; +} +*/ + + +//----------------------------------------------------------------------------- +// Gets the selected activity/sequence +//----------------------------------------------------------------------------- +CSequencePicker::PickType_t CSequencePicker::GetSelectedSequenceType( ) +{ + if ( m_pSequencesPage && ( m_pViewsSheet->GetActivePage() == m_pSequencesPage ) ) + return PICK_SEQUENCES; + if ( m_pActivitiesPage && ( m_pViewsSheet->GetActivePage() == m_pActivitiesPage ) ) + return PICK_ACTIVITIES; + return PICK_NONE; +} + +const char *CSequencePicker::GetSelectedSequenceName( ) +{ + if ( m_pSequencesPage && ( m_pViewsSheet->GetActivePage() == m_pSequencesPage ) ) + { + int nIndex = m_pSequencesList->GetSelectedItem( 0 ); + if ( nIndex >= 0 ) + { + KeyValues *pkv = m_pSequencesList->GetItem( nIndex ); + return pkv->GetString( "sequence", NULL ); + } + return NULL; + } + + if ( m_pActivitiesPage && ( m_pViewsSheet->GetActivePage() == m_pActivitiesPage ) ) + { + int nIndex = m_pActivitiesList->GetSelectedItem( 0 ); + if ( nIndex >= 0 ) + { + KeyValues *pkv = m_pActivitiesList->GetItem( nIndex ); + return pkv->GetString( "activity", NULL ); + } + return NULL; + } + + return NULL; +} + + +//----------------------------------------------------------------------------- +// Plays the selected activity +//----------------------------------------------------------------------------- +void CSequencePicker::PlayActivity( const char *pActivityName ) +{ + studiohdr_t *pstudiohdr = vgui::MDLCache()->GetStudioHdr( m_hSelectedMDL ); + for ( int i = 0; i < pstudiohdr->GetNumSeq(); i++ ) + { + mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i ); + if ( stricmp( seqdesc.pszActivityName(), pActivityName ) == 0 ) + { + // FIXME: Add weighted sequence selection logic? + m_pMDLPreview->SetSequence( i ); + break; + } + } +} + + +//----------------------------------------------------------------------------- +// Plays the selected sequence +//----------------------------------------------------------------------------- +void CSequencePicker::PlaySequence( const char *pSequenceName ) +{ + studiohdr_t *pstudiohdr = vgui::MDLCache()->GetStudioHdr( m_hSelectedMDL ); + for (int i = 0; i < pstudiohdr->GetNumSeq(); i++) + { + mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i ); + if ( !Q_stricmp( seqdesc.pszLabel(), pSequenceName ) ) + { + m_pMDLPreview->SetSequence( i ); + break; + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Called when a page is shown +//----------------------------------------------------------------------------- +void CSequencePicker::OnPageChanged( ) +{ + if ( m_pSequencesPage && ( m_pViewsSheet->GetActivePage() == m_pSequencesPage ) ) + { + const char *pSequenceName = GetSelectedSequenceName(); + if ( pSequenceName ) + { + PlaySequence( pSequenceName ); + PostActionSignal( new KeyValues( "SequencePreviewChanged", "sequence", pSequenceName ) ); + } + return; + } + + if ( m_pActivitiesPage && ( m_pViewsSheet->GetActivePage() == m_pActivitiesPage ) ) + { + const char *pActivityName = GetSelectedSequenceName(); + if ( pActivityName ) + { + PlayActivity( pActivityName ); + PostActionSignal( new KeyValues( "SequencePreviewChanged", "activity", pActivityName ) ); + } + return; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: refreshes dialog on text changing +//----------------------------------------------------------------------------- +void CSequencePicker::OnItemSelected( KeyValues *kv ) +{ + Panel *pPanel = (Panel *)kv->GetPtr("panel", NULL); + if ( m_pSequencesList && (pPanel == m_pSequencesList ) ) + { + const char *pSequenceName = GetSelectedSequenceName(); + if ( pSequenceName ) + { + PlaySequence( pSequenceName ); + PostActionSignal( new KeyValues( "SequencePreviewChanged", "sequence", pSequenceName ) ); + } + return; + } + + if ( m_pActivitiesList && ( pPanel == m_pActivitiesList ) ) + { + const char *pActivityName = GetSelectedSequenceName(); + if ( pActivityName ) + { + PlayActivity( pActivityName ); + PostActionSignal( new KeyValues( "SequencePreviewChanged", "activity", pActivityName ) ); + } + return; + } +} + + +//----------------------------------------------------------------------------- +// Sets the MDL to select sequences in +//----------------------------------------------------------------------------- +void CSequencePicker::SetMDL( const char *pMDLName ) +{ + m_hSelectedMDL = pMDLName ? vgui::MDLCache()->FindMDL( pMDLName ) : MDLHANDLE_INVALID; + if ( vgui::MDLCache()->IsErrorModel( m_hSelectedMDL ) ) + { + m_hSelectedMDL = MDLHANDLE_INVALID; + } + m_pMDLPreview->SetMDL( m_hSelectedMDL ); + m_pMDLPreview->LookAtMDL(); + RefreshActivitiesAndSequencesList(); +} + + +//----------------------------------------------------------------------------- +// +// Purpose: Modal picker frame +// +//----------------------------------------------------------------------------- +CSequencePickerFrame::CSequencePickerFrame( vgui::Panel *pParent, int nFlags ) : BaseClass( pParent, "SequencePickerFrame" ) +{ + SetDeleteSelfOnClose( true ); + m_pPicker = new CSequencePicker( this, nFlags ); + m_pPicker->AddActionSignalTarget( this ); + m_pOpenButton = new Button( this, "OpenButton", "#FileOpenDialog_Open", this, "Open" ); + m_pCancelButton = new Button( this, "CancelButton", "#FileOpenDialog_Cancel", this, "Cancel" ); + SetBlockDragChaining( true ); + + LoadControlSettingsAndUserConfig( "resource/sequencepickerframe.res" ); + + m_pOpenButton->SetEnabled( false ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Activate the dialog +//----------------------------------------------------------------------------- +void CSequencePickerFrame::DoModal( const char *pMDLName ) +{ + m_pPicker->SetMDL( pMDLName ); + BaseClass::DoModal(); +} + + +//----------------------------------------------------------------------------- +// On mdl preview changed +//----------------------------------------------------------------------------- +void CSequencePickerFrame::OnSequencePreviewChanged( KeyValues *pKeyValues ) +{ + const char *pSequence = pKeyValues->GetString( "sequence", NULL ); + const char *pActivity = pKeyValues->GetString( "activity", NULL ); + m_pOpenButton->SetEnabled( pSequence || pActivity ); +} + + +//----------------------------------------------------------------------------- +// On command +//----------------------------------------------------------------------------- +void CSequencePickerFrame::OnCommand( const char *pCommand ) +{ + if ( !Q_stricmp( pCommand, "Open" ) ) + { + CSequencePicker::PickType_t type = m_pPicker->GetSelectedSequenceType( ); + if (( type == CSequencePicker::PICK_SEQUENCES ) || ( type == CSequencePicker::PICK_ACTIVITIES )) + { + const char *pSequenceName = m_pPicker->GetSelectedSequenceName(); + if ( pSequenceName ) + { + if ( type == CSequencePicker::PICK_SEQUENCES ) + { + PostActionSignal( new KeyValues("SequenceSelected", "sequence", pSequenceName ) ); + } + else + { + PostActionSignal( new KeyValues("SequenceSelected", "activity", pSequenceName ) ); + } + CloseModal(); + return; + } + } + return; + } + + if ( !Q_stricmp( pCommand, "Cancel" ) ) + { + CloseModal(); + return; + } + + BaseClass::OnCommand( pCommand ); +} + + diff --git a/vgui2/matsys_controls/tgapreviewpanel.cpp b/vgui2/matsys_controls/tgapreviewpanel.cpp new file mode 100644 index 00000000..c91b6f35 --- /dev/null +++ b/vgui2/matsys_controls/tgapreviewpanel.cpp @@ -0,0 +1,72 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#include "matsys_controls/tgapreviewpanel.h" +#include "bitmap/tgaloader.h" +#include "tier1/utlbuffer.h" +#include "filesystem.h" + +using namespace vgui; + + +//----------------------------------------------------------------------------- +// +// TGA Preview panel +// +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// constructor +//----------------------------------------------------------------------------- +CTGAPreviewPanel::CTGAPreviewPanel( vgui::Panel *pParent, const char *pName ) : + BaseClass( pParent, pName ) +{ +} + + +//----------------------------------------------------------------------------- +// Sets the current TGA +//----------------------------------------------------------------------------- +void CTGAPreviewPanel::SetTGA( const char *pFullPath ) +{ + int nWidth, nHeight; + ImageFormat format; + float flGamma; + + CUtlBuffer buf; + if ( !g_pFullFileSystem->ReadFile( pFullPath, NULL, buf ) ) + { + Warning( "Can't open TGA file: %s\n", pFullPath ); + return; + } + + TGALoader::GetInfo( buf, &nWidth, &nHeight, &format, &flGamma ); + + Shutdown(); + Init( nWidth, nHeight, true ); + m_TGAName = pFullPath; + + buf.SeekGet( CUtlBuffer::SEEK_HEAD, 0 ); + if ( !TGALoader::Load( (unsigned char*)GetImageBuffer(), buf, + nWidth, nHeight, IMAGE_FORMAT_BGRA8888, flGamma, false ) ) + { + Shutdown(); + } + else + { + DownloadTexture(); + } +} + + +//----------------------------------------------------------------------------- +// Gets the current TGA +//----------------------------------------------------------------------------- +const char *CTGAPreviewPanel::GetTGA() const +{ + return m_TGAName; +} diff --git a/vgui2/matsys_controls/vmtpanel.cpp b/vgui2/matsys_controls/vmtpanel.cpp new file mode 100644 index 00000000..2b37f1f5 --- /dev/null +++ b/vgui2/matsys_controls/vmtpanel.cpp @@ -0,0 +1,458 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#include "matsys_controls/vmtpanel.h" +#include "materialsystem/imesh.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/itexture.h" +#include "VGuiMatSurface/IMatSystemSurface.h" +#include "vgui_controls/ScrollBar.h" +#include "matsys_controls/matsyscontrols.h" +#include "vgui/IVGui.h" +#include "vgui_controls/ToolWindow.h" +#include "tier2/renderutils.h" + +using namespace vgui; + +//----------------------------------------------------------------------------- +// Enums +//----------------------------------------------------------------------------- +enum +{ + SCROLLBAR_SIZE=18, // the width of a scrollbar + WINDOW_BORDER_WIDTH=2 // the width of the window's border +}; + +#define SPHERE_RADIUS 10.0f + + +//----------------------------------------------------------------------------- +// Constructor, destructor +//----------------------------------------------------------------------------- +CVMTPanel::CVMTPanel( vgui::Panel *pParent, const char *pName ) : BaseClass( pParent, pName ) +{ + m_bUseActualSize = true; + m_pMaterial = NULL; + + m_pHorizontalBar = new ScrollBar( this, "HorizScrollBar", false ); + m_pHorizontalBar->AddActionSignalTarget(this); + m_pHorizontalBar->SetVisible(false); + + m_pVerticalBar = new ScrollBar( this, "VertScrollBar", true ); + m_pVerticalBar->AddActionSignalTarget(this); + m_pVerticalBar->SetVisible(false); + + LookAt( SPHERE_RADIUS ); + + m_pLightmapTexture.Init( "//platform/materials/debug/defaultlightmap", "editor" ); + m_DefaultEnvCubemap.Init( "editor/cubemap", "editor", true ); +} + +CVMTPanel::~CVMTPanel() +{ + m_pLightmapTexture.Shutdown(); + m_DefaultEnvCubemap.Shutdown(); + if (m_pMaterial) + { + m_pMaterial->DecrementReferenceCount(); + } +} + + +//----------------------------------------------------------------------------- +// Scheme +//----------------------------------------------------------------------------- +void CVMTPanel::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + SetBorder( pScheme->GetBorder( "MenuBorder") ); +} + + +//----------------------------------------------------------------------------- +// Set the material to draw +//----------------------------------------------------------------------------- +void CVMTPanel::SetMaterial( IMaterial *pMaterial ) +{ + if (pMaterial) + { + pMaterial->IncrementReferenceCount(); + } + if (m_pMaterial) + { + m_pMaterial->DecrementReferenceCount(); + } + m_pMaterial = pMaterial; + InvalidateLayout(); +} + + +//----------------------------------------------------------------------------- +// Set rendering mode (stretch to full screen, or use actual size) +//----------------------------------------------------------------------------- +void CVMTPanel::RenderUsingActualSize( bool bEnable ) +{ + m_bUseActualSize = bEnable; + InvalidateLayout(); +} + + +//----------------------------------------------------------------------------- +// Purpose: relayouts out the panel after any internal changes +//----------------------------------------------------------------------------- +void CVMTPanel::PerformLayout() +{ + BaseClass::PerformLayout(); + return; + + // Get the current size, see if it's big enough to view the entire thing + int iWidth, iHeight; + GetSize( iWidth, iHeight ); + + // In the case of stretching, just stretch to the size and blow off + // the scrollbars. Same holds true if there's no material + if (!m_bUseActualSize || !m_pMaterial) + { + m_iViewableWidth = iWidth; + m_iViewableHeight = iHeight; + m_pHorizontalBar->SetVisible(false); + m_pVerticalBar->SetVisible(false); + return; + } + + // Check the size of the material... + int iMaterialWidth = m_pMaterial->GetMappingWidth(); + int iMaterialHeight = m_pMaterial->GetMappingHeight(); + + // Check if the scroll bars are visible + bool bHorizScrollVisible = (iMaterialWidth > iWidth); + bool bVertScrollVisible = (iMaterialHeight > iHeight); + + m_pHorizontalBar->SetVisible(bHorizScrollVisible); + m_pVerticalBar->SetVisible(bVertScrollVisible); + + // Shrink the bars if both are visible + m_iViewableWidth = bVertScrollVisible ? iWidth - SCROLLBAR_SIZE - WINDOW_BORDER_WIDTH : iWidth; + m_iViewableHeight = bHorizScrollVisible ? iHeight - SCROLLBAR_SIZE - WINDOW_BORDER_WIDTH : iHeight; + + // Set the position of the horizontal bar... + if (bHorizScrollVisible) + { + m_pHorizontalBar->SetPos(0, iHeight - SCROLLBAR_SIZE); + m_pHorizontalBar->SetSize( m_iViewableWidth, SCROLLBAR_SIZE ); + + m_pHorizontalBar->SetRangeWindow( m_iViewableWidth ); + m_pHorizontalBar->SetRange( 0, iMaterialWidth ); + + // FIXME: Change scroll amount based on how much is not visible? + m_pHorizontalBar->SetButtonPressedScrollValue( 5 ); + } + + // Set the position of the vertical bar... + if (bVertScrollVisible) + { + m_pVerticalBar->SetPos(iWidth - SCROLLBAR_SIZE, 0); + m_pVerticalBar->SetSize(SCROLLBAR_SIZE, m_iViewableHeight); + + m_pVerticalBar->SetRangeWindow( m_iViewableHeight ); + m_pVerticalBar->SetRange( 0, iMaterialHeight); + m_pVerticalBar->SetButtonPressedScrollValue( 5 ); + } +} + + +//----------------------------------------------------------------------------- +// paint it stretched to the window size +//----------------------------------------------------------------------------- +void CVMTPanel::DrawStretchedToPanel( CMeshBuilder &meshBuilder ) +{ + // Draw a polygon the size of the panel + meshBuilder.Color4ub( 255, 255, 255, 255 ); + meshBuilder.Position3f( 0, 0, 0 ); + meshBuilder.TexCoord2f( 0, 0, 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( 255, 255, 255, 255 ); + meshBuilder.Position3f( 0, m_iViewableHeight, 0 ); + meshBuilder.TexCoord2f( 0, 0, 1 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( 255, 255, 255, 255 ); + meshBuilder.Position3f( m_iViewableWidth, m_iViewableHeight, 0 ); + meshBuilder.TexCoord2f( 0, 1, 1 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( 255, 255, 255, 255 ); + meshBuilder.Position3f( m_iViewableWidth, 0, 0 ); + meshBuilder.TexCoord2f( 0, 0, 1 ); + meshBuilder.AdvanceVertex(); +} + + +//----------------------------------------------------------------------------- +// paint it actual size +//----------------------------------------------------------------------------- +void CVMTPanel::DrawActualSize( CMeshBuilder &meshBuilder ) +{ + // Check the size of the material... + int iMaterialWidth = m_pMaterial->GetMappingWidth(); + int iMaterialHeight = m_pMaterial->GetMappingHeight(); + + Vector2D ul; + Vector2D lr; + Vector2D tul; + Vector2D tlr; + + if (m_iViewableWidth >= iMaterialWidth) + { + // Center the material if we've got enough horizontal space + ul.x = (m_iViewableWidth - iMaterialWidth) * 0.5f; + lr.x = ul.x + iMaterialWidth; + tul.x = 0.0f; tlr.x = 1.0f; + } + else + { + // Use the scrollbars here... + int val = m_pHorizontalBar->GetValue(); + tul.x = (float)val / (float)iMaterialWidth; + tlr.x = tul.x + (float)m_iViewableWidth / (float)iMaterialWidth; + + ul.x = 0; + lr.x = m_iViewableWidth; + } + + if (m_iViewableHeight >= iMaterialHeight) + { + // Center the material if we've got enough vertical space + ul.y = (m_iViewableHeight - iMaterialHeight) * 0.5f; + lr.y = ul.y + iMaterialHeight; + tul.y = 0.0f; tlr.y = 1.0f; + } + else + { + // Use the scrollbars here... + int val = m_pVerticalBar->GetValue(); + + tul.y = (float)val / (float)iMaterialHeight; + tlr.y = tul.y + (float)m_iViewableHeight / (float)iMaterialHeight; + + ul.y = 0; + lr.y = m_iViewableHeight; + } + + meshBuilder.Color4ub( 255, 255, 255, 255 ); + meshBuilder.Position3f( ul.x, ul.y, 0 ); + meshBuilder.TexCoord2f( 0, tul.x, tul.y ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( 255, 255, 255, 255 ); + meshBuilder.Position3f( lr.x, ul.y, 0 ); + meshBuilder.TexCoord2f( 0, tlr.x, tul.y ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( 255, 255, 255, 255 ); + meshBuilder.Position3f( lr.x, lr.y, 0 ); + meshBuilder.TexCoord2f( 0, tlr.x, tlr.y ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( 255, 255, 255, 255 ); + meshBuilder.Position3f( ul.x, lr.y, 0 ); + meshBuilder.TexCoord2f( 0, tul.x, tlr.y ); + meshBuilder.AdvanceVertex(); +} + + +//----------------------------------------------------------------------------- +// Draw it on a sphere +//----------------------------------------------------------------------------- +void CVMTPanel::RenderSphere( const Vector &vCenter, float flRadius, int nTheta, int nPhi ) +{ + int nVertices = nTheta * nPhi; + int nIndices = 2 * ( nTheta + 1 ) * ( nPhi - 1 ); + + CMatRenderContextPtr pRenderContext( MaterialSystem() ); + pRenderContext->FogMode( MATERIAL_FOG_NONE ); + pRenderContext->SetNumBoneWeights( 0 ); + pRenderContext->Bind( m_pMaterial ); + pRenderContext->BindLightmapTexture( m_pLightmapTexture ); + pRenderContext->BindLocalCubemap( m_DefaultEnvCubemap ); + + IMesh* pMesh = pRenderContext->GetDynamicMesh(); + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, nVertices, nIndices ); + + bool bIsUsingLightmap = m_pMaterial->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_LIGHTMAP ); + bool bIsUsingBumpedLightmap = m_pMaterial->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_BUMPED_LIGHTMAPS ); + + int nLightmapWidth = m_pLightmapTexture->GetActualWidth(); + float flHalfLuxel = 0.5f / nLightmapWidth; + + // + // Build the index buffer. + // + int i, j; + for ( i = 0; i < nPhi; ++i ) + { + for ( j = 0; j < nTheta; ++j ) + { + float u = j / ( float )(nTheta - 1); + float v = i / ( float )(nPhi - 1); + float theta = ( j != nTheta-1 ) ? 2.0f * M_PI * u : 0.0f; + float phi = M_PI * v; + + Vector vecPos; + vecPos.x = flRadius * sin(phi) * cos(theta); + vecPos.y = flRadius * sin(phi) * sin(theta); + vecPos.z = flRadius * cos(phi); + + Vector vecNormal = vecPos; + VectorNormalize( vecNormal ); + + Vector4D vecTangentS; + Vector vecTangentT; + vecTangentS.Init( -vecPos.y, vecPos.x, 0.0f, 1.0f ); + if ( VectorNormalize( vecTangentS.AsVector3D() ) == 0.0f ) + { + vecTangentS.Init( 1.0f, 0.0f, 0.0f, 1.0f ); + } + + CrossProduct( vecNormal, vecTangentS.AsVector3D(), vecTangentT ); + + unsigned char red = (int)( u * 255.0f ); + unsigned char green = (int)( v * 255.0f ); + unsigned char blue = (int)( v * 255.0f ); + unsigned char alpha = (int)( v * 255.0f ); + + vecPos += vCenter; + + float u1, u2, v1, v2; + u1 = u2 = u; + v1 = v2 = v; + + if ( bIsUsingLightmap ) + { + u1 = RemapVal( u1, 0.0f, 1.0f, flHalfLuxel, 0.25 - flHalfLuxel ); + + if ( bIsUsingBumpedLightmap ) + { + u2 = 0.25f; + v2 = 0.0f; + } + } + + meshBuilder.Position3fv( vecPos.Base() ); + meshBuilder.Normal3fv( vecNormal.Base() ); + meshBuilder.Color4ub( red, green, blue, alpha ); + meshBuilder.TexCoord2f( 0, u, v ); + meshBuilder.TexCoord2f( 1, u1, v1 ); + meshBuilder.TexCoord2f( 2, u2, v2 ); + meshBuilder.TangentS3fv( vecTangentS.Base() ); + meshBuilder.TangentT3fv( vecTangentT.Base() ); + meshBuilder.UserData( vecTangentS.Base() ); + meshBuilder.AdvanceVertex(); + } + } + + // + // Emit the triangle strips. + // + int idx = 0; + for ( i = 0; i < nPhi - 1; ++i ) + { + for ( j = 0; j < nTheta; ++j ) + { + idx = nTheta * i + j; + + meshBuilder.FastIndex( idx ); + meshBuilder.FastIndex( idx + nTheta ); + } + + // + // Emit a degenerate triangle to skip to the next row without + // a connecting triangle. + // + if ( i < nPhi - 2 ) + { + meshBuilder.FastIndex( idx + 1 ); + meshBuilder.FastIndex( idx + 1 + nTheta ); + } + } + + meshBuilder.End(); + pMesh->Draw(); +} + + +//----------------------------------------------------------------------------- +// Power of two FB texture +//----------------------------------------------------------------------------- +static CTextureReference s_pPowerOfTwoFrameBufferTexture; + +static ITexture *GetPowerOfTwoFrameBufferTexture( void ) +{ + if( !s_pPowerOfTwoFrameBufferTexture ) + { + s_pPowerOfTwoFrameBufferTexture.Init( materials->FindTexture( "_rt_PowerOfTwoFB", TEXTURE_GROUP_RENDER_TARGET ) ); + } + + return s_pPowerOfTwoFrameBufferTexture; +} + + +//----------------------------------------------------------------------------- +// paint it! +//----------------------------------------------------------------------------- +void CVMTPanel::OnPaint3D() +{ + if (!m_pMaterial) + return; + + // Deal with refraction + CMatRenderContextPtr pRenderContext( MaterialSystem() ); + if ( m_pMaterial->NeedsPowerOfTwoFrameBufferTexture() ) + { + ITexture *pTexture = GetPowerOfTwoFrameBufferTexture(); + if ( pTexture && !pTexture->IsError() ) + { + pRenderContext->CopyRenderTargetToTexture( pTexture ); + pRenderContext->SetFrameBufferCopyTexture( pTexture ); + } + } + + // Draw a background (translucent objects will appear that way) + + // FIXME: Draw the outline of this panel? + + pRenderContext->CullMode( MATERIAL_CULLMODE_CW ); + + RenderSphere( vec3_origin, SPHERE_RADIUS, 20, 20 ); + /* + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->LoadIdentity(); + pRenderContext->Ortho( 0, 0, m_iViewableWidth, m_iViewableHeight, 0, 1 ); + + pRenderContext->Bind( m_pMaterial ); + IMesh *pMesh = pRenderContext->GetDynamicMesh(); + CMeshBuilder meshBuilder; + + meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); + + if (!m_bUseActualSize) + { + DrawStretchedToPanel( meshBuilder ); + } + else + { + DrawActualSize( meshBuilder ); + } + + meshBuilder.End(); + pMesh->Draw(); + */ +} + \ No newline at end of file diff --git a/vgui2/matsys_controls/vmtpicker.cpp b/vgui2/matsys_controls/vmtpicker.cpp new file mode 100644 index 00000000..f642067a --- /dev/null +++ b/vgui2/matsys_controls/vmtpicker.cpp @@ -0,0 +1,78 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "filesystem.h" +#include "matsys_controls/vmtpicker.h" +#include "matsys_controls/vmtpreviewpanel.h" +#include "vgui_controls/Splitter.h" + + +using namespace vgui; + + +//----------------------------------------------------------------------------- +// +// Asset Picker with no preview +// +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CVMTPicker::CVMTPicker( vgui::Panel *pParent, bool bAllowMultiselect ) : + BaseClass( pParent, "VMT Files", "vmt", "materials", "vmtName" ) +{ + // Horizontal splitter for preview + m_pPreviewSplitter = new Splitter( this, "PreviewSplitter", SPLITTER_MODE_VERTICAL, 1 ); + vgui::Panel *pSplitterLeftSide = m_pPreviewSplitter->GetChild( 0 ); + vgui::Panel *pSplitterRightSide = m_pPreviewSplitter->GetChild( 1 ); + + m_p2D3DSplitter = new Splitter( pSplitterRightSide, "2D3DSplitter", SPLITTER_MODE_HORIZONTAL, 1 ); + vgui::Panel *pSplitterTopSide = m_p2D3DSplitter->GetChild( 0 ); + vgui::Panel *pSplitterBottomSide = m_p2D3DSplitter->GetChild( 1 ); + + // VMT preview + m_pVMTPreview2D = new CVMTPreviewPanel( pSplitterTopSide, "VMTPreview2D" ); + m_pVMTPreview3D = new CVMTPreviewPanel( pSplitterBottomSide, "VMTPreview3D" ); + m_pVMTPreview3D->DrawIn3DMode( true ); + + // Standard browser controls + CreateStandardControls( pSplitterLeftSide, bAllowMultiselect ); + + LoadControlSettingsAndUserConfig( "resource/vmtpicker.res" ); +} + +CVMTPicker::~CVMTPicker() +{ +} + + +//----------------------------------------------------------------------------- +// Derived classes have this called when the previewed asset changes +//----------------------------------------------------------------------------- +void CVMTPicker::OnSelectedAssetPicked( const char *pAssetName ) +{ + m_pVMTPreview2D->SetVMT( pAssetName ); + m_pVMTPreview3D->SetVMT( pAssetName ); +} + + +//----------------------------------------------------------------------------- +// +// Purpose: Modal picker frame +// +//----------------------------------------------------------------------------- +CVMTPickerFrame::CVMTPickerFrame( vgui::Panel *pParent, const char *pTitle, bool bAllowMultiselect ) : + BaseClass( pParent ) +{ + SetAssetPicker( new CVMTPicker( this, bAllowMultiselect ) ); + LoadControlSettingsAndUserConfig( "resource/vmtpickerframe.res" ); + SetTitle( pTitle, false ); +} + + + diff --git a/vgui2/matsys_controls/vmtpreviewpanel.cpp b/vgui2/matsys_controls/vmtpreviewpanel.cpp new file mode 100644 index 00000000..6616df24 --- /dev/null +++ b/vgui2/matsys_controls/vmtpreviewpanel.cpp @@ -0,0 +1,625 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#include "matsys_controls/vmtpreviewpanel.h" +#include "matsys_controls/matsyscontrols.h" +#include "VGuiMatSurface/IMatSystemSurface.h" +#include "materialsystem/MaterialSystemUtil.h" +#include "materialsystem/imaterialsystem.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/itexture.h" +#include "materialsystem/imesh.h" +#include "tier1/KeyValues.h" + + +using namespace vgui; + + +#define FOV 90.0f +#define ZNEAR 0.1f +#define ZFAR 2000.0f +#define ROTATION_SPEED 40.0f // degrees/sec +#define VIEW_DISTANCE 12.0f + +//----------------------------------------------------------------------------- +// +// VMT Preview panel +// +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// constructor +//----------------------------------------------------------------------------- +CVMTPreviewPanel::CVMTPreviewPanel( vgui::Panel *pParent, const char *pName ) : + BaseClass( pParent, pName ) +{ + SetVMT( "//platform/materials/vgui/vtfnotloaded" ); + + m_pLightmapTexture.Init( "//platform/materials/debug/defaultlightmap", "editor" ); + m_DefaultEnvCubemap.Init( "editor/cubemap", "editor", true ); + m_LightDirection.Init( 0.0f, 1.0f, -1.0f ); + m_LightColor.SetColor( 255, 255, 255, 255 ); + m_flLightIntensity = 2.0f; + m_bDrawIn3DMode = false; + + // Reset the camera direction + m_vecCameraDirection.Init( 1.0f, 0.0f, 0.0f ); + m_flLastRotationTime = Plat_FloatTime(); +} + + +//----------------------------------------------------------------------------- +// Sets the current VMT +//----------------------------------------------------------------------------- +void CVMTPreviewPanel::SetVMT( const char *pMaterialName ) +{ + m_Material.Init( pMaterialName, "editor material" ); + m_VMTName = pMaterialName; +} + + +//----------------------------------------------------------------------------- +// Gets the current VMT +//----------------------------------------------------------------------------- +const char *CVMTPreviewPanel::GetVMT() const +{ + return m_VMTName; +} + + +//----------------------------------------------------------------------------- +// View it in 3D or 2D mode +//----------------------------------------------------------------------------- +void CVMTPreviewPanel::DrawIn3DMode( bool b3DMode ) +{ + m_bDrawIn3DMode = b3DMode; +} + + +//----------------------------------------------------------------------------- +// Sets up lighting state +//----------------------------------------------------------------------------- +void CVMTPreviewPanel::SetupLightingState() +{ + LightDesc_t desc; + memset( &desc, 0, sizeof(desc) ); + + desc.m_Type = MATERIAL_LIGHT_DIRECTIONAL; + + desc.m_Color[0] = m_LightColor.r(); + desc.m_Color[1] = m_LightColor.g(); + desc.m_Color[2] = m_LightColor.b(); + desc.m_Color *= m_flLightIntensity / 255.0f; + + desc.m_Attenuation0 = 1.0f; + desc.m_Attenuation1 = 0.0f; + desc.m_Attenuation2 = 0.0f; + desc.m_Flags = LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0; + + desc.m_Direction = m_LightDirection; + VectorNormalize( desc.m_Direction ); + + desc.m_Theta = 0.0f; + desc.m_Phi = 0.0f; + desc.m_Falloff = 1.0f; + + CMatRenderContextPtr pRenderContext( MaterialSystem() ); + + pRenderContext->SetLight( 0, desc ); +} + + +//----------------------------------------------------------------------------- +// Draw a sphere +//----------------------------------------------------------------------------- +void CVMTPreviewPanel::RenderSphere( const Vector &vCenter, float flRadius, int nTheta, int nPhi ) +{ + int nVertices = nTheta * nPhi; + int nIndices = 2 * ( nTheta + 1 ) * ( nPhi - 1 ); + + CMatRenderContextPtr pRenderContext( MaterialSystem() ); + + IMesh* pMesh = pRenderContext->GetDynamicMesh(); + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, nVertices, nIndices ); + + bool bIsUsingLightmap = m_Material->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_LIGHTMAP ); + bool bIsUsingBumpedLightmap = m_Material->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_BUMPED_LIGHTMAPS ); + + int nLightmapWidth = m_pLightmapTexture->GetActualWidth(); + float flHalfLuxel = 0.5f / nLightmapWidth; + + // + // Build the index buffer. + // + int i, j; + for ( i = 0; i < nPhi; ++i ) + { + for ( j = 0; j < nTheta; ++j ) + { + float u = j / ( float )(nTheta - 1); + float v = i / ( float )(nPhi - 1); + float theta = ( j != nTheta-1 ) ? 2.0f * M_PI * u : 0.0f; + float phi = M_PI * v; + + Vector vecPos; + vecPos.x = flRadius * sin(phi) * cos(theta); + vecPos.y = flRadius * sin(phi) * sin(theta); + vecPos.z = flRadius * cos(phi); + + Vector vecNormal = vecPos; + VectorNormalize( vecNormal ); + + Vector4D vecTangentS; + Vector vecTangentT; + vecTangentS.Init( vecPos.z, -vecPos.x, 0.0f, 1.0f ); + if ( VectorNormalize( vecTangentS.AsVector3D() ) == 0.0f ) + { + vecTangentS.Init( 1.0f, 0.0f, 0.0f, 1.0f ); + } + + CrossProduct( vecNormal, vecTangentS.AsVector3D(), vecTangentT ); + + unsigned char red = (int)( u * 255.0f ); + unsigned char green = (int)( v * 255.0f ); + unsigned char blue = (int)( v * 255.0f ); + unsigned char alpha = (int)( v * 255.0f ); + + vecPos += vCenter; + + float u1, u2, v1, v2; + u1 = u2 = u; + v1 = v2 = v; + + if ( bIsUsingLightmap ) + { + u1 = RemapVal( u1, 0.0f, 1.0f, flHalfLuxel, 0.25 - flHalfLuxel ); + + if ( bIsUsingBumpedLightmap ) + { + u2 = 0.25f; + v2 = 0.0f; + } + } + + meshBuilder.Position3fv( vecPos.Base() ); + meshBuilder.Normal3fv( vecNormal.Base() ); + meshBuilder.Color4ub( red, green, blue, alpha ); + meshBuilder.TexCoord2f( 0, 2.0f * u, v ); + meshBuilder.TexCoord2f( 1, u1, v1 ); + meshBuilder.TexCoord2f( 2, u2, v2 ); + meshBuilder.TangentS3fv( vecTangentS.Base() ); + meshBuilder.TangentT3fv( vecTangentT.Base() ); + meshBuilder.BoneWeight( 0, 1.0f ); + meshBuilder.BoneMatrix( 0, 0 ); + meshBuilder.UserData( vecTangentS.Base() ); + meshBuilder.AdvanceVertex(); + } + } + + // + // Emit the triangle strips. + // + int idx = 0; + for ( i = 0; i < nPhi - 1; ++i ) + { + for ( j = 0; j < nTheta; ++j ) + { + idx = nTheta * i + j; + + meshBuilder.FastIndex( idx ); + meshBuilder.FastIndex( idx + nTheta ); + } + + // + // Emit a degenerate triangle to skip to the next row without + // a connecting triangle. + // + if ( i < nPhi - 2 ) + { + meshBuilder.FastIndex( idx + 1 ); + meshBuilder.FastIndex( idx + 1 + nTheta ); + } + } + + meshBuilder.End(); + pMesh->Draw(); +} + + +//----------------------------------------------------------------------------- +// Draw sprite-card based materials +//----------------------------------------------------------------------------- +void CVMTPreviewPanel::RenderSpriteCard( const Vector &vCenter, float flRadius ) +{ + CMatRenderContextPtr pRenderContext( MaterialSystem() ); + IMesh *pMesh = pRenderContext->GetDynamicMesh(); + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); + + // Draw a polygon the size of the panel + meshBuilder.Position3fv( vCenter.Base() ); + meshBuilder.Color4ub( 255, 255, 255, 255 ); + meshBuilder.TexCoord4f( 0, 0.0f, 0.0f, 1.0f, 1.0f ); + meshBuilder.TexCoord4f( 1, 0.0f, 0.0f, 1.0f, 1.0f ); + meshBuilder.TexCoord4f( 2, 0.0f, 0.0f, flRadius, 0.0f ); + meshBuilder.TexCoord2f( 3, 0, 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv( vCenter.Base() ); + meshBuilder.Color4ub( 255, 255, 255, 255 ); + meshBuilder.TexCoord4f( 0, 0.0f, 0.0f, 1.0f, 1.0f ); + meshBuilder.TexCoord4f( 1, 0.0f, 0.0f, 1.0f, 1.0f ); + meshBuilder.TexCoord4f( 2, 0.0f, 0.0f, flRadius, 0.0f ); + meshBuilder.TexCoord2f( 3, 0, 1 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv( vCenter.Base() ); + meshBuilder.Color4ub( 255, 255, 255, 255 ); + meshBuilder.TexCoord4f( 0, 0.0f, 0.0f, 1.0f, 1.0f ); + meshBuilder.TexCoord4f( 1, 0.0f, 0.0f, 1.0f, 1.0f ); + meshBuilder.TexCoord4f( 2, 0.0f, 0.0f, flRadius, 0.0f ); + meshBuilder.TexCoord2f( 3, 1, 1 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv( vCenter.Base() ); + meshBuilder.Color4ub( 255, 255, 255, 255 ); + meshBuilder.TexCoord4f( 0, 0.0f, 0.0f, 1.0f, 1.0f ); + meshBuilder.TexCoord4f( 1, 0.0f, 0.0f, 1.0f, 1.0f ); + meshBuilder.TexCoord4f( 2, 0.0f, 0.0f, flRadius, 0.0f ); + meshBuilder.TexCoord2f( 3, 1, 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.End(); + pMesh->Draw(); +} + + +//----------------------------------------------------------------------------- +// Paints a regular texture +//----------------------------------------------------------------------------- +void CVMTPreviewPanel::DrawRectangle( void ) +{ + // Get the aspect ratio of the material + int tw = m_Material->GetMappingWidth(); + int th = m_Material->GetMappingHeight(); + + if ( tw <= 0 || th <= 0 ) + return; + + int w, h; + GetSize( w, h ); + if ( w == 0 || h == 0 ) + return; + + SetupOrthoMatrix( w, h ); + SetupLightingState(); + + CMatRenderContextPtr pRenderContext( MaterialSystem() ); + + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->LoadIdentity(); + + pRenderContext->MatrixMode( MATERIAL_MODEL ); + pRenderContext->LoadIdentity(); + + IMesh* pMesh = pRenderContext->GetDynamicMesh(); + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, 4, 4 ); + + bool bIsUsingLightmap = m_Material->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_LIGHTMAP ); + bool bIsUsingBumpedLightmap = m_Material->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_BUMPED_LIGHTMAPS ); + + int nLightmapWidth = m_pLightmapTexture->GetActualWidth(); + float flHalfLuxel = 0.5f / nLightmapWidth; + Vector2D halfTexel( 0.5f / tw, 0.5f / th ); + + Vector vecNormal( 0.0f, 0.0f, 1.0f ); + Vector4D vecTangentS( 1.0f, 0.0f, 0.0f, 1.0f ); + Vector vecTangentT; + CrossProduct( vecNormal, vecTangentS.AsVector3D(), vecTangentT ); + + float screenaspect = (float)tw / (float)th; + float aspect = (float)w / (float)h; + + float ratio = screenaspect / aspect; + + // Screen is wider, need bars at top and bottom + int x2, y2; + int x, y; + x = y = 0; + int nXBorder = w > 15 ? 5 : w / 3; + int nYBorder = h > 15 ? 5 : h / 3; + w -= 2 * nXBorder; + h -= 2 * nYBorder; + if ( ratio > 1.0f ) + { + int usetall = (float)w / screenaspect; + y = ( h - usetall ) / 2; + h = usetall; + } + // Screen is narrower, need bars at left/right + else + { + int usewide = (float)h * screenaspect; + x = ( w - usewide ) / 2; + w = usewide; + } + x += nXBorder; + y += nYBorder; + + x2 = x+w; y2 = y+h; + + float u = halfTexel.x; + float v = halfTexel.y; + + float u1_l, u1_r, v1_t, v1_b; + float u2_l, u2_r, v2_t, v2_b; + + u1_l = u2_l = u; + u1_r = u2_r = 1.0f - u; + v1_t = v2_t = v; + v1_b = v2_b = 1.0f - v; + + if ( bIsUsingLightmap ) + { + u1_l = v1_t = flHalfLuxel; + u1_r = v1_b = 0.25 - flHalfLuxel; + if ( bIsUsingBumpedLightmap ) + { + u2_l = u2_r = 0.25f; + v2_t = v2_b = 0.0f; + } + } + + meshBuilder.Position3f( x, y2, 0.0f ); + meshBuilder.Normal3fv( vecNormal.Base() ); + meshBuilder.Color4ub( 255, 0, 0, 255 ); + meshBuilder.TexCoord2f( 0, u, v ); + meshBuilder.TexCoord2f( 1, u1_l, v1_t ); + meshBuilder.TexCoord2f( 2, u2_l, v2_t ); + meshBuilder.TangentS3fv( vecTangentS.Base() ); + meshBuilder.TangentT3fv( vecTangentT.Base() ); + meshBuilder.BoneWeight( 0, 1.0f ); + meshBuilder.BoneMatrix( 0, 0 ); + meshBuilder.UserData( vecTangentS.Base() ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3f( x, y, 0.0f ); + meshBuilder.Normal3fv( vecNormal.Base() ); + meshBuilder.Color4ub( 255, 255, 255, 64 ); + meshBuilder.TexCoord2f( 0, u, 1.0f - v ); + meshBuilder.TexCoord2f( 1, u1_l, v1_b ); + meshBuilder.TexCoord2f( 2, u2_l, v2_b ); + meshBuilder.TangentS3fv( vecTangentS.Base() ); + meshBuilder.TangentT3fv( vecTangentT.Base() ); + meshBuilder.BoneWeight( 0, 1.0f ); + meshBuilder.BoneMatrix( 0, 0 ); + meshBuilder.UserData( vecTangentS.Base() ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3f( x2, y2, 0.0f ); + meshBuilder.Normal3fv( vecNormal.Base() ); + meshBuilder.Color4ub( 0, 0, 255, 255 ); + meshBuilder.TexCoord2f( 0, 1.0f - u, v ); + meshBuilder.TexCoord2f( 1, u1_r, v1_t ); + meshBuilder.TexCoord2f( 2, u2_r, v2_t ); + meshBuilder.TangentS3fv( vecTangentS.Base() ); + meshBuilder.TangentT3fv( vecTangentT.Base() ); + meshBuilder.BoneWeight( 0, 1.0f ); + meshBuilder.BoneMatrix( 0, 0 ); + meshBuilder.UserData( vecTangentS.Base() ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3f( x2, y, 0.0f ); + meshBuilder.Normal3fv( vecNormal.Base() ); + meshBuilder.Color4ub( 0, 255, 0, 64 ); + meshBuilder.TexCoord2f( 0, 1.0f - u, 1.0f - v ); + meshBuilder.TexCoord2f( 1, u1_r, v1_b ); + meshBuilder.TexCoord2f( 2, u2_r, v2_b ); + meshBuilder.TangentS3fv( vecTangentS.Base() ); + meshBuilder.TangentT3fv( vecTangentT.Base() ); + meshBuilder.BoneWeight( 0, 1.0f ); + meshBuilder.BoneMatrix( 0, 0 ); + meshBuilder.UserData( vecTangentS.Base() ); + meshBuilder.AdvanceVertex(); + + meshBuilder.FastIndex( 0 ); + meshBuilder.FastIndex( 1 ); + meshBuilder.FastIndex( 2 ); + meshBuilder.FastIndex( 3 ); + + meshBuilder.End(); + pMesh->Draw(); +} + + +//----------------------------------------------------------------------------- +// Paints a cubemap texture +//----------------------------------------------------------------------------- +void CVMTPreviewPanel::DrawSphere( void ) +{ + float flNewTime = Plat_FloatTime(); + + // Circle the camera around the origin + VMatrix rot; + MatrixBuildRotateZ( rot, ROTATION_SPEED * (flNewTime - m_flLastRotationTime ) ); + Vector vecTemp; + Vector3DMultiply( rot, m_vecCameraDirection, vecTemp ); + m_vecCameraDirection = vecTemp; + m_flLastRotationTime = flNewTime; + + int w, h; + GetSize( w, h ); + SetupProjectionMatrix( w, h ); + SetupLightingState(); + + LookAt( vec3_origin, VIEW_DISTANCE ); + + // Draw a sphere at the origin + if ( !m_Material->IsSpriteCard() ) + { + RenderSphere( vec3_origin, 10.0f, 20, 20 ); + } + else + { + RenderSpriteCard( vec3_origin, 10.0f ); + } +} + + +//----------------------------------------------------------------------------- +// Sets the camera to look at the the thing we're spinning around +//----------------------------------------------------------------------------- +void CVMTPreviewPanel::LookAt( const Vector &vecLookAt, float flRadius ) +{ + // Compute the distance to the camera for the object based on its + // radius and fov. + + // since tan( fov/2 ) = f/d + // cos( fov/2 ) = r / r' where r = sphere radius, r' = perp distance from sphere center to max extent of camera + // d/f = r'/d' where d' is distance of camera to sphere + // d' = r' / tan( fov/2 ) * r' = r / ( cos (fov/2) * tan( fov/2 ) ) = r / sin( fov/2 ) + float flFOVx = FOV; + + // Compute fov/2 in radians + flFOVx *= M_PI / 360.0f; + + // Compute an effective fov based on the aspect ratio + // if the height is smaller than the width + int w, h; + GetSize( w, h ); + if ( h < w ) + { + flFOVx = atan( h * tan( flFOVx ) / w ); + } + + float flDistance = flRadius / sin( flFOVx ); + + Vector vecMDLOrigin = vecLookAt; + Vector vecCameraOrigin; + VectorMA( vecMDLOrigin, -flDistance, m_vecCameraDirection, vecCameraOrigin ); + + CMatRenderContextPtr pRenderContext( MaterialSystem() ); + QAngle angles; + VectorAngles( m_vecCameraDirection, angles ); + + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->LoadIdentity(); + + // convert from a right handed system to a left handed system + // since dx for wants it that way. +// pRenderContext->Scale( 1.0f, 1.0f, -1.0f ); + + pRenderContext->Rotate( -90, 1, 0, 0 ); // put Z going up + pRenderContext->Rotate( 90, 0, 0, 1 ); // put Z going up + pRenderContext->Rotate( -angles[2], 1, 0, 0 ); + pRenderContext->Rotate( -angles[0], 0, 1, 0 ); + pRenderContext->Rotate( -angles[1], 0, 0, 1 ); + pRenderContext->Translate( -vecCameraOrigin[0], -vecCameraOrigin[1], -vecCameraOrigin[2] ); +} + + +//----------------------------------------------------------------------------- +// Set up a projection matrix for a 90 degree fov +//----------------------------------------------------------------------------- +void CVMTPreviewPanel::SetupProjectionMatrix( int nWidth, int nHeight ) +{ + VMatrix proj; + float flFOV = FOV; + float flZNear = ZNEAR; + float flZFar = ZFAR; + float flApsectRatio = (nHeight != 0.0f) ? (float)nWidth / (float)nHeight : 100.0f; + + float halfWidth = tan( flFOV * M_PI / 360.0 ); + float halfHeight = halfWidth / flApsectRatio; + + memset( proj.Base(), 0, sizeof( proj ) ); + proj[0][0] = 1.0f / halfWidth; + proj[1][1] = 1.0f / halfHeight; + proj[2][2] = flZFar / ( flZNear - flZFar ); + proj[3][2] = -1.0f; + proj[2][3] = flZNear * flZFar / ( flZNear - flZFar ); + + CMatRenderContextPtr pRenderContext( MaterialSystem() ); + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->LoadMatrix( proj ); +} + + +//----------------------------------------------------------------------------- +// Set up a orthographic projection matrix +//----------------------------------------------------------------------------- +void CVMTPreviewPanel::SetupOrthoMatrix( int nWidth, int nHeight ) +{ + CMatRenderContextPtr pRenderContext( MaterialSystem() ); + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->LoadIdentity(); + pRenderContext->Ortho( 0, 0, nWidth, nHeight, -1.0f, 1.0f ); +} + + +//----------------------------------------------------------------------------- +// Power of two FB texture +//----------------------------------------------------------------------------- +static CTextureReference s_pPowerOfTwoFrameBufferTexture; + +static ITexture *GetPowerOfTwoFrameBufferTexture( void ) +{ + if( !s_pPowerOfTwoFrameBufferTexture ) + { + s_pPowerOfTwoFrameBufferTexture.Init( vgui::MaterialSystem()->FindTexture( "_rt_PowerOfTwoFB", TEXTURE_GROUP_RENDER_TARGET ) ); + } + + return s_pPowerOfTwoFrameBufferTexture; +} + + +//----------------------------------------------------------------------------- +// Paints the texture +//----------------------------------------------------------------------------- +void CVMTPreviewPanel::Paint( void ) +{ + CMatRenderContextPtr pRenderContext( MaterialSystem() ); + int w, h; + GetSize( w, h ); + vgui::MatSystemSurface()->Begin3DPaint( 0, 0, w, h ); + + // Deal with refraction + if ( m_Material->NeedsPowerOfTwoFrameBufferTexture() ) + { + ITexture *pTexture = GetPowerOfTwoFrameBufferTexture(); + if ( pTexture && !pTexture->IsError() ) + { + pRenderContext->CopyRenderTargetToTexture( pTexture ); + pRenderContext->SetFrameBufferCopyTexture( pTexture ); + } + } + + pRenderContext->ClearColor4ub( 76, 88, 68, 255 ); + pRenderContext->ClearBuffers( true, true ); + + pRenderContext->FogMode( MATERIAL_FOG_NONE ); + pRenderContext->SetNumBoneWeights( 0 ); + pRenderContext->Bind( m_Material ); + pRenderContext->BindLightmapTexture( m_pLightmapTexture ); + pRenderContext->BindLocalCubemap( m_DefaultEnvCubemap ); + + if ( m_bDrawIn3DMode || m_Material->IsSpriteCard() ) + { + DrawSphere(); + } + else + { + DrawRectangle(); + } + + vgui::MatSystemSurface()->End3DPaint( ); +} \ No newline at end of file diff --git a/vgui2/matsys_controls/vtfpicker.cpp b/vgui2/matsys_controls/vtfpicker.cpp new file mode 100644 index 00000000..55973769 --- /dev/null +++ b/vgui2/matsys_controls/vtfpicker.cpp @@ -0,0 +1,71 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "filesystem.h" +#include "matsys_controls/vtfpicker.h" +#include "matsys_controls/vtfpreviewpanel.h" +#include "vgui_controls/Splitter.h" + + +using namespace vgui; + + +//----------------------------------------------------------------------------- +// +// Asset Picker with no preview +// +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CVTFPicker::CVTFPicker( vgui::Panel *pParent ) : + BaseClass( pParent, "VTF Files", "vtf", "materials", "vtfName" ) +{ + // Horizontal splitter for preview + m_pPreviewSplitter = new Splitter( this, "PreviewSplitter", SPLITTER_MODE_VERTICAL, 1 ); + vgui::Panel *pSplitterLeftSide = m_pPreviewSplitter->GetChild( 0 ); + vgui::Panel *pSplitterRightSide = m_pPreviewSplitter->GetChild( 1 ); + + // VTF preview + m_pVTFPreview = new CVTFPreviewPanel( pSplitterRightSide, "VTFPreview" ); + + // Standard browser controls + CreateStandardControls( pSplitterLeftSide ); + + LoadControlSettingsAndUserConfig( "resource/vtfpicker.res" ); +} + +CVTFPicker::~CVTFPicker() +{ +} + + +//----------------------------------------------------------------------------- +// Derived classes have this called when the previewed asset changes +//----------------------------------------------------------------------------- +void CVTFPicker::OnSelectedAssetPicked( const char *pAssetName ) +{ + m_pVTFPreview->SetVTF( pAssetName ); +} + + +//----------------------------------------------------------------------------- +// +// Purpose: Modal picker frame +// +//----------------------------------------------------------------------------- +CVTFPickerFrame::CVTFPickerFrame( vgui::Panel *pParent, const char *pTitle ) : + BaseClass( pParent ) +{ + SetAssetPicker( new CVTFPicker( this ) ); + LoadControlSettingsAndUserConfig( "resource/vtfpickerframe.res" ); + SetTitle( pTitle, false ); +} + + + diff --git a/vgui2/matsys_controls/vtfpreviewpanel.cpp b/vgui2/matsys_controls/vtfpreviewpanel.cpp new file mode 100644 index 00000000..abd7afa8 --- /dev/null +++ b/vgui2/matsys_controls/vtfpreviewpanel.cpp @@ -0,0 +1,398 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#include "matsys_controls/vtfpreviewpanel.h" +#include "matsys_controls/matsyscontrols.h" +#include "VGuiMatSurface/IMatSystemSurface.h" +#include "materialsystem/MaterialSystemUtil.h" +#include "materialsystem/imaterialsystem.h" +#include "materialsystem/itexture.h" +#include "materialsystem/imesh.h" +#include "tier1/KeyValues.h" + + +using namespace vgui; + + +#define FOV 90.0f +#define ZNEAR 0.1f +#define ZFAR 2000.0f +#define ROTATION_SPEED 120.0f // degrees/sec + +//----------------------------------------------------------------------------- +// +// VTF Preview panel +// +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// constructor +//----------------------------------------------------------------------------- +CVTFPreviewPanel::CVTFPreviewPanel( vgui::Panel *pParent, const char *pName ) : + BaseClass( pParent, pName ) +{ + SetVTF( "//platform/materials/vgui/vtfnotloaded", true ); + m_nTextureID = MatSystemSurface()->CreateNewTextureID( false ); +} + +CVTFPreviewPanel::~CVTFPreviewPanel() +{ + if ( vgui::surface() && m_nTextureID != -1 ) + { + vgui::surface()->DestroyTextureID( m_nTextureID ); + m_nTextureID = -1; + } +} + + +//----------------------------------------------------------------------------- +// Sets the current VTF +//----------------------------------------------------------------------------- +void CVTFPreviewPanel::SetVTF( const char *pFullPath, bool bLoadImmediately ) +{ + m_PreviewTexture.Init( pFullPath, "editor texture" ); + m_VTFName = pFullPath; + + KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" ); + if ( m_PreviewTexture->IsCubeMap() ) + { + pVMTKeyValues->SetString( "$envmap", pFullPath ); + } + else if ( m_PreviewTexture->IsNormalMap() ) + { + pVMTKeyValues->SetString( "$bumpmap", pFullPath ); + } + else + { + pVMTKeyValues->SetString( "$basetexture", pFullPath ); + } + pVMTKeyValues->SetInt( "$nocull", 1 ); + pVMTKeyValues->SetInt( "$nodebug", 1 ); + m_PreviewMaterial.Init( MaterialSystem()->CreateMaterial( pFullPath, pVMTKeyValues )); + + MatSystemSurface()->DrawSetTextureMaterial( m_nTextureID, m_PreviewMaterial ); + + // Reset the camera direction + m_vecCameraDirection.Init( 1.0f, 0.0f, 0.0f ); + m_flLastRotationTime = Plat_FloatTime(); +} + + +//----------------------------------------------------------------------------- +// Gets the current VTF +//----------------------------------------------------------------------------- +const char *CVTFPreviewPanel::GetVTF() const +{ + return m_VTFName; +} + + +//----------------------------------------------------------------------------- +// Draw a sphere +//----------------------------------------------------------------------------- +void CVTFPreviewPanel::RenderSphere( const Vector &vCenter, float flRadius, int nTheta, int nPhi ) +{ + CMatRenderContextPtr pRenderContext( MaterialSystem() ); + + int nVertices = nTheta * nPhi; + int nIndices = 2 * ( nTheta + 1 ) * ( nPhi - 1 ); + + pRenderContext->FogMode( MATERIAL_FOG_NONE ); + pRenderContext->SetNumBoneWeights( 0 ); + pRenderContext->Bind( m_PreviewMaterial ); + + IMesh* pMesh = pRenderContext->GetDynamicMesh(); + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, nVertices, nIndices ); + + // + // Build the index buffer. + // + int i, j; + for ( i = 0; i < nPhi; ++i ) + { + for ( j = 0; j < nTheta; ++j ) + { + float u = j / ( float )(nTheta - 1); + float v = i / ( float )(nPhi - 1); + float theta = ( j != nTheta-1 ) ? 2.0f * M_PI * u : 0.0f; + float phi = M_PI * v; + + Vector vecPos; + vecPos.x = flRadius * sin(phi) * cos(theta); + vecPos.y = flRadius * cos(phi); + vecPos.z = -flRadius * sin(phi) * sin(theta); + + Vector vecNormal = vecPos; + VectorNormalize( vecNormal ); + + Vector4D vecTangentS; + Vector vecTangentT; + vecTangentS.Init( vecPos.z, -vecPos.x, 0.0f, 1.0f ); + if ( VectorNormalize( vecTangentS.AsVector3D() ) == 0.0f ) + { + vecTangentS.Init( 1.0f, 0.0f, 0.0f, 1.0f ); + } + + CrossProduct( vecNormal, vecTangentS.AsVector3D(), vecTangentT ); + + unsigned char red = (int)( u * 255.0f ); + unsigned char green = (int)( v * 255.0f ); + unsigned char blue = (int)( v * 255.0f ); + unsigned char alpha = (int)( v * 255.0f ); + + vecPos += vCenter; + + float u1, u2, v1, v2; + u1 = u2 = u; + v1 = v2 = v; + + meshBuilder.Position3fv( vecPos.Base() ); + meshBuilder.Normal3fv( vecNormal.Base() ); + meshBuilder.Color4ub( red, green, blue, alpha ); + meshBuilder.TexCoord2f( 0, u, v ); + meshBuilder.TexCoord2f( 1, u1, v1 ); + meshBuilder.TexCoord2f( 2, u2, v2 ); + meshBuilder.TangentS3fv( vecTangentS.Base() ); + meshBuilder.TangentT3fv( vecTangentT.Base() ); + meshBuilder.BoneWeight( 0, 1.0f ); + meshBuilder.BoneMatrix( 0, 0 ); + meshBuilder.UserData( vecTangentS.Base() ); + meshBuilder.AdvanceVertex(); + } + } + + // + // Emit the triangle strips. + // + int idx = 0; + for ( i = 0; i < nPhi - 1; ++i ) + { + for ( j = 0; j < nTheta; ++j ) + { + idx = nTheta * i + j; + + meshBuilder.FastIndex( idx ); + meshBuilder.FastIndex( idx + nTheta ); + } + + // + // Emit a degenerate triangle to skip to the next row without + // a connecting triangle. + // + if ( i < nPhi - 2 ) + { + meshBuilder.FastIndex( idx + 1 ); + meshBuilder.FastIndex( idx + 1 + nTheta ); + } + } + + meshBuilder.End(); + pMesh->Draw(); +} + + +//----------------------------------------------------------------------------- +// Paints a regular texture +//----------------------------------------------------------------------------- +void CVTFPreviewPanel::PaintStandardTexture( void ) +{ + int x, y, w, h; + x = y = 0; + GetSize( w, h ); + vgui::surface()->DrawSetTexture( m_nTextureID ); + vgui::surface()->DrawSetColor( 255, 255, 255, 255 ); + + // Get the aspect ratio of the texture + int tw = m_PreviewTexture->GetActualWidth(); + int th = m_PreviewTexture->GetActualHeight(); + + if ( th > 0 && h > 0 ) + { + float screenaspect = (float)tw / (float)th; + float aspect = (float)w / (float)h; + + float ratio = screenaspect / aspect; + + // Screen is wider, need bars at top and bottom + if ( ratio > 1.0f ) + { + int usetall = (float)w / screenaspect; + y = ( h - usetall ) / 2; + h = usetall; + } + // Screen is narrower, need bars at left/right + else + { + int usewide = (float)h * screenaspect; + x = ( w - usewide ) / 2; + w = usewide; + } + } + + vgui::surface()->DrawTexturedRect( x, y, x+w, y+h ); +} + + +//----------------------------------------------------------------------------- +// Paints a normalmap texture +//----------------------------------------------------------------------------- +void CVTFPreviewPanel::PaintNormalMapTexture( void ) +{ +} + + +//----------------------------------------------------------------------------- +// Paints a volume texture +//----------------------------------------------------------------------------- +void CVTFPreviewPanel::PaintVolumeTexture( void ) +{ +} + + +//----------------------------------------------------------------------------- +// Paints a cubemap texture +//----------------------------------------------------------------------------- +void CVTFPreviewPanel::PaintCubeTexture( void ) +{ + float flNewTime = Plat_FloatTime(); + + // Circle the camera around the origin + VMatrix rot; + MatrixBuildRotateZ( rot, ROTATION_SPEED * (flNewTime - m_flLastRotationTime ) ); + Vector vecTemp; + Vector3DMultiply( rot, m_vecCameraDirection, vecTemp ); + m_vecCameraDirection = vecTemp; + m_flLastRotationTime = flNewTime; + + LookAt( vec3_origin, 12.0f ); + + // Draw a sphere at the origin + RenderSphere( vec3_origin, 10.0f, 20, 20 ); +} + + +//----------------------------------------------------------------------------- +// Sets the camera to look at the the thing we're spinning around +//----------------------------------------------------------------------------- +void CVTFPreviewPanel::LookAt( const Vector &vecLookAt, float flRadius ) +{ + // Compute the distance to the camera for the object based on its + // radius and fov. + + // since tan( fov/2 ) = f/d + // cos( fov/2 ) = r / r' where r = sphere radius, r' = perp distance from sphere center to max extent of camera + // d/f = r'/d' where d' is distance of camera to sphere + // d' = r' / tan( fov/2 ) * r' = r / ( cos (fov/2) * tan( fov/2 ) ) = r / sin( fov/2 ) + float flFOVx = FOV; + + // Compute fov/2 in radians + flFOVx *= M_PI / 360.0f; + + // Compute an effective fov based on the aspect ratio + // if the height is smaller than the width + int w, h; + GetSize( w, h ); + if ( h < w ) + { + flFOVx = atan( h * tan( flFOVx ) / w ); + } + + float flDistance = flRadius / sin( flFOVx ); + + Vector vecMDLOrigin = vecLookAt; + Vector vecCameraOrigin; + VectorMA( vecMDLOrigin, -flDistance, m_vecCameraDirection, vecCameraOrigin ); + + CMatRenderContextPtr pRenderContext( MaterialSystem() ); + QAngle angles; + VectorAngles( m_vecCameraDirection, angles ); + + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->LoadIdentity(); + + // convert from a right handed system to a left handed system + // since dx for wants it that way. +// pRenderContext->Scale( 1.0f, 1.0f, -1.0f ); + + pRenderContext->Rotate( -90, 1, 0, 0 ); // put Z going up + pRenderContext->Rotate( 90, 0, 0, 1 ); // put Z going up + pRenderContext->Rotate( -angles[2], 1, 0, 0 ); + pRenderContext->Rotate( -angles[0], 0, 1, 0 ); + pRenderContext->Rotate( -angles[1], 0, 0, 1 ); + pRenderContext->Translate( -vecCameraOrigin[0], -vecCameraOrigin[1], -vecCameraOrigin[2] ); +} + + +//----------------------------------------------------------------------------- +// Set up a projection matrix for a 90 degree fov +//----------------------------------------------------------------------------- +void CVTFPreviewPanel::SetupProjectionMatrix( int nWidth, int nHeight ) +{ + CMatRenderContextPtr pRenderContext( MaterialSystem() ); + VMatrix proj; + float flFOV = FOV; + float flZNear = ZNEAR; + float flZFar = ZFAR; + float flApsectRatio = (nHeight != 0.0f) ? (float)nWidth / (float)nHeight : 100.0f; + +#if 1 + float halfWidth = tan( flFOV * M_PI / 360.0 ); + float halfHeight = halfWidth / flApsectRatio; +#else + float halfHeight = tan( flFOV * M_PI / 360.0 ); + float halfWidth = flApsectRatio * halfHeight; +#endif + memset( proj.Base(), 0, sizeof( proj ) ); + proj[0][0] = 1.0f / halfWidth; + proj[1][1] = 1.0f / halfHeight; + proj[2][2] = flZFar / ( flZNear - flZFar ); + proj[3][2] = -1.0f; + proj[2][3] = flZNear * flZFar / ( flZNear - flZFar ); + + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->LoadMatrix( proj ); +} + + +//----------------------------------------------------------------------------- +// Paints the texture +//----------------------------------------------------------------------------- +void CVTFPreviewPanel::Paint( void ) +{ + if ( !m_PreviewTexture->IsCubeMap() && /*!m_PreviewTexture->IsNormalMap() &&*/ !m_PreviewTexture->IsVolumeTexture() ) + { + PaintStandardTexture(); + return; + } + + CMatRenderContextPtr pRenderContext( MaterialSystem() ); + int w, h; + GetSize( w, h ); + vgui::MatSystemSurface()->Begin3DPaint( 0, 0, w, h ); + + pRenderContext->ClearColor4ub( 76, 88, 68, 255 ); + pRenderContext->ClearBuffers( true, true ); + + SetupProjectionMatrix( w, h ); + + if ( m_PreviewTexture->IsCubeMap() ) + { + PaintCubeTexture(); + } + else if ( m_PreviewTexture->IsNormalMap() ) + { + PaintNormalMapTexture(); + } + else if ( m_PreviewTexture->IsVolumeTexture() ) + { + PaintVolumeTexture(); + } + + vgui::MatSystemSurface()->End3DPaint( ); +} \ No newline at end of file diff --git a/vgui2/vgui_controls/AnimationController.cpp b/vgui2/vgui_controls/AnimationController.cpp index 48f8c4e1..9942a1e4 100644 --- a/vgui2/vgui_controls/AnimationController.cpp +++ b/vgui2/vgui_controls/AnimationController.cpp @@ -1344,6 +1344,10 @@ void AnimationController::StartCmd_Animate(UtlSymId_t seqName, AnimCmdAnimate_t if (!panel) return; + // Block some panels (like HudScope). Unfortunately players are abusing animations with broad/null parents. + if ( !panel->CanAnimate() ) + return; + StartCmd_Animate(panel, seqName, cmd, bCanBeCancelled); } diff --git a/vgui2/vgui_controls/Menu.cpp b/vgui2/vgui_controls/Menu.cpp index 5e354edf..ac45dec1 100644 --- a/vgui2/vgui_controls/Menu.cpp +++ b/vgui2/vgui_controls/Menu.cpp @@ -2386,16 +2386,15 @@ int Menu::GetCurrentlyHighlightedItem() // Purpose: Respond to cursor entering a menuItem. //----------------------------------------------------------------------------- // -// Josh: Slightly annoying, but need to completely ensure compatiblity with the SDK + GameUI interactions. +// Josh: Slightly annoying, but need to completely ensure compatibility with the SDK + GameUI interactions. #ifdef PLATFORM_64BITS void Menu::OnCursorEnteredMenuItem( vgui::Panel* VPanel ) -{ - VPANEL menuItem = (VPANEL) VPanel; #else void Menu::OnCursorEnteredMenuItem(int VPanel) +#endif { VPANEL menuItem = (VPANEL)VPanel; -#endif + // if we are in mouse mode if (m_iInputMode == MOUSE) { @@ -2419,13 +2418,12 @@ void Menu::OnCursorEnteredMenuItem(int VPanel) //----------------------------------------------------------------------------- #ifdef PLATFORM_64BITS void Menu::OnCursorExitedMenuItem( vgui::Panel* VPanel ) -{ - VPANEL menuItem = (VPANEL) VPanel; #else void Menu::OnCursorExitedMenuItem( int VPanel ) +#endif { VPANEL menuItem = (VPANEL) VPanel; -#endif + // only care if we are in mouse mode if (m_iInputMode == MOUSE) { diff --git a/vgui2/vgui_controls/MenuBar.cpp b/vgui2/vgui_controls/MenuBar.cpp index 1c7052cc..22518533 100644 --- a/vgui2/vgui_controls/MenuBar.cpp +++ b/vgui2/vgui_controls/MenuBar.cpp @@ -221,7 +221,11 @@ void MenuBar::OnMenuClose() //----------------------------------------------------------------------------- // Purpose: Message map //----------------------------------------------------------------------------- +#ifdef PLATFORM_64BITS +void MenuBar::OnCursorEnteredMenuButton(vgui::Panel* VPanel) +#else void MenuBar::OnCursorEnteredMenuButton(int VPanel) +#endif { VPANEL menuButton = (VPANEL)VPanel; // see if we had a menu open diff --git a/vgui2/vgui_controls/MenuButton.cpp b/vgui2/vgui_controls/MenuButton.cpp index 19b35ae6..2bf4aade 100644 --- a/vgui2/vgui_controls/MenuButton.cpp +++ b/vgui2/vgui_controls/MenuButton.cpp @@ -238,7 +238,11 @@ void MenuButton::OnCursorEntered() // forward the message on to the parent of this menu. KeyValues *msg = new KeyValues ("CursorEnteredMenuButton"); // tell the parent this menuitem is the one that was entered so it can open the menu if it wants +#ifdef PLATFORM_64BITS + msg->SetPtr("VPanel", (void*)GetVPanel()); +#else msg->SetInt("VPanel", GetVPanel()); +#endif ivgui()->PostMessage(GetVParent(), msg, NULL); } diff --git a/vgui2/vgui_controls/PropertySheet.cpp b/vgui2/vgui_controls/PropertySheet.cpp index 81e84382..46eb8c00 100644 --- a/vgui2/vgui_controls/PropertySheet.cpp +++ b/vgui2/vgui_controls/PropertySheet.cpp @@ -1022,11 +1022,11 @@ void PropertySheet::PerformLayout() if(_showTabs) { - _activePage->SetBounds(0, tabHeight, wide, tall - tabHeight); + _activePage->SetBounds(0, tabHeight + m_iPageYOffset, wide, tall - tabHeight); } else { - _activePage->SetBounds(0, 0, wide, tall ); + _activePage->SetBounds(0, m_iPageYOffset, wide, tall ); } _activePage->InvalidateLayout(); } @@ -1060,11 +1060,11 @@ void PropertySheet::PerformLayout() if (m_PageTabs[i] == _activeTab) { // active tab is taller - _activeTab->SetBounds(xtab, 2, width, tabHeight); + _activeTab->SetBounds(xtab, 2 + m_iPageYOffset, width, tabHeight); } else { - m_PageTabs[i]->SetBounds(xtab, 4, width, tabHeight - 2); + m_PageTabs[i]->SetBounds(xtab, 4 + m_iPageYOffset, width, tabHeight - 2); } m_PageTabs[i]->SetVisible(true); xtab += (width + 1) + m_iTabXDelta; diff --git a/vpc_scripts/groups.vgc b/vpc_scripts/groups.vgc index 0ff57f71..de84d17b 100644 --- a/vpc_scripts/groups.vgc +++ b/vpc_scripts/groups.vgc @@ -19,6 +19,7 @@ $Group "game" "client" "launcher_main" "mathlib" + "matsys_controls" "raytrace" "server" "tier1" @@ -40,6 +41,7 @@ $Group "everything" "height2normal" "launcher_main" "mathlib" + "matsys_controls" "motionmapper" "phonemeextractor" "qc_eyes" diff --git a/vpc_scripts/projects.vgc b/vpc_scripts/projects.vgc index b277b1a2..2a62976c 100644 --- a/vpc_scripts/projects.vgc +++ b/vpc_scripts/projects.vgc @@ -65,6 +65,11 @@ $Project "mathlib" "mathlib\mathlib.vpc" } +$Project "matsys_controls" +{ + "vgui2\matsys_controls\matsys_controls.vpc" +} + $Project "motionmapper" { "utils\motionmapper\motionmapper.vpc" [$WINDOWS] diff --git a/vpc_scripts/source_win32_base.vpc b/vpc_scripts/source_win32_base.vpc index 8fa5b704..9bd65c39 100644 --- a/vpc_scripts/source_win32_base.vpc +++ b/vpc_scripts/source_win32_base.vpc @@ -58,6 +58,8 @@ $Configuration $DisableSpecificWarnings "$BASE;4577" [$AT_LEAST_VS2015] // 'noexcept' used with no exception handling mode specified; termination on exception is not guaranteed. Specify /EHsc $DisableSpecificWarnings "$BASE;4091" [$AT_LEAST_VS2015] // 'keyword' : ignored on left of 'type' when no variable is declared + $DisableSpecificWarnings "$BASE;4355" [$AT_LEAST_VS2015] + // Started appearning now since compiler updates... We have warnings as errors on Win32, so disable this there. $DisableSpecificWarnings "$BASE;4101" [$WIN32 && $AT_LEAST_VS2022] // 'Start': unreferenced local variable