//========= 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 ]; sprintf( szPathedFileName, "%s%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 ]; sprintf( 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; sprintf( 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 ); sprintf( temp, "%g %g %g", vecPos.x, vecPos.y, vecPos.z ); CaptureData->SetString( "CameraPosition", temp ); sprintf( temp, "%g %g %g", angDir.x, angDir.y, angDir.z ); CaptureData->SetString( "CameraAngles", temp ); Vector vecOffset; m_pMDLPreview->GetCameraOffset( vecOffset ); sprintf( 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(); sprintf( 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 ] ); sprintf( 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++ ) { sprintf( 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] = ""; sprintf( 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; }