diff options
Diffstat (limited to 'vgui2/matsys_controls/mdlpicker.cpp')
| -rw-r--r-- | vgui2/matsys_controls/mdlpicker.cpp | 1742 |
1 files changed, 1742 insertions, 0 deletions
diff --git a/vgui2/matsys_controls/mdlpicker.cpp b/vgui2/matsys_controls/mdlpicker.cpp new file mode 100644 index 0000000..9098c94 --- /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 ]; + 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 <asset>_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<unsigned char> 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<unsigned char> 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<int, unsigned short> 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<CMDLPicker*>( 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; +} |