//========= 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;
}