//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Implementation of the VGUI ISurface interface using the 
// material system to implement it
//
//=============================================================================//

#if defined( WIN32) && !defined( _X360 )
#include <windows.h>
#endif
#ifdef OSX
#include <Carbon/Carbon.h>
#endif

#if defined( USE_SDL )
#include <appframework/ilaunchermgr.h>
ILauncherMgr *g_pLauncherMgr = NULL;
#endif


#include "tier1/strtools.h"
#include "tier0/icommandline.h"
#include "tier0/dbg.h"
#include "filesystem.h"
#include <vgui/VGUI.h>
#include <Color.h>
#include "utlbuffer.h"
#include "utlvector.h"
#include "Clip2D.h"
#include <vgui_controls/Panel.h>
#include <vgui/IInput.h>
#include <vgui/Point.h>
#include "bitmap/imageformat.h"
#include "TextureDictionary.h"
#include "Cursor.h"
#include "Input.h"
#include <vgui/IHTML.h>
#include <vgui/IVGui.h>
#include "vgui_surfacelib/FontManager.h"
#include "FontTextureCache.h"
#include "MatSystemSurface.h"
#include "inputsystem/iinputsystem.h"
#include <vgui_controls/Controls.h>
#include <vgui/ISystem.h>
#include "icvar.h"
#include "mathlib/mathlib.h"
#include <vgui/ILocalize.h>
#include "mathlib/vmatrix.h"
#include <tier0/vprof.h>
#include "materialsystem/itexture.h"
#ifdef OSX
#include <malloc/malloc.h>
#else
#include <malloc.h>
#endif
#include "../vgui2/src/VPanel.h"
#include <vgui/IInputInternal.h>
#if defined( _X360 )
#include "xbox/xbox_win32stubs.h"
#endif
#include "xbox/xboxstubs.h"
#include "../vgui2/src/Memorybitmap.h"

#pragma warning( disable : 4706 )

#include <vgui/IVguiMatInfo.h>
#include <vgui/IVguiMatInfoVar.h>
#include "materialsystem/imaterialvar.h"

#pragma warning( default : 4706 )

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"



#define VPANEL_NORMAL	((vgui::SurfacePlat *) NULL)
#define VPANEL_MINIMIZED ((vgui::SurfacePlat *) 0x00000001)

using namespace vgui;

static bool g_bSpewFocus = false;

class CVguiMatInfoVar : public IVguiMatInfoVar
{
public:
	CVguiMatInfoVar( IMaterialVar *pMaterialVar )
	{
		m_pMaterialVar = pMaterialVar;
	}

	// from IVguiMatInfoVar
	virtual int GetIntValue ( void ) const
	{
		return m_pMaterialVar->GetIntValue();
	}

	virtual void SetIntValue ( int val )
	{
		m_pMaterialVar->SetIntValue( val );
	}

private:
	IMaterialVar *m_pMaterialVar;
};

class CVguiMatInfo : public IVguiMatInfo
{
public:
	CVguiMatInfo( IMaterial *pMaterial )
	{
		m_pMaterial = pMaterial;
	}

	// from IVguiMatInfo
	virtual IVguiMatInfoVar* FindVarFactory( const char *varName, bool *found )
	{
		IMaterialVar *pMaterialVar = m_pMaterial->FindVar( varName, found );

		if ( pMaterialVar == NULL )
			return NULL;
		return new CVguiMatInfoVar( pMaterialVar );
	}

	virtual int GetNumAnimationFrames( void )
	{
		return m_pMaterial->GetNumAnimationFrames();
	}

private:
	IMaterial *m_pMaterial;
};


//-----------------------------------------------------------------------------
// Globals...
//-----------------------------------------------------------------------------
vgui::IInputInternal		*g_pIInput;
static bool					g_bInDrawing;
static CFontTextureCache	g_FontTextureCache;

//-----------------------------------------------------------------------------
// Singleton instance
//-----------------------------------------------------------------------------
CMatSystemSurface g_MatSystemSurface;
EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CMatSystemSurface, ISurface, 
						VGUI_SURFACE_INTERFACE_VERSION, g_MatSystemSurface );

#if defined(LINUX) || defined(OSX) || defined(PLATFORM_BSD)
CUtlDict< CMatSystemSurface::font_entry, unsigned short > CMatSystemSurface::m_FontData;
#endif

//-----------------------------------------------------------------------------
// Make sure the panel is the same size as the viewport
//-----------------------------------------------------------------------------
CMatEmbeddedPanel::CMatEmbeddedPanel() : BaseClass( NULL, "MatSystemTopPanel" )
{
	SetPaintBackgroundEnabled( false );

#if defined( _X360 )
	SetPos( 0, 0 );
	SetSize( GetSystemMetrics( SM_CXSCREEN ), GetSystemMetrics( SM_CYSCREEN ) );
#endif
}

void CMatEmbeddedPanel::OnThink()
{
	int x, y, width, height;
	CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
	pRenderContext->GetViewport( x, y, width, height );
	SetSize( width, height );
	SetPos( x, y );
	Repaint();
}

VPANEL CMatEmbeddedPanel::IsWithinTraverse(int x, int y, bool traversePopups)
{
	VPANEL retval = BaseClass::IsWithinTraverse( x, y, traversePopups );
	if ( retval == GetVPanel() )
		return 0;
	return retval;
}


//-----------------------------------------------------------------------------
// Constructor, destructor
//-----------------------------------------------------------------------------
CMatSystemSurface::CMatSystemSurface() : m_pEmbeddedPanel(NULL), m_pWhite(NULL)
{
	m_iBoundTexture = -1; 
	m_HWnd = NULL; 
	m_bIn3DPaintMode = false;
	m_b3DPaintRenderToTexture = false;
	m_bDrawingIn3DWorld = false;
	m_PlaySoundFunc = NULL;
	m_bInThink = false;
	m_bAllowJavaScript = false;
	m_bAppDrivesInput = false;
	m_nLastInputPollCount = 0;

	m_hCurrentFont = NULL;
	m_pRestrictedPanel = NULL;

	m_bNeedsKeyboard = true;
	m_bNeedsMouse = true;
	m_bUsingTempFullScreenBufferMaterial = false;
	m_nFullScreenBufferMaterialId = -1;

	memset( m_WorkSpaceInsets, 0, sizeof( m_WorkSpaceInsets ) );
	m_nBatchedCharVertCount = 0;

	m_nFullscreenViewportX = m_nFullscreenViewportY = 0;
	m_nFullscreenViewportWidth = m_nFullscreenViewportHeight = 0;
	m_pFullscreenRenderTarget = NULL;

	m_cursorAlwaysVisible = false;
}

CMatSystemSurface::~CMatSystemSurface()
{
	if ( m_nFullScreenBufferMaterialId != -1 )
	{
		DestroyTextureID( m_nFullScreenBufferMaterialId );
		m_nFullScreenBufferMaterialId = -1;
	}
}


//-----------------------------------------------------------------------------
// Connect, disconnect...
//-----------------------------------------------------------------------------
bool CMatSystemSurface::Connect( CreateInterfaceFn factory )
{
	if ( !BaseClass::Connect( factory ) )
		return false;

	if ( !g_pFullFileSystem )
	{
		Warning( "MatSystemSurface requires the file system to run!\n" );
		return false;
	}

	if ( !g_pMaterialSystem )
	{
		Warning( "MatSystemSurface requires the material system to run!\n" );
		return false;
	}

	if ( !g_pVGuiPanel )
	{
		Warning( "MatSystemSurface requires the vgui::IPanel system to run!\n" );
		return false;
	}

	g_pIInput = (IInputInternal *)factory( VGUI_INPUTINTERNAL_INTERFACE_VERSION, NULL );
	if ( !g_pIInput )
	{
		Warning( "MatSystemSurface requires the vgui::IInput system to run!\n" );
		return false;
	}

	if ( !g_pVGui )
	{
		Warning( "MatSystemSurface requires the vgui::IVGUI system to run!\n" );
		return false;
	}

	Assert( g_pVGuiSurface == this );

	// initialize vgui_control interfaces
	if ( !vgui::VGui_InitInterfacesList( "MATSURFACE", &factory, 1 ) )
		return false;

#ifdef USE_SDL
	g_pLauncherMgr = (ILauncherMgr *)factory( SDLMGR_INTERFACE_VERSION, NULL );
#endif

	return true;	
}

void CMatSystemSurface::Disconnect()
{
	g_pIInput = NULL;
	BaseClass::Disconnect();
}


//-----------------------------------------------------------------------------
// Access to other interfaces...
//-----------------------------------------------------------------------------
void *CMatSystemSurface::QueryInterface( const char *pInterfaceName )
{
	// We also implement the IMatSystemSurface interface
	if (!Q_strncmp(	pInterfaceName, MAT_SYSTEM_SURFACE_INTERFACE_VERSION, Q_strlen(MAT_SYSTEM_SURFACE_INTERFACE_VERSION) + 1))
		return (IMatSystemSurface*)this;

	// We also implement the IMatSystemSurface interface
	if (!Q_strncmp(	pInterfaceName, VGUI_SURFACE_INTERFACE_VERSION, Q_strlen(VGUI_SURFACE_INTERFACE_VERSION) + 1))
		return (vgui::ISurface*)this;

	return BaseClass::QueryInterface( pInterfaceName );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CMatSystemSurface::InitFullScreenBuffer( const char *pszRenderTargetName )
{
	if ( !IsPC() )
		return;

	char pTemp[512];
	Q_snprintf( pTemp, sizeof(pTemp), "VGUI_3DPaint_FullScreen_%s", pszRenderTargetName );
	m_FullScreenBufferMaterial.Shutdown();

	// Set up a material with which to reference the final image for subsequent display using vgui
	KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" );
	pVMTKeyValues->SetString( "$basetexture", pszRenderTargetName );
	pVMTKeyValues->SetInt( "$nocull", 1 );
	pVMTKeyValues->SetInt( "$nofog", 1 );
	pVMTKeyValues->SetInt( "$ignorez", 1 );
	pVMTKeyValues->SetInt( "$translucent", 1 );
	m_FullScreenBufferMaterial.Init( pTemp, TEXTURE_GROUP_OTHER, pVMTKeyValues );
	m_FullScreenBufferMaterial->Refresh();

	if ( m_nFullScreenBufferMaterialId != -1 )
	{
		DestroyTextureID( m_nFullScreenBufferMaterialId );
	}
	m_nFullScreenBufferMaterialId = -1;
	m_FullScreenBuffer.Shutdown();

	m_FullScreenBufferName = pszRenderTargetName;
}

//-----------------------------------------------------------------------------
// Initialization and shutdown...
//-----------------------------------------------------------------------------
InitReturnVal_t CMatSystemSurface::Init( void )
{
	InitReturnVal_t nRetVal = BaseClass::Init();
	if ( nRetVal != INIT_OK )
		return nRetVal;

	// Allocate a white material
	KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" );
	pVMTKeyValues->SetInt( "$vertexcolor", 1 );
	pVMTKeyValues->SetInt( "$vertexalpha", 1 );
	pVMTKeyValues->SetInt( "$ignorez", 1 );
	pVMTKeyValues->SetInt( "$no_fullbright", 1 );
	
	if ( ! (CommandLine()->FindParm("-disable_matsurf_noculls")) )
	{
		pVMTKeyValues->SetInt( "$nocull", 1 );	// skip this if user asks for the switch above
	}
	
	m_pWhite.Init( "VGUI_White", TEXTURE_GROUP_OTHER, pVMTKeyValues );

	InitFullScreenBuffer( "_rt_FullScreen" );

	m_DrawColor[0] = m_DrawColor[1] = m_DrawColor[2] = m_DrawColor[3] = 255;
	m_nTranslateX = m_nTranslateY = 0;
	EnableScissor( false );
	SetScissorRect( 0, 0, 100000, 100000 );
	m_flAlphaMultiplier = 1.0f;

	// By default, use the default embedded panel
	m_pDefaultEmbeddedPanel = new CMatEmbeddedPanel;
	SetEmbeddedPanel( m_pDefaultEmbeddedPanel->GetVPanel() );

	m_iBoundTexture = -1;

	// Initialize font info..
	m_pDrawTextPos[0] = m_pDrawTextPos[1] = 0;
	m_DrawTextColor[0] = m_DrawTextColor[1] = m_DrawTextColor[2] = m_DrawTextColor[3] = 255;

	m_bIn3DPaintMode = false;
	m_b3DPaintRenderToTexture = false;
	m_bDrawingIn3DWorld = false;
	m_PlaySoundFunc = NULL;

	// Input system
	InitInput();

	// Initialize cursors
	InitCursors();

	// fonts initialization
	char language[64];
	bool bValid;
	if ( IsPC() )
	{
		bValid = system()->GetRegistryString( "HKEY_CURRENT_USER\\Software\\Valve\\Source\\Language", language, sizeof(language)-1 );
	}
	else
	{
		Q_strncpy( language, XBX_GetLanguageString(), sizeof( language ) );
		bValid = true;
	}

	if ( bValid )
	{
		FontManager().SetLanguage( language );
	}
	else
	{
		FontManager().SetLanguage( "english" );
	}

#if defined(LINUX) || defined(OSX) || defined(PLATFORM_BSD)
	FontManager().SetFontDataHelper( &CMatSystemSurface::FontDataHelper );
#endif

	// font manager needs the file system and material system for bitmap fonts
	FontManager().SetInterfaces( g_pFullFileSystem, g_pMaterialSystem );

	g_bSpewFocus = CommandLine()->FindParm( "-vguifocus" ) ? true : false;

	return INIT_OK;
}


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CMatSystemSurface::Shutdown( void )
{
	for ( int i = m_FileTypeImages.First(); i != m_FileTypeImages.InvalidIndex(); i = m_FileTypeImages.Next( i ) )
	{
		delete m_FileTypeImages[ i ];
	}
	m_FileTypeImages.RemoveAll();

	// Release all textures
	TextureDictionary()->DestroyAllTextures();
	m_iBoundTexture = -1;

	// Release the standard materials
	m_pWhite.Shutdown();
	m_FullScreenBufferMaterial.Shutdown();
	m_FullScreenBuffer.Shutdown();

	m_Titles.Purge();
	m_PaintStateStack.Purge();

#if defined( WIN32 ) && !defined( _X360 )
 	// release any custom font files
	// use newer function if possible
	HMODULE gdiModule = ::LoadLibrary( "gdi32.dll" );
	typedef int (WINAPI *RemoveFontResourceExProc)(LPCTSTR, DWORD, PVOID);
	RemoveFontResourceExProc pRemoveFontResourceEx = NULL;
	if ( gdiModule )
	{
		pRemoveFontResourceEx = (RemoveFontResourceExProc)::GetProcAddress(gdiModule, "RemoveFontResourceExA");
	}

	for (int i = 0; i < m_CustomFontFileNames.Count(); i++)
 	{
		if (pRemoveFontResourceEx)
		{
			// dvs: Keep removing the font until we get an error back. After consulting with Microsoft, it appears
			// that RemoveFontResourceEx must sometimes be called multiple times to work. Doing this insures that
			// when we load the font next time we get the real font instead of Ariel.
			int nRetries = 0;
			while ( (*pRemoveFontResourceEx)(m_CustomFontFileNames[i].String(), 0x10, NULL) && ( nRetries < 10 ) )
			{
				nRetries++;
				Msg( "Removed font resource %s on attempt %d.\n", m_CustomFontFileNames[i].String(), nRetries );
			}
		}
		else
		{
			// dvs: Keep removing the font until we get an error back. After consulting with Microsoft, it appears
			// that RemoveFontResourceEx must sometimes be called multiple times to work. Doing this insures that
			// when we load the font next time we get the real font instead of Ariel.
			int nRetries = 0;
			while ( ::RemoveFontResource(m_CustomFontFileNames[i].String()) && ( nRetries < 10 ) )
			{
				nRetries++;
				Msg( "Removed font resource %s on attempt %d.\n", m_CustomFontFileNames[i].String(), nRetries );
			}
		}
 	}
#endif

 	m_CustomFontFileNames.RemoveAll();
	m_BitmapFontFileNames.RemoveAll();
	m_BitmapFontFileMapping.RemoveAll();

	Cursor_ClearUserCursors();

#if defined( WIN32 ) && !defined( _X360 )
	if ( gdiModule )
	{
		::FreeLibrary(gdiModule);
	}
#endif

	BaseClass::Shutdown();
}

void CMatSystemSurface::SetEmbeddedPanel(VPANEL pEmbeddedPanel)
{
	m_pEmbeddedPanel = pEmbeddedPanel;
	((VPanel *)pEmbeddedPanel)->Client()->RequestFocus(0);
}

//-----------------------------------------------------------------------------
// hierarchy root
//-----------------------------------------------------------------------------
VPANEL CMatSystemSurface::GetEmbeddedPanel()
{
	return m_pEmbeddedPanel;
}

//-----------------------------------------------------------------------------
// Purpose: cap bits
// Warning: if you change this, make sure the SurfaceV28 wrapper above reports
//          the correct capabilities.
//-----------------------------------------------------------------------------
bool CMatSystemSurface::SupportsFeature(SurfaceFeature_e feature)
{
	switch (feature)
	{
	case ISurface::ANTIALIASED_FONTS:
	case ISurface::DROPSHADOW_FONTS:
		return true;

	case ISurface::OUTLINE_FONTS:
		if ( IsX360() )
			return false;
		return true;

	case ISurface::ESCAPE_KEY:
		return true;

	case ISurface::OPENING_NEW_HTML_WINDOWS:
	case ISurface::FRAME_MINIMIZE_MAXIMIZE:
	default:
		return false;
	};
}

//-----------------------------------------------------------------------------
// Hook needed to Get input to work
//-----------------------------------------------------------------------------
void CMatSystemSurface::AttachToWindow( void *hWnd, bool bLetAppDriveInput )
{
	InputDetachFromWindow( m_HWnd );
	m_HWnd = hWnd;
	if ( hWnd )
	{
		InputAttachToWindow( hWnd );
		m_bAppDrivesInput = bLetAppDriveInput;
	}
	else
	{
		// Never call RunFrame stuff
		m_bAppDrivesInput = true;
	}
}

bool CMatSystemSurface::HandleInputEvent( const InputEvent_t &event )
{
	if ( !m_bAppDrivesInput )
	{
		g_pIInput->UpdateButtonState( event );
	}

	return InputHandleInputEvent( event );
}


//-----------------------------------------------------------------------------
// Draws a panel in 3D space. Assumes view + projection are already set up
// Also assumes the (x,y) coordinates of the panels are defined in 640xN coords
// (N isn't necessary 480 because the panel may not be 4x3)
// The width + height specified are the size of the panel in world coordinates
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawPanelIn3DSpace( vgui::VPANEL pRootPanel, const VMatrix &panelCenterToWorld, int pw, int ph, float sw, float sh )
{
	Assert( pRootPanel );

	// FIXME: When should such panels be solved?!?
	SolveTraverse( pRootPanel, false );

	CMatRenderContextPtr pRenderContext( g_pMaterialSystem );

	// Force Z buffering to be on for all panels drawn...
	pRenderContext->OverrideDepthEnable( true, false );

	Assert(!m_bDrawingIn3DWorld);
	m_bDrawingIn3DWorld = true;

	StartDrawingIn3DSpace( panelCenterToWorld, pw, ph, sw, sh );

	((VPanel *)pRootPanel)->Client()->Repaint();
	((VPanel *)pRootPanel)->Client()->PaintTraverse(true, false);

	FinishDrawing();

	// Reset z buffering to normal state
	pRenderContext->OverrideDepthEnable( false, true ); 

	m_bDrawingIn3DWorld = false;
}


//-----------------------------------------------------------------------------
// Purpose: Setup rendering for vgui on a panel existing in 3D space
//-----------------------------------------------------------------------------
void CMatSystemSurface::StartDrawingIn3DSpace( const VMatrix &screenToWorld, int pw, int ph, float sw, float sh )
{
	g_bInDrawing = true;
	m_iBoundTexture = -1; 

	int px = 0;
	int py = 0;

	m_pSurfaceExtents[0] = px;
	m_pSurfaceExtents[1] = py;
	m_pSurfaceExtents[2] = px + pw;
	m_pSurfaceExtents[3] = py + ph;

	// In order for this to work, the model matrix must have its origin
	// at the upper left corner of the screen. We must also scale down the
	// rendering from pixel space to screen space. Let's construct a matrix
	// transforming from pixel coordinates (640xN) to screen coordinates
	// (wxh, with the origin at the upper left of the screen). Then we'll
	// concatenate it with the panelCenterToWorld to produce pixelToWorld transform
	VMatrix pixelToScreen;

	// First, scale it so that 0->pw transforms to 0->sw
	MatrixBuildScale( pixelToScreen, sw / pw, -sh / ph, 1.0f );

	// Construct pixelToWorld
	VMatrix pixelToWorld;
	MatrixMultiply( screenToWorld, pixelToScreen, pixelToWorld );

	// make sure there is no translation and rotation laying around
	CMatRenderContextPtr pRenderContext( g_pMaterialSystem );

	pRenderContext->MatrixMode( MATERIAL_MODEL );
	pRenderContext->PushMatrix();
	pRenderContext->LoadMatrix( pixelToWorld );

	// These are only here so that FinishDrawing works...
	pRenderContext->MatrixMode( MATERIAL_PROJECTION );
	pRenderContext->PushMatrix();

	pRenderContext->MatrixMode( MATERIAL_VIEW );
	pRenderContext->PushMatrix();

	// Always enable scissoring (translate to origin because of the glTranslatef call above..)
	EnableScissor( true );

	m_nTranslateX = 0;
	m_nTranslateY = 0;
	m_flAlphaMultiplier = 1.0f;
}


//-----------------------------------------------------------------------------
// Purpose: Setup ortho for vgui
//-----------------------------------------------------------------------------

// we may need to offset by 0.5 texels to account for the different in pixel vs. texel centers in dx7-9
// however, we do this fixup already when we set up the texture coordinates for all materials/fonts
// so in theory we shouldn't need to do any adjustments for setting up the screen
// HOWEVER, we must do the offset, else the driver will think the text is something that should
// be antialiased, so the text will look broken if antialiasing is turned on (usually forced on in the driver)
float g_flPixelOffsetX = 0.5f;
float g_flPixelOffsetY = 0.5f;

bool g_bCheckedCommandLine = false;

extern void ___stop___( void );
void CMatSystemSurface::StartDrawing( void )
{
	MAT_FUNC;

	if ( !g_bCheckedCommandLine )
	{
		g_bCheckedCommandLine = true;
		
		const char *pX = CommandLine()->ParmValue( "-pixel_offset_x", (const char*)NULL );
		if ( pX )
			g_flPixelOffsetX = atof( pX );

		const char *pY = CommandLine()->ParmValue( "-pixel_offset_y", (const char*)NULL );
		if ( pY )
			g_flPixelOffsetY = atof( pY );
	}

	g_bInDrawing = true;
	m_iBoundTexture = -1; 

	int x, y, width, height;

	CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
	pRenderContext->GetViewport( x, y, width, height);

	// we don't want to include x and y from the viewport here. DX will 
	// automatically translate any drawing we do into that viewport.
	m_pSurfaceExtents[0] = 0;
	m_pSurfaceExtents[1] = 0;
	m_pSurfaceExtents[2] = width;
	m_pSurfaceExtents[3] = height;

	pRenderContext->MatrixMode( MATERIAL_PROJECTION );
	pRenderContext->PushMatrix();
	pRenderContext->LoadIdentity();
	pRenderContext->Scale( 1, -1, 1 );
	
	//___stop___();
	pRenderContext->Ortho( g_flPixelOffsetX, g_flPixelOffsetY, width + g_flPixelOffsetX, height + g_flPixelOffsetY, -1.0f, 1.0f ); 

	// make sure there is no translation and rotation laying around
	pRenderContext->MatrixMode( MATERIAL_MODEL );
	pRenderContext->PushMatrix();
	pRenderContext->LoadIdentity();

	// Always enable scissoring (translate to origin because of the glTranslatef call above..)
	EnableScissor( true );

	m_nTranslateX = 0;
	m_nTranslateY = 0;

	pRenderContext->MatrixMode( MATERIAL_VIEW );
	pRenderContext->PushMatrix();
	pRenderContext->LoadIdentity();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CMatSystemSurface::FinishDrawing( void )
{
	MAT_FUNC;

	// We're done with scissoring
	EnableScissor( false );

	// Restore the matrices
	CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
	pRenderContext->MatrixMode( MATERIAL_PROJECTION );
	pRenderContext->PopMatrix();

	pRenderContext->MatrixMode( MATERIAL_MODEL );
	pRenderContext->PopMatrix();

	pRenderContext->MatrixMode( MATERIAL_VIEW );
	pRenderContext->PopMatrix();

  	Assert( g_bInDrawing );
	g_bInDrawing = false;
}


//-----------------------------------------------------------------------------
// frame
//-----------------------------------------------------------------------------
void CMatSystemSurface::RunFrame()
{
	int nPollCount = g_pInputSystem->GetPollCount();
	if ( m_nLastInputPollCount == nPollCount )
		return;

	// If this isn't true, we've lost input!
	if ( !m_bAppDrivesInput && m_nLastInputPollCount != nPollCount - 1 )
	{
		Assert( 0 );
		Warning( "Vgui is losing input messages! Call brian!\n" );
	}

	m_nLastInputPollCount = nPollCount;

	if ( m_bAppDrivesInput )
		return;

	// Generate all input messages
	int nEventCount = g_pInputSystem->GetEventCount();
	const InputEvent_t* pEvents = g_pInputSystem->GetEventData( );
	for ( int i = 0; i < nEventCount; ++i )
	{
		HandleInputEvent( pEvents[i] );
	}
}


//-----------------------------------------------------------------------------
// Sets up a particular painting state...
//-----------------------------------------------------------------------------
void CMatSystemSurface::SetupPaintState( const PaintState_t &paintState )
{
	m_nTranslateX = paintState.m_iTranslateX;
	m_nTranslateY = paintState.m_iTranslateY;
	SetScissorRect( paintState.m_iScissorLeft, paintState.m_iScissorTop, 
		paintState.m_iScissorRight, paintState.m_iScissorBottom );
}

//-----------------------------------------------------------------------------
// Indicates a particular panel is about to be rendered 
//-----------------------------------------------------------------------------
void CMatSystemSurface::PushMakeCurrent(VPANEL pPanel, bool useInSets)
{
	int inSets[4] = {0, 0, 0, 0};
	int absExtents[4];
	int clipRect[4];

	if (useInSets)
	{
		g_pVGuiPanel->GetInset(pPanel, inSets[0], inSets[1], inSets[2], inSets[3]);
	}

	g_pVGuiPanel->GetAbsPos(pPanel, absExtents[0], absExtents[1]);
	int wide, tall;
	g_pVGuiPanel->GetSize(pPanel, wide, tall);
	absExtents[2] = absExtents[0] + wide;
	absExtents[3] = absExtents[1] + tall;

	g_pVGuiPanel->GetClipRect(pPanel, clipRect[0], clipRect[1], clipRect[2], clipRect[3]);

	int i = m_PaintStateStack.AddToTail();
	PaintState_t &paintState = m_PaintStateStack[i];
	paintState.m_pPanel = pPanel;

	// Determine corrected top left origin
	paintState.m_iTranslateX = inSets[0] + absExtents[0] - m_pSurfaceExtents[0];	
	paintState.m_iTranslateY = inSets[1] + absExtents[1] - m_pSurfaceExtents[1];

	// Setup clipping rectangle for scissoring
	paintState.m_iScissorLeft	= clipRect[0] - m_pSurfaceExtents[0];
	paintState.m_iScissorTop	= clipRect[1] - m_pSurfaceExtents[1];
	paintState.m_iScissorRight	= clipRect[2] - m_pSurfaceExtents[0];
	paintState.m_iScissorBottom	= clipRect[3] - m_pSurfaceExtents[1];
	
	SetupPaintState( paintState );
}

void CMatSystemSurface::PopMakeCurrent(VPANEL pPanel)
{
	//hushed MAT_FUNC;

	// draw any remaining text
	if ( m_nBatchedCharVertCount > 0 )
	{
		DrawFlushText();
	}

	int top = m_PaintStateStack.Count() - 1;

	// More pops that pushes?
	Assert( top >= 0 );

	// Didn't pop in reverse order of push?
	Assert( m_PaintStateStack[top].m_pPanel == pPanel );

	m_PaintStateStack.Remove(top);

	if (top > 0)
		SetupPaintState( m_PaintStateStack[top-1] );

//	m_iBoundTexture = -1; 
}


//-----------------------------------------------------------------------------
// Color Setting methods
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawSetColor(int r, int g, int b, int a)
{
  	Assert( g_bInDrawing );
	m_DrawColor[0]=(unsigned char)r;
	m_DrawColor[1]=(unsigned char)g;
	m_DrawColor[2]=(unsigned char)b;
	m_DrawColor[3]=(unsigned char)(a * m_flAlphaMultiplier);
}

void CMatSystemSurface::DrawSetColor(Color col)
{
  	Assert( g_bInDrawing );
	DrawSetColor(col[0], col[1], col[2], col[3]);
}


//-----------------------------------------------------------------------------
// material Setting methods 
//-----------------------------------------------------------------------------
void CMatSystemSurface::InternalSetMaterial( IMaterial *pMaterial )
{
	if (!pMaterial)
	{
		pMaterial = m_pWhite;
	}

	CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
	m_pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMaterial );
}


//-----------------------------------------------------------------------------
// Helper method to initialize vertices (transforms them into screen space too)
//-----------------------------------------------------------------------------
void CMatSystemSurface::InitVertex( vgui::Vertex_t &vertex, int x, int y, float u, float v )
{
	vertex.m_Position.Init( x + m_nTranslateX, y + m_nTranslateY );
	vertex.m_TexCoord.Init( u, v );
}


//-----------------------------------------------------------------------------
// Draws a line!
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawTexturedLineInternal( const Vertex_t &a, const Vertex_t &b )
{
	MAT_FUNC;

	Assert( !m_bIn3DPaintMode );

	// Don't bother drawing fully transparent lines
	if( m_DrawColor[3] == 0 )
		return;

	vgui::Vertex_t verts[2] = { a, b };
	
	verts[0].m_Position.x += m_nTranslateX + g_flPixelOffsetX;
	verts[0].m_Position.y += m_nTranslateY + g_flPixelOffsetY;
	
	verts[1].m_Position.x += m_nTranslateX + g_flPixelOffsetX;
	verts[1].m_Position.y += m_nTranslateY + g_flPixelOffsetY;

	vgui::Vertex_t clippedVerts[2];

	if (!ClipLine( verts, clippedVerts ))
		return;

	meshBuilder.Begin( m_pMesh, MATERIAL_LINES, 1 );

	meshBuilder.Position3f( clippedVerts[0].m_Position.x, clippedVerts[0].m_Position.y, m_flZPos );
	meshBuilder.Color4ubv( m_DrawColor );
	meshBuilder.TexCoord2fv( 0, clippedVerts[0].m_TexCoord.Base() );
	meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();

	meshBuilder.Position3f( clippedVerts[1].m_Position.x, clippedVerts[1].m_Position.y, m_flZPos );
	meshBuilder.Color4ubv( m_DrawColor );
	meshBuilder.TexCoord2fv( 0, clippedVerts[1].m_TexCoord.Base() );
	meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();

	meshBuilder.End();
	m_pMesh->Draw();
}

void CMatSystemSurface::DrawLine( int x0, int y0, int x1, int y1 )
{
	MAT_FUNC;

	Assert( g_bInDrawing );

	// Don't bother drawing fully transparent lines
	if( m_DrawColor[3] == 0 )
		return;

	vgui::Vertex_t verts[2];
	verts[0].Init( Vector2D( x0, y0 ), Vector2D( 0, 0 ) );
	verts[1].Init( Vector2D( x1, y1 ), Vector2D( 1, 1 ) );
	
	InternalSetMaterial( );
	DrawTexturedLineInternal( verts[0], verts[1] );
}


void CMatSystemSurface::DrawTexturedLine( const Vertex_t &a, const Vertex_t &b )
{
	IMaterial *pMaterial = TextureDictionary()->GetTextureMaterial(m_iBoundTexture);
	InternalSetMaterial( pMaterial );
	DrawTexturedLineInternal( a, b );
}


//-----------------------------------------------------------------------------
// Draws a line!
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawPolyLine( int *px, int *py ,int n )
{
	MAT_FUNC;

	Assert( g_bInDrawing );

	Assert( !m_bIn3DPaintMode );

	// Don't bother drawing fully transparent lines
	if( m_DrawColor[3] == 0 )
		return;

	InternalSetMaterial( );
	meshBuilder.Begin( m_pMesh, MATERIAL_LINES, n );

	for ( int i = 0; i < n ; i++ )
	{
		int inext = ( i + 1 ) % n;

		vgui::Vertex_t verts[2];
		vgui::Vertex_t clippedVerts[2];
		
		int x0, y0, x1, y1;

		x0 = px[ i ];
		x1 = px[ inext ];
		y0 = py[ i ];
		y1 = py[ inext ];

		InitVertex( verts[0], x0, y0, 0, 0 );
		InitVertex( verts[1], x1, y1, 1, 1 );

		if (!ClipLine( verts, clippedVerts ))
			continue;

		meshBuilder.Position3f( clippedVerts[0].m_Position.x+ g_flPixelOffsetX, clippedVerts[0].m_Position.y + g_flPixelOffsetY, m_flZPos );
		meshBuilder.Color4ubv( m_DrawColor );
		meshBuilder.TexCoord2fv( 0, clippedVerts[0].m_TexCoord.Base() );
		meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();

		meshBuilder.Position3f( clippedVerts[1].m_Position.x+ g_flPixelOffsetX, clippedVerts[1].m_Position.y + g_flPixelOffsetY, m_flZPos );
		meshBuilder.Color4ubv( m_DrawColor );
		meshBuilder.TexCoord2fv( 0, clippedVerts[1].m_TexCoord.Base() );
		meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();
	}

	meshBuilder.End();
	m_pMesh->Draw();
}


void CMatSystemSurface::DrawTexturedPolyLine( const vgui::Vertex_t *p,int n )
{
	MAT_FUNC;

	int iPrev = n - 1;
	for ( int i=0; i < n; i++ )
	{
		DrawTexturedLine( p[iPrev], p[i] );
		iPrev = i;
	}
}


//-----------------------------------------------------------------------------
// Draws a quad: 
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawQuad( const vgui::Vertex_t &ul, const vgui::Vertex_t &lr, unsigned char *pColor )
{
	MAT_FUNC;
	
	Assert( !m_bIn3DPaintMode );

	if ( !m_pMesh )
		return;

	meshBuilder.Begin( m_pMesh, MATERIAL_QUADS, 1 );

	meshBuilder.Position3f( ul.m_Position.x, ul.m_Position.y, m_flZPos );
	meshBuilder.Color4ubv( pColor );
	meshBuilder.TexCoord2f( 0, ul.m_TexCoord.x, ul.m_TexCoord.y );
	meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();

	meshBuilder.Position3f( lr.m_Position.x, ul.m_Position.y, m_flZPos );
	meshBuilder.Color4ubv( pColor );
	meshBuilder.TexCoord2f( 0, lr.m_TexCoord.x, ul.m_TexCoord.y );
	meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();

	meshBuilder.Position3f( lr.m_Position.x, lr.m_Position.y, m_flZPos );
	meshBuilder.Color4ubv( pColor );
	meshBuilder.TexCoord2f( 0, lr.m_TexCoord.x, lr.m_TexCoord.y );
	meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();

	meshBuilder.Position3f( ul.m_Position.x, lr.m_Position.y, m_flZPos );
	meshBuilder.Color4ubv( pColor );
	meshBuilder.TexCoord2f( 0, ul.m_TexCoord.x, lr.m_TexCoord.y );
	meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();

	meshBuilder.End();
	m_pMesh->Draw();
}


//-----------------------------------------------------------------------------
// Purpose: Draws an array of quads
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawQuadArray( int quadCount, vgui::Vertex_t *pVerts, unsigned char *pColor, bool bShouldClip )
{
	MAT_FUNC;

	Assert( !m_bIn3DPaintMode );

	if ( !m_pMesh )
		return;

	meshBuilder.Begin( m_pMesh, MATERIAL_QUADS, quadCount );

	vgui::Vertex_t ulc;
	vgui::Vertex_t lrc;
	vgui::Vertex_t *pulc;
	vgui::Vertex_t *plrc;

	if ( bShouldClip )
	{
		for ( int i = 0; i < quadCount; ++i )
		{
			PREFETCH360( &pVerts[ 2 * ( i + 1 ) ], 0 );

			if ( !ClipRect( pVerts[2*i], pVerts[2*i + 1], &ulc, &lrc ) )
			{
				continue;	
			}
			pulc = &ulc;
			plrc = &lrc;

			meshBuilder.Position3f( pulc->m_Position.x, pulc->m_Position.y, m_flZPos );
			meshBuilder.Color4ubv( pColor );
			meshBuilder.TexCoord2f( 0, pulc->m_TexCoord.x, pulc->m_TexCoord.y );
			meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();

			meshBuilder.Position3f( plrc->m_Position.x, pulc->m_Position.y, m_flZPos );
			meshBuilder.Color4ubv( pColor );
			meshBuilder.TexCoord2f( 0, plrc->m_TexCoord.x, pulc->m_TexCoord.y );
			meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();

			meshBuilder.Position3f( plrc->m_Position.x, plrc->m_Position.y, m_flZPos );
			meshBuilder.Color4ubv( pColor );
			meshBuilder.TexCoord2f( 0, plrc->m_TexCoord.x, plrc->m_TexCoord.y );
			meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();

			meshBuilder.Position3f( pulc->m_Position.x, plrc->m_Position.y, m_flZPos );
			meshBuilder.Color4ubv( pColor );
			meshBuilder.TexCoord2f( 0, pulc->m_TexCoord.x, plrc->m_TexCoord.y );
			meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();
		}
	}
	else
	{
		for ( int i = 0; i < quadCount; ++i )
		{
			PREFETCH360( &pVerts[ 2 * ( i + 1 ) ], 0 );

			pulc = &pVerts[2*i];
			plrc = &pVerts[2*i + 1];

			meshBuilder.Position3f( pulc->m_Position.x, pulc->m_Position.y, m_flZPos );
			meshBuilder.Color4ubv( pColor );
			meshBuilder.TexCoord2f( 0, pulc->m_TexCoord.x, pulc->m_TexCoord.y );
			meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();

			meshBuilder.Position3f( plrc->m_Position.x, pulc->m_Position.y, m_flZPos );
			meshBuilder.Color4ubv( pColor );
			meshBuilder.TexCoord2f( 0, plrc->m_TexCoord.x, pulc->m_TexCoord.y );
			meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();

			meshBuilder.Position3f( plrc->m_Position.x, plrc->m_Position.y, m_flZPos );
			meshBuilder.Color4ubv( pColor );
			meshBuilder.TexCoord2f( 0, plrc->m_TexCoord.x, plrc->m_TexCoord.y );
			meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();

			meshBuilder.Position3f( pulc->m_Position.x, plrc->m_Position.y, m_flZPos );
			meshBuilder.Color4ubv( pColor );
			meshBuilder.TexCoord2f( 0, pulc->m_TexCoord.x, plrc->m_TexCoord.y );
			meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();
		}
	}

	meshBuilder.End();
	m_pMesh->Draw();
}


//-----------------------------------------------------------------------------
// Purpose: Draws a rectangle colored with the current drawcolor
//		using the white material
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawFilledRect( int x0, int y0, int x1, int y1 )
{
	MAT_FUNC;

	Assert( g_bInDrawing );

	// Don't even bother drawing fully transparent junk
	if( m_DrawColor[3]!=0 )
	{
		vgui::Vertex_t rect[2];
		vgui::Vertex_t clippedRect[2];
		InitVertex( rect[0], x0, y0, 0, 0 );
		InitVertex( rect[1], x1, y1, 0, 0 );

		// Fully clipped?
		if ( !ClipRect(rect[0], rect[1], &clippedRect[0], &clippedRect[1]) )
			return;	
		
		InternalSetMaterial();
		DrawQuad( clippedRect[0], clippedRect[1], m_DrawColor );
	}
}

//-----------------------------------------------------------------------------
// Purpose: Draws an array of rectangles colored with the current drawcolor
//		using the white material
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawFilledRectArray( IntRect *pRects, int numRects )
{
	MAT_FUNC;

	Assert( g_bInDrawing );

	// Don't even bother drawing fully transparent junk
	if( m_DrawColor[3]==0 )
		return;

	if ( !m_pMesh )
		return;

	InternalSetMaterial( );

	meshBuilder.Begin( m_pMesh, MATERIAL_QUADS, numRects );

	for (int i = 0; i < numRects; ++i )
	{
		vgui::Vertex_t rect[2];
		vgui::Vertex_t clippedRect[2];
		InitVertex( rect[0], pRects[i].x0, pRects[i].y0, 0, 0 );
		InitVertex( rect[1], pRects[i].x1, pRects[i].y1, 0, 0 );
		
		ClipRect( rect[0], rect[1], &clippedRect[0], &clippedRect[1] );
	
		vgui::Vertex_t &ul = clippedRect[0];
		vgui::Vertex_t &lr = clippedRect[1];

		meshBuilder.Position3f( ul.m_Position.x, ul.m_Position.y, m_flZPos );
		meshBuilder.Color4ubv( m_DrawColor );
		meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 0>();

		meshBuilder.Position3f( lr.m_Position.x, ul.m_Position.y, m_flZPos );
		meshBuilder.Color4ubv( m_DrawColor );
		meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 0>();

		meshBuilder.Position3f( lr.m_Position.x, lr.m_Position.y, m_flZPos );
		meshBuilder.Color4ubv( m_DrawColor );
		meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 0>();

		meshBuilder.Position3f( ul.m_Position.x, lr.m_Position.y, m_flZPos );
		meshBuilder.Color4ubv( m_DrawColor );
		meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 0>();
	}

	meshBuilder.End();
	m_pMesh->Draw();
}

//-----------------------------------------------------------------------------
// Draws a fade between the fadeStartPt and fadeEndPT with the current draw color oriented according to argument
//   Example: DrawFilledRectFastFade( 10, 10, 100, 20, 50, 60, 255, 128, true );  
//			  -this will draw 
//					a solid rect (10,10,50,20) //alpha 255
//					a solid rect (50,10,60,20) //alpha faded from 255 to 128
//					a solid rect (60,10,100,20) //alpha 128
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawFilledRectFastFade( int x0, int y0, int x1, int y1, int fadeStartPt, int fadeEndPt, unsigned int alpha0, unsigned int alpha1, bool bHorizontal )
{
	if( bHorizontal )
	{
		if( alpha0 )
		{
			DrawSetColor( m_DrawColor[0], m_DrawColor[1], m_DrawColor[2], alpha0 );
			DrawFilledRect( x0, y0, fadeStartPt, y1 );
		}
		DrawFilledRectFade( fadeStartPt, y0, fadeEndPt, y1, alpha0, alpha1, true );
		if( alpha1 )
		{
			DrawSetColor( m_DrawColor[0], m_DrawColor[1], m_DrawColor[2], alpha1 );
			DrawFilledRect( fadeEndPt, y0, x1, y1 );
		}
	}
	else
	{
		if( alpha0 )
		{
			DrawSetColor( m_DrawColor[0], m_DrawColor[1], m_DrawColor[2], alpha0 );
			DrawFilledRect( x0, y0, x1, fadeStartPt );
		}
		DrawFilledRectFade( x0, fadeStartPt, x1, fadeEndPt, alpha0, alpha1, false );
		if( alpha1 )
		{
			DrawSetColor( m_DrawColor[0], m_DrawColor[1], m_DrawColor[2], alpha1 );
			DrawFilledRect( x0, fadeEndPt, x1, y1 );
		}
	}
}

//-----------------------------------------------------------------------------
// Draws a fade with the current draw color oriented according to argument
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawFilledRectFade( int x0, int y0, int x1, int y1, unsigned int alpha0, unsigned int alpha1, bool bHorizontal )
{
	MAT_FUNC;

	Assert( g_bInDrawing );

	// Scale the desired alphas by the surface alpha
	float alphaScale = m_DrawColor[3] / 255.f;
	alpha0 *= alphaScale;
	alpha1 *= alphaScale;

	// Don't even bother drawing fully transparent junk
	if ( alpha0 == 0 && alpha1 == 0 )
		return;

	vgui::Vertex_t rect[2];
	vgui::Vertex_t clippedRect[2];
	InitVertex( rect[0], x0, y0, 0, 0 );
	InitVertex( rect[1], x1, y1, 0, 0 );

	// Fully clipped?
	if ( !ClipRect(rect[0], rect[1], &clippedRect[0], &clippedRect[1]) )
		return;	
	
	InternalSetMaterial();

	unsigned char colors[4][4] = {{0}};
	for ( int i=0; i<4; i++ )
	{
		// copy the rgb and leave the alpha at zero
		Q_memcpy( colors[i], m_DrawColor, 3 );
	}

	unsigned char nAlpha0 = (alpha0 & 0xFF);
	unsigned char nAlpha1 = (alpha1 & 0xFF);

	if ( bHorizontal )
	{
		// horizontal fade
		colors[0][3] = nAlpha0;
		colors[1][3] = nAlpha1;
		colors[2][3] = nAlpha1;
		colors[3][3] = nAlpha0;
	}
	else
	{
		// vertical fade
		colors[0][3] = nAlpha0;
		colors[1][3] = nAlpha0;
		colors[2][3] = nAlpha1;
		colors[3][3] = nAlpha1;
	}

	meshBuilder.Begin( m_pMesh, MATERIAL_QUADS, 1 );

	meshBuilder.Position3f( clippedRect[0].m_Position.x, clippedRect[0].m_Position.y, m_flZPos );
	meshBuilder.Color4ubv( colors[0] );
	meshBuilder.TexCoord2f( 0, clippedRect[0].m_TexCoord.x, clippedRect[0].m_TexCoord.y );
	meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();

	meshBuilder.Position3f( clippedRect[1].m_Position.x, clippedRect[0].m_Position.y, m_flZPos );
	meshBuilder.Color4ubv( colors[1] );
	meshBuilder.TexCoord2f( 0, clippedRect[1].m_TexCoord.x, clippedRect[0].m_TexCoord.y );
	meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();

	meshBuilder.Position3f( clippedRect[1].m_Position.x, clippedRect[1].m_Position.y, m_flZPos );
	meshBuilder.Color4ubv( colors[2] );
	meshBuilder.TexCoord2f( 0, clippedRect[1].m_TexCoord.x, clippedRect[1].m_TexCoord.y );
	meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();

	meshBuilder.Position3f( clippedRect[0].m_Position.x, clippedRect[1].m_Position.y, m_flZPos );
	meshBuilder.Color4ubv( colors[3] );
	meshBuilder.TexCoord2f( 0, clippedRect[0].m_TexCoord.x, clippedRect[1].m_TexCoord.y );
	meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();

	meshBuilder.End();
	m_pMesh->Draw();
}

//-----------------------------------------------------------------------------
// Purpose: Draws an unfilled rectangle in the current drawcolor
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawOutlinedRect(int x0,int y0,int x1,int y1)
{		
	MAT_FUNC;

	// Don't even bother drawing fully transparent junk
	if ( m_DrawColor[3] == 0 )
		return;

	DrawFilledRect(x0,y0,x1,y0+1);     //top
	DrawFilledRect(x0,y1-1,x1,y1);	   //bottom
	DrawFilledRect(x0,y0+1,x0+1,y1-1); //left
	DrawFilledRect(x1-1,y0+1,x1,y1-1); //right
}


//-----------------------------------------------------------------------------
// Purpose: Draws an outlined circle in the current drawcolor
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawOutlinedCircle(int x, int y, int radius, int segments)
{
	MAT_FUNC;

	Assert( g_bInDrawing );

	Assert( !m_bIn3DPaintMode );

	// Don't even bother drawing fully transparent junk
	if( m_DrawColor[3]==0 )
		return;

	// NOTE: Gotta use lines instead of linelist or lineloop due to clipping
	InternalSetMaterial( );
	meshBuilder.Begin( m_pMesh, MATERIAL_LINES, segments );

	vgui::Vertex_t renderVertex[2];
	vgui::Vertex_t vertex[2];
	vertex[0].m_Position.Init( m_nTranslateX + x + radius, m_nTranslateY + y );
	vertex[0].m_TexCoord.Init( 1.0f, 0.5f );

	float invDelta = 2.0f * M_PI / segments;
	for ( int i = 1; i <= segments; ++i )
	{
		float flRadians = i * invDelta;
		float ca = cos( flRadians );
		float sa = sin( flRadians );
					 
		// Rotate it around the circle
		vertex[1].m_Position.x = m_nTranslateX + x + (radius * ca);
		vertex[1].m_Position.y = m_nTranslateY + y + (radius * sa);
		vertex[1].m_TexCoord.x = 0.5f * (ca + 1.0f);
		vertex[1].m_TexCoord.y = 0.5f * (sa + 1.0f);

		if (ClipLine( vertex, renderVertex ))
		{
			meshBuilder.Position3f( renderVertex[0].m_Position.x, renderVertex[0].m_Position.y, m_flZPos );
			meshBuilder.Color4ubv( m_DrawColor );
			meshBuilder.TexCoord2fv( 0, renderVertex[0].m_TexCoord.Base() );
			meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();

			meshBuilder.Position3f( renderVertex[1].m_Position.x, renderVertex[1].m_Position.y, m_flZPos );
			meshBuilder.Color4ubv( m_DrawColor );
			meshBuilder.TexCoord2fv( 0, renderVertex[1].m_TexCoord.Base() );
			meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();
		}

		vertex[0].m_Position = vertex[1].m_Position;
		vertex[0].m_TexCoord = vertex[1].m_TexCoord;
	}

	meshBuilder.End();
	m_pMesh->Draw();
}


//-----------------------------------------------------------------------------
// Loads a particular texture (material)
//-----------------------------------------------------------------------------
int CMatSystemSurface::CreateNewTextureID( bool procedural /*=false*/ )
{
	return TextureDictionary()->CreateTexture( procedural );
}

void CMatSystemSurface::DestroyTextureID( int id )
{
	TextureDictionary()->DestroyTexture( id );
}

bool CMatSystemSurface::DeleteTextureByID(int id)
{
	TextureDictionary()->DestroyTexture( id );
	return false;
}

#ifdef _X360
void CMatSystemSurface::UncacheUnusedMaterials()
{
	// unbind any currently set texture (which may be uncached)
	DrawSetTexture( -1 );

	// X360TBD: Need to only destroy "marked" textures
}
#endif

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : id - 
//			*filename - 
//			maxlen - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CMatSystemSurface::DrawGetTextureFile(int id, char *filename, int maxlen )
{
	if ( !TextureDictionary()->IsValidId( id ) )
		return false;

	IMaterial *texture = TextureDictionary()->GetTextureMaterial(id);
	if ( !texture )
		return false;

	Q_strncpy( filename, texture->GetName(), maxlen );
	return true;
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : id - texture id
// Output : returns IMaterial for the referenced texture
//-----------------------------------------------------------------------------
IVguiMatInfo *CMatSystemSurface::DrawGetTextureMatInfoFactory(int id)
{
	if ( !TextureDictionary()->IsValidId( id ) )
		return NULL;

	IMaterial *texture = TextureDictionary()->GetTextureMaterial(id);

	if ( texture == NULL )
		return NULL;

	return new CVguiMatInfo(texture);
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *filename - 
// Output : int
//-----------------------------------------------------------------------------
int CMatSystemSurface::DrawGetTextureId( char const *filename )
{
	return TextureDictionary()->FindTextureIdForTextureFile( filename );
}


//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *pTexture
// Output : int
//-----------------------------------------------------------------------------
int CMatSystemSurface::DrawGetTextureId( ITexture *pTexture )
{
	return TextureDictionary()->CreateTextureByTexture( pTexture );
}


//-----------------------------------------------------------------------------
// Associates a texture with a material file (also binds it)
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawSetTextureFile(int id, const char *pFileName, int hardwareFilter, bool forceReload /*= false*/)
{
	TextureDictionary()->BindTextureToFile( id, pFileName );
	DrawSetTexture( id );
}


//-----------------------------------------------------------------------------
// Associates a texture with a material file (also binds it)
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawSetTextureMaterial(int id, IMaterial *pMaterial)
{
	TextureDictionary()->BindTextureToMaterial( id, pMaterial );
	DrawSetTexture( id );
}

IMaterial *CMatSystemSurface::DrawGetTextureMaterial( int id )
{
	return TextureDictionary()->GetTextureMaterial( id );
}


void CMatSystemSurface::ReferenceProceduralMaterial( int id, int referenceId, IMaterial *pMaterial )
{
	TextureDictionary()->BindTextureToMaterialReference( id, referenceId, pMaterial );
}


//-----------------------------------------------------------------------------
// Binds a texture
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawSetTexture( int id )
{
	// if we're switching textures, flush any batched text
	if ( id != m_iBoundTexture )
	{
		DrawFlushText();
		m_iBoundTexture = id;

		if ( IsX360() && id == -1 )
		{
			// ensure we unbind current material that may go away
			CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
			pRenderContext->Bind( m_pWhite );
		}
	}
}


//-----------------------------------------------------------------------------
// Returns texture size
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawGetTextureSize(int id, int &iWide, int &iTall)
{
	TextureDictionary()->GetTextureSize( id, iWide, iTall );
}


//-----------------------------------------------------------------------------
// Draws a textured rectangle
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawTexturedRect( int x0, int y0, int x1, int y1 )
{
	MAT_FUNC;

	Assert( g_bInDrawing );

	// Don't even bother drawing fully transparent junk
	if( m_DrawColor[3] == 0 )
		return;

	float s0, t0, s1, t1;
	TextureDictionary()->GetTextureTexCoords( m_iBoundTexture, s0, t0, s1, t1 );

	vgui::Vertex_t rect[2];
	vgui::Vertex_t clippedRect[2];
	InitVertex( rect[0], x0, y0, s0, t0 );
	InitVertex( rect[1], x1, y1, s1, t1 );

	// Fully clipped?
	if ( !ClipRect(rect[0], rect[1], &clippedRect[0], &clippedRect[1]) )
		return;	

	IMaterial *pMaterial = TextureDictionary()->GetTextureMaterial(m_iBoundTexture);
	InternalSetMaterial( pMaterial );
	DrawQuad( clippedRect[0], clippedRect[1], m_DrawColor );
}

//-----------------------------------------------------------------------------
// Draws a textured rectangle
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawTexturedSubRect( int x0, int y0, int x1, int y1, float texs0, float text0, float texs1, float text1 )
{
	MAT_FUNC;

	Assert( g_bInDrawing );

	// Don't even bother drawing fully transparent junk
	if( m_DrawColor[3] == 0 )
		return;

	float s0, t0, s1, t1;
	TextureDictionary()->GetTextureTexCoords( m_iBoundTexture, s0, t0, s1, t1 );

	float ssize = s1 - s0;
	float tsize = t1 - t0;

	// Rescale tex values into range of s0 to s1 ,etc.
	texs0 = s0 + texs0 * ( ssize );
	texs1 = s0 + texs1 * ( ssize );
	text0 = t0 + text0 * ( tsize );
	text1 = t0 + text1 * ( tsize );

	vgui::Vertex_t rect[2];
	vgui::Vertex_t clippedRect[2];
	InitVertex( rect[0], x0, y0, texs0, text0 );
	InitVertex( rect[1], x1, y1, texs1, text1 );

	// Fully clipped?
	if ( !ClipRect(rect[0], rect[1], &clippedRect[0], &clippedRect[1]) )
		return;	

	IMaterial *pMaterial = TextureDictionary()->GetTextureMaterial(m_iBoundTexture);
	InternalSetMaterial( pMaterial );
	DrawQuad( clippedRect[0], clippedRect[1], m_DrawColor );
}

//-----------------------------------------------------------------------------
// Draws a textured polygon
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawTexturedPolygon(int n, Vertex_t *pVertices, bool bClipVertices /*= true*/ )
{
	MAT_FUNC;

	Assert( !m_bIn3DPaintMode );

	Assert( g_bInDrawing );

	// Don't even bother drawing fully transparent junk
	if( (n == 0) || (m_DrawColor[3]==0) )
		return;

	if ( bClipVertices )
	{
		int iCount;
		Vertex_t **ppClippedVerts = NULL;
		iCount = ClipPolygon( n, pVertices, m_nTranslateX, m_nTranslateY, &ppClippedVerts );
		if (iCount <= 0)
			return;

		IMaterial *pMaterial = TextureDictionary()->GetTextureMaterial(m_iBoundTexture);
		InternalSetMaterial( pMaterial );

		meshBuilder.Begin( m_pMesh, MATERIAL_POLYGON, iCount );

		for (int i = 0; i < iCount; ++i)
		{
			meshBuilder.Position3f( ppClippedVerts[i]->m_Position.x, ppClippedVerts[i]->m_Position.y, m_flZPos );
			meshBuilder.Color4ubv( m_DrawColor );
			meshBuilder.TexCoord2fv( 0, ppClippedVerts[i]->m_TexCoord.Base() );
			meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();
		}

		meshBuilder.End();
		m_pMesh->Draw();
	}
	else
	{
		IMaterial *pMaterial = TextureDictionary()->GetTextureMaterial(m_iBoundTexture);
		InternalSetMaterial( pMaterial );

		meshBuilder.Begin( m_pMesh, MATERIAL_POLYGON, n );

		for (int i = 0; i < n; ++i)
		{
			meshBuilder.Position3f( pVertices[i].m_Position.x + m_nTranslateX, pVertices[i].m_Position.y + m_nTranslateY, m_flZPos );
			meshBuilder.Color4ubv( m_DrawColor );
			meshBuilder.TexCoord2fv( 0, pVertices[i].m_TexCoord.Base() );
			meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();
		}

		meshBuilder.End();
		m_pMesh->Draw();
	}
}



//-----------------------------------------------------------------------------
//
// Font-related methods begin here
//
//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
// Purpose: creates a new empty font
//-----------------------------------------------------------------------------
HFont CMatSystemSurface::CreateFont()
{
	MAT_FUNC;

	return FontManager().CreateFont();
}

//-----------------------------------------------------------------------------
// Purpose: adds glyphs to a font created by CreateFont()
//-----------------------------------------------------------------------------
bool CMatSystemSurface::SetFontGlyphSet(HFont font, const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags, int nRangeMin, int nRangeMax)
{
	return FontManager().SetFontGlyphSet(font, windowsFontName, tall, weight, blur, scanlines, flags, nRangeMin, nRangeMax);
}

//-----------------------------------------------------------------------------
// Purpose: adds glyphs to a font created by CreateFont()
//-----------------------------------------------------------------------------
bool CMatSystemSurface::SetBitmapFontGlyphSet(HFont font, const char *windowsFontName, float scalex, float scaley, int flags)
{
	return FontManager().SetBitmapFontGlyphSet(font, windowsFontName, scalex, scaley, flags);
}

//-----------------------------------------------------------------------------
// Purpose: returns the max height of a font
//-----------------------------------------------------------------------------
int CMatSystemSurface::GetFontTall(HFont font)
{
	return FontManager().GetFontTall(font);
}

//-----------------------------------------------------------------------------
// Purpose: returns the requested height of a font
//-----------------------------------------------------------------------------
int CMatSystemSurface::GetFontTallRequested(HFont font)
{
	return FontManager().GetFontTallRequested(font);
}

//-----------------------------------------------------------------------------
// Purpose: returns the max height of a font
//-----------------------------------------------------------------------------
int CMatSystemSurface::GetFontAscent(HFont font, wchar_t wch)
{
	return FontManager().GetFontAscent(font,wch);
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : font - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CMatSystemSurface::IsFontAdditive(HFont font)
{
	return FontManager().IsFontAdditive(font);
}

//-----------------------------------------------------------------------------
// Purpose: returns the abc widths of a single character
//-----------------------------------------------------------------------------
void CMatSystemSurface::GetCharABCwide(HFont font, int ch, int &a, int &b, int &c)
{
	FontManager().GetCharABCwide(font, ch, a, b, c);
}

//-----------------------------------------------------------------------------
// Purpose: returns the pixel width of a single character
//-----------------------------------------------------------------------------
int CMatSystemSurface::GetCharacterWidth(HFont font, int ch)
{
	return FontManager().GetCharacterWidth(font, ch);
}

//-----------------------------------------------------------------------------
// Purpose: returns the kerned width of this char
//-----------------------------------------------------------------------------
void CMatSystemSurface::GetKernedCharWidth( HFont font, wchar_t ch, wchar_t chBefore, wchar_t chAfter, float &wide, float &abcA ) //, float &abcC )
{
	float abcC = 0.0f;
	FontManager().GetKernedCharWidth(font, ch, chBefore, chAfter, wide, abcA, abcC );
}


//-----------------------------------------------------------------------------
// Purpose: returns the area of a text string, including newlines
//-----------------------------------------------------------------------------
void CMatSystemSurface::GetTextSize(HFont font, const wchar_t *text, int &wide, int &tall)
{
	FontManager().GetTextSize(font, text, wide, tall);
}

//-----------------------------------------------------------------------------
// Purpose: adds a custom font file (only supports true type font files (.ttf) for now)
//-----------------------------------------------------------------------------
bool CMatSystemSurface::AddCustomFontFile( const char *fontName, const char *fontFileName )
{
	if ( IsX360() )
	{
		// custom fonts are not supported (not needed) on xbox, all .vfonts are offline converted to ttfs
		// ttfs are mounted/handled elsewhere
		return true;
	}
	MAT_FUNC;

	char fullPath[MAX_PATH];
	bool bFound = false;
	// windows needs an absolute path for ttf
	bFound = g_pFullFileSystem->GetLocalPath( fontFileName, fullPath, sizeof( fullPath ) );
	if ( !bFound )
	{
		Warning( "Couldn't find custom font file '%s'\n", fontFileName );
		return false;
	}

	// only add if it's not already in the list
	Q_strlower( fullPath );
	CUtlSymbol sym(fullPath);
	int i;
	for ( i = 0; i < m_CustomFontFileNames.Count(); i++ )
	{
		if ( m_CustomFontFileNames[i] == sym )
			break;
	}
	if ( !m_CustomFontFileNames.IsValidIndex( i ) )
	{
	 	m_CustomFontFileNames.AddToTail( fullPath );

		if ( IsPC() )
		{
			// make sure it's on disk
			// only do this once for each font since in steam it will overwrite the
			// registered font file, causing windows to invalidate the font
			g_pFullFileSystem->GetLocalCopy( fullPath );
		}
	}

	// try and use the optimal custom font loader, will makes sure fonts are unloaded properly
	// this function is in a newer version of the gdi library (win2k+), so need to try get it directly
#if defined( WIN32 ) && !defined( _X360 )
	bool successfullyAdded = false;
	HMODULE gdiModule = ::LoadLibrary("gdi32.dll");
	if (gdiModule)
	{
		typedef int (WINAPI *AddFontResourceExProc)(LPCTSTR, DWORD, PVOID);
		AddFontResourceExProc pAddFontResourceEx = (AddFontResourceExProc)::GetProcAddress(gdiModule, "AddFontResourceExA");
		if (pAddFontResourceEx)
		{
			int result = (*pAddFontResourceEx)(fullPath, 0x10, NULL);
			if (result > 0)
			{
				successfullyAdded = true;
			}
		}
		::FreeLibrary(gdiModule);
	}

	// add to windows
	bool success = successfullyAdded || (::AddFontResource(fullPath) > 0);
	if ( !success )
	{
		Msg( "Failed to load custom font file '%s'\n", fullPath );
	}
	Assert( success );
	return success;
#elif defined(LINUX) || defined(OSX) || defined(PLATFORM_BSD)

	int size;
	if ( CMatSystemSurface::FontDataHelper( fontName, size, fontFileName ) )
		return true;
	return false;

#elif defined( _X360 )
#include "xbox/xbox_win32stubs.h"
#else
#error	
#endif
}

#if defined(LINUX) || defined(OSX) || defined(PLATFORM_BSD)

static void RemoveSpaces( CUtlString &str )
{
	char *dst = str.GetForModify();

	for( int i = 0; i < str.Length(); i++ )
	{
		if( ( str[ i ] != ' ' ) && ( str[ i ] != '-' ) )
		{
			*dst++ = str[ i ];
		}
	}

	*dst = 0;
}

void *CMatSystemSurface::FontDataHelper( const char *pchFontName, int &size, const char *fontFileName )
{
	size = 0;

	if( fontFileName )
	{
		// If we were given a fontFileName, then load that bugger and shove it in the cache.

		// Just load the font data, decrypt in memory and register for this process
		CUtlBuffer buf;
		if ( !g_pFullFileSystem->ReadFile( fontFileName, NULL, buf ) )
		{
			Msg( "Failed to load custom font file '%s'\n", fontFileName );
			return NULL;
		}

		FT_Face face;
		const FT_Error error = FT_New_Memory_Face( FontManager().GetFontLibraryHandle(), (FT_Byte *)buf.Base(), buf.TellPut(), 0, &face );

		if ( error  ) 
		{
			// FT_Err_Unknown_File_Format, etc.
			Msg( "ERROR %d: UNABLE TO LOAD FONT FILE %s\n", error, fontFileName );
			return NULL;
		}

		if( !pchFontName )
		{
			// If we weren't passed a font name for this thing, then use the one from the face.
			pchFontName = face->family_name;
			if ( !pchFontName || !pchFontName[ 0 ] )
			{
				pchFontName = FT_Get_Postscript_Name( face );
			}
		}

		// Replace spaces and dashes with underscores.
		CUtlString strFontName( pchFontName );
		RemoveSpaces( strFontName );

		font_entry entry;
		entry.size = buf.TellPut();
		entry.data = malloc( entry.size );
		memcpy( entry.data, buf.Base(), entry.size );
		m_FontData.Insert( strFontName.Get(), entry );

		FT_Done_Face( face );

		size = entry.size;
		return entry.data;
	}
	else
	{
		// Replace spaces and dashes with underscores.
		CUtlString strFontName( pchFontName );
		RemoveSpaces( strFontName );

		int iIndex = m_FontData.Find( strFontName.Get() );
		if ( iIndex != m_FontData.InvalidIndex() )
		{
			size = m_FontData[ iIndex ].size;
			return m_FontData[ iIndex ].data;
		}
	}

	return NULL;
}

#endif // LINUX

//-----------------------------------------------------------------------------
// Purpose: adds a bitmap font file
//-----------------------------------------------------------------------------
bool CMatSystemSurface::AddBitmapFontFile( const char *fontFileName )
{
	MAT_FUNC;

	bool bFound = false;
	bFound = ( ( g_pFullFileSystem->GetDVDMode() == DVDMODE_STRICT ) || g_pFullFileSystem->FileExists( fontFileName, IsX360() ? "GAME" : NULL ) );
	if ( !bFound )
	{
		Msg( "Couldn't find bitmap font file '%s'\n", fontFileName );
		return false;
	}
	char path[MAX_PATH];
	Q_strncpy( path, fontFileName, MAX_PATH );

	// only add if it's not already in the list
	Q_strlower( path );
	CUtlSymbol sym( path );
	int i;
	for ( i = 0; i < m_BitmapFontFileNames.Count(); i++ )
	{
		if ( m_BitmapFontFileNames[i] == sym )
			break;
	}
	if ( !m_BitmapFontFileNames.IsValidIndex( i ) )
	{
	 	m_BitmapFontFileNames.AddToTail( path );

		if ( IsPC() )
		{
			// make sure it's on disk
			// only do this once for each font since in steam it will overwrite the
			// registered font file, causing windows to invalidate the font
			g_pFullFileSystem->GetLocalCopy( path );
		}
	}

	return true;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CMatSystemSurface::SetBitmapFontName( const char *pName, const char *pFontFilename )
{
	char fontPath[MAX_PATH];
	Q_strncpy( fontPath, pFontFilename, MAX_PATH );
	Q_strlower( fontPath );

	CUtlSymbol sym( fontPath );
	int i;
	for (i = 0; i < m_BitmapFontFileNames.Count(); i++)
	{
		if ( m_BitmapFontFileNames[i] == sym )
		{
			// found it, update the mapping
			int index = m_BitmapFontFileMapping.Find( pName );
			if ( !m_BitmapFontFileMapping.IsValidIndex( index ) )
			{
				index = m_BitmapFontFileMapping.Insert( pName );	
			}
			m_BitmapFontFileMapping.Element( index ) = i;
			break;
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
const char *CMatSystemSurface::GetBitmapFontName( const char *pName )
{
	// find it in the mapping symbol table
	int index = m_BitmapFontFileMapping.Find( pName );
	if ( index == m_BitmapFontFileMapping.InvalidIndex() )
	{
		return "";
	}

	return m_BitmapFontFileNames[m_BitmapFontFileMapping.Element( index )].String();
}

void CMatSystemSurface::ClearTemporaryFontCache( void )
{
	FontManager().ClearTemporaryFontCache();
}

//-----------------------------------------------------------------------------
// Purpose: Force a set of characters to be rendered into the font page.
//-----------------------------------------------------------------------------
void CMatSystemSurface::PrecacheFontCharacters( HFont font, const wchar_t *pCharacterString )
{
	wchar_t *pCommonChars = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,.!:-/%";
	MAT_FUNC;

	if ( !pCharacterString || !pCharacterString[0] )
	{
		// use the common chars, alternate languages are not handled
		pCharacterString = pCommonChars;
	}

	StartDrawing();
	DrawSetTextFont( font );

	int numChars = 0;
	while( pCharacterString[ numChars ] )
	{
		numChars++;
	}
	int *pTextureIDs_ignored = (int *)_alloca( numChars*sizeof( int ) );
	float **pTexCoords_ignored = (float **)_alloca( numChars*sizeof( float * ) );
	g_FontTextureCache.GetTextureForChars( m_hCurrentFont, FONT_DRAW_DEFAULT, pCharacterString, pTextureIDs_ignored, pTexCoords_ignored, numChars );

	FinishDrawing();
}

const char *CMatSystemSurface::GetFontName( HFont font )
{
	return FontManager().GetFontName( font );
}

const char *CMatSystemSurface::GetFontFamilyName( HFont font )
{
	return FontManager().GetFontFamilyName( font );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawSetTextFont(HFont font)
{
	Assert( g_bInDrawing );

	m_hCurrentFont = font;
}

//-----------------------------------------------------------------------------
// Purpose: Renders any batched up text
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawFlushText()
{
	if ( !m_nBatchedCharVertCount )
		return;

	{
		// don't log entry unless actual work happens..
		MAT_FUNC;
		
		IMaterial *pMaterial = TextureDictionary()->GetTextureMaterial(m_iBoundTexture);
		InternalSetMaterial( pMaterial );
		DrawQuadArray( m_nBatchedCharVertCount / 2, m_BatchedCharVerts, m_DrawTextColor );
		m_nBatchedCharVertCount = 0;
	}
}

//-----------------------------------------------------------------------------
// Sets the text color
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawSetTextColor(int r, int g, int b, int a)
{
	int adjustedAlpha = (a * m_flAlphaMultiplier);

	if ( r != m_DrawTextColor[0] || g != m_DrawTextColor[1] || b != m_DrawTextColor[2] || adjustedAlpha != m_DrawTextColor[3] )
	{
		// text color changed, flush any existing text
		DrawFlushText();

		m_DrawTextColor[0] = (unsigned char)r;
		m_DrawTextColor[1] = (unsigned char)g;
		m_DrawTextColor[2] = (unsigned char)b;
		m_DrawTextColor[3] = (unsigned char)adjustedAlpha;
	}
}

//-----------------------------------------------------------------------------
// Purpose: alternate color set
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawSetTextColor(Color col)
{
	DrawSetTextColor(col[0], col[1], col[2], col[3]);
}

//-----------------------------------------------------------------------------
// Purpose: change the scale of a bitmap font
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawSetTextScale(float sx, float sy)
{
	FontManager().SetFontScale( m_hCurrentFont, sx, sy );
}

//-----------------------------------------------------------------------------
// Text rendering location
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawSetTextPos(int x, int y)
{
	Assert( g_bInDrawing );

	m_pDrawTextPos[0] = x;
	m_pDrawTextPos[1] = y;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawGetTextPos(int& x,int& y)
{
	Assert( g_bInDrawing );

	x = m_pDrawTextPos[0];
	y = m_pDrawTextPos[1];
}

#pragma warning( disable : 4706 )
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawUnicodeString( const wchar_t *pString, FontDrawType_t drawType /*= FONT_DRAW_DEFAULT */ )
{
	// skip fully transparent characters
	if ( m_DrawTextColor[3] == 0 )
		return;

	//hushed MAT_FUNC;
#ifdef POSIX
	DrawPrintText( pString, V_wcslen( pString ) , drawType );
#else
	wchar_t	ch;

	while ( ( ch = *pString++ ) )
	{
		DrawUnicodeChar( ch );	
	}
#endif
}
#pragma warning( default : 4706 )

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawUnicodeChar(wchar_t ch, FontDrawType_t drawType /*= FONT_DRAW_DEFAULT */ )
{
	// skip fully transparent characters
	if ( m_DrawTextColor[3] == 0 )
		return;
	//hushed MAT_FUNC;

	CharRenderInfo info;
	info.drawType = drawType;
	if ( DrawGetUnicodeCharRenderInfo( ch, info ) )
	{
		DrawRenderCharFromInfo( info );
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool CMatSystemSurface::DrawGetUnicodeCharRenderInfo( wchar_t ch, CharRenderInfo& info )
{
	//hushed MAT_FUNC;

	Assert( g_bInDrawing );
	info.valid = false;

	if ( !m_hCurrentFont )
	{
		return info.valid;
	}

	PREFETCH360( &m_BatchedCharVerts[ m_nBatchedCharVertCount ], 0 );

	info.valid = true;
	info.ch = ch;
	DrawGetTextPos(info.x, info.y);

	info.currentFont = m_hCurrentFont;
	info.fontTall = GetFontTall(m_hCurrentFont);

	GetCharABCwide(m_hCurrentFont, ch, info.abcA, info.abcB, info.abcC);
	bool bUnderlined = FontManager().GetFontUnderlined( m_hCurrentFont );
	
	// Do prestep before generating texture coordinates, etc.
	if ( !bUnderlined )
	{
		info.x += info.abcA;
	}

	// get the character texture from the cache
	info.textureId = 0;
	float *texCoords = NULL;
	if (!g_FontTextureCache.GetTextureForChar(m_hCurrentFont, info.drawType, ch, &info.textureId, &texCoords))
	{
		info.valid = false;
		return info.valid;
	}

	int fontWide = info.abcB;
	if ( bUnderlined )
	{
		fontWide += ( info.abcA + info.abcC );
		info.x-= info.abcA;
	}

	// Because CharRenderInfo has a pointer to the verts, we need to keep m_BatchedCharVerts in sync, so if we 
	//  will be flushing the text when we get to this char, flush it now instead.
	if ( info.textureId != m_iBoundTexture )
	{
		DrawFlushText();
	}

	// This avoid copying the data in the nonclipped case!!! (X360)
	info.verts = &m_BatchedCharVerts[ m_nBatchedCharVertCount ];
	InitVertex( info.verts[0], info.x, info.y, texCoords[0], texCoords[1] );
	InitVertex( info.verts[1], info.x + fontWide, info.y + info.fontTall, texCoords[2], texCoords[3] );

	info.shouldclip = true;

	return info.valid;
}

//-----------------------------------------------------------------------------
// Purpose: batches up characters for rendering
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawRenderCharInternal( const CharRenderInfo& info )
{
	//hushed MAT_FUNC;

	Assert( g_bInDrawing );
	
	// xbox opts out of pricey/pointless text clipping
	if ( IsPC() && info.shouldclip )
	{
		Vertex_t clip[ 2 ];
		clip[ 0 ] = info.verts[ 0 ];
		clip[ 1 ] = info.verts[ 1 ];
		if ( !ClipRect( clip[0], clip[1], &info.verts[0], &info.verts[1] ) )
		{
			// Fully clipped
			return;	
		}
	}

	m_nBatchedCharVertCount += 2;

	if ( m_nBatchedCharVertCount >= MAX_BATCHED_CHAR_VERTS - 2 )
	{
		DrawFlushText();
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawRenderCharFromInfo( const CharRenderInfo& info )
{
	//hushed MAT_FUNC;

	if ( !info.valid )
		return;

	int x = info.x;

	// get the character texture from the cache
	DrawSetTexture( info.textureId );
	
	DrawRenderCharInternal( info );

	// Only do post step
	x += ( info.abcB + info.abcC );

	// Update cursor pos
	DrawSetTextPos(x, info.y);
}

//-----------------------------------------------------------------------------
// Renders a text buffer
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawPrintText(const wchar_t *text, int iTextLen, FontDrawType_t drawType /*= FONT_DRAW_DEFAULT */ )
{
	MAT_FUNC;

	Assert( g_bInDrawing );
	if (!text)
		return;

	if (!m_hCurrentFont)
		return;

	int x = m_pDrawTextPos[0] + m_nTranslateX;
	int y = m_pDrawTextPos[1] + m_nTranslateY;

	int iTall = GetFontTall(m_hCurrentFont);
	int iLastTexId = -1;

	int iCount = 0;
	vgui::Vertex_t *pQuads = (vgui::Vertex_t*)stackalloc((2 * iTextLen) * sizeof(vgui::Vertex_t) );
	bool bUnderlined = FontManager().GetFontUnderlined( m_hCurrentFont );

	int iTotalWidth = 0;
	for (int i=0; i<iTextLen; ++i)
	{
		wchar_t ch = text[i];

#if USE_GETKERNEDCHARWIDTH
		//iTotalWidth += abcA;
		float flWide;
		float flabcA;
		float flabcC;
		wchar_t chBefore = 0;
		wchar_t chAfter = 0;
		if ( i > 0 )
			chBefore = text[i-1];
		if ( i < (iTextLen-1) )
			chAfter = text[i+1];
		FontManager().GetKernedCharWidth( m_hCurrentFont, ch, chBefore, chAfter, flWide, flabcA, flabcC );
		
		int abcA,abcB,abcC;
		// also grab the single char dimensions so we match the texture size to the one in the font page,
		// different to the amount we step ahead once rendered
		GetCharABCwide(m_hCurrentFont, ch, abcA, abcB, abcC);
		
		int textureWide = abcB;
		if ( bUnderlined )
		{
			textureWide += ( abcA + abcC );
			x-= flabcA;
		}
#else
		int abcA,abcB,abcC;
		GetCharABCwide(m_hCurrentFont, ch, abcA, abcB, abcC);
		int textureWide = abcB;
		if ( bUnderlined )
		{
			textureWide += ( abcA + abcC );
			x-= abcA;
		}
		float flabcA = abcA;
		float flWide = abcA + abcB + abcC;
#endif
		
		if ( !iswspace( ch ) || bUnderlined )
		{
			// get the character texture from the cache
			int iTexId = 0;
			float *texCoords = NULL;
			if (!g_FontTextureCache.GetTextureForChar(m_hCurrentFont, drawType, ch, &iTexId, &texCoords))
				continue;

			Assert( texCoords );

			if (iTexId != iLastTexId)
			{
				// FIXME: At the moment, we just draw all the batched up
				// text when the font changes. We Should batch up per material
				// and *then* draw
				if (iCount)
				{
					IMaterial *pMaterial = TextureDictionary()->GetTextureMaterial(iLastTexId);
					InternalSetMaterial( pMaterial );
					DrawQuadArray( iCount, pQuads, m_DrawTextColor, IsPC() );
					iCount = 0;
				}

				iLastTexId = iTexId;
			}

 			vgui::Vertex_t &ul = pQuads[2*iCount];
 			vgui::Vertex_t &lr = pQuads[2*iCount + 1];
			++iCount;

			ul.m_Position.x = x + iTotalWidth + floor(flabcA + 0.6);
			ul.m_Position.y = y;
			lr.m_Position.x = ul.m_Position.x +  textureWide;
			lr.m_Position.y = ul.m_Position.y + iTall;

			// Gets at the texture coords for this character in its texture page
			/*
			float tex_U0_bias = prc->Knob("tex-U0-bias");
			float tex_V0_bias = prc->Knob("tex-V0-bias");
			float tex_U1_bias = prc->Knob("tex-U1-bias");
			float tex_V1_bias = prc->Knob("tex-V1-bias");

			ul.m_TexCoord[0] = texCoords[0] + tex_U0_bias;
			ul.m_TexCoord[1] = texCoords[1] + tex_V0_bias;
			lr.m_TexCoord[0] = texCoords[2] + tex_U1_bias;
			lr.m_TexCoord[1] = texCoords[3] + tex_V1_bias;
			*/

			ul.m_TexCoord[0] = texCoords[0];
			ul.m_TexCoord[1] = texCoords[1];
			lr.m_TexCoord[0] = texCoords[2];
			lr.m_TexCoord[1] = texCoords[3];
		}

		iTotalWidth += floor(flWide+0.6);
	}

	// Draw any left-over characters
	if (iCount)
	{
		IMaterial *pMaterial = TextureDictionary()->GetTextureMaterial(iLastTexId);
		InternalSetMaterial( pMaterial );
		DrawQuadArray( iCount, pQuads, m_DrawTextColor, IsPC() );
	}

	m_pDrawTextPos[0] += iTotalWidth;

	stackfree(pQuads);
}


//-----------------------------------------------------------------------------
// Returns the screen size
//-----------------------------------------------------------------------------
void CMatSystemSurface::GetScreenSize(int &iWide, int &iTall)
{
	if ( m_ScreenSizeOverride.m_bActive )
	{
		iWide = m_ScreenSizeOverride.m_nValue[ 0 ];
		iTall = m_ScreenSizeOverride.m_nValue[ 1 ];
		return;
	}

	int x, y;

	// mikesart: This is just sticking in unnecessary BeginRender/EndRender calls to the queue.
	//   CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
	IMatRenderContext *pRenderContext = g_pMaterialSystem->GetRenderContext();
	pRenderContext->GetViewport( x, y, iWide, iTall );
}

bool CMatSystemSurface::ForceScreenSizeOverride( bool bState, int wide, int tall )
{
	bool bWasSet = m_ScreenSizeOverride.m_bActive;
	m_ScreenSizeOverride.m_bActive = bState;
	m_ScreenSizeOverride.m_nValue[ 0 ] = wide;
	m_ScreenSizeOverride.m_nValue[ 1 ] = tall;
	return bWasSet;
}

// LocalToScreen, ParentLocalToScreen fixups for explicit PaintTraverse calls on Panels not at 0, 0 position
bool CMatSystemSurface::ForceScreenPosOffset( bool bState, int x, int y )
{
	bool bWasSet = m_ScreenPosOverride.m_bActive;
	m_ScreenPosOverride.m_bActive = bState;
	m_ScreenPosOverride.m_nValue[ 0 ] = x;
	m_ScreenPosOverride.m_nValue[ 1 ] = y;
	return bWasSet;
}

void CMatSystemSurface::OffsetAbsPos( int &x, int &y )
{
	if ( !m_ScreenPosOverride.m_bActive )
		return;

	x += m_ScreenPosOverride.m_nValue[ 0 ];
	y += m_ScreenPosOverride.m_nValue[ 1 ];
}


bool CMatSystemSurface::IsScreenSizeOverrideActive( void )
{
	return ( m_ScreenSizeOverride.m_bActive );
}

bool CMatSystemSurface::IsScreenPosOverrideActive( void )
{
	return ( m_ScreenPosOverride.m_bActive );
}


//-----------------------------------------------------------------------------
// Purpose: Notification of a new screen size
//-----------------------------------------------------------------------------
void CMatSystemSurface::OnScreenSizeChanged( int nOldWidth, int nOldHeight )
{
	int iNewWidth, iNewHeight;
	GetScreenSize( iNewWidth, iNewHeight );

	Msg( "Changing resolutions from (%d, %d) -> (%d, %d)\n", nOldWidth, nOldHeight, iNewWidth, iNewHeight );

	// update the root panel size
	ipanel()->SetSize(m_pEmbeddedPanel, iNewWidth, iNewHeight);

	// notify every panel
	VPANEL panel = GetEmbeddedPanel();
	ivgui()->PostMessage(panel, new KeyValues("OnScreenSizeChanged", "oldwide", nOldWidth, "oldtall", nOldHeight), NULL);

	// Run a frame of the GUI to notify all subwindows of the message size change
	ivgui()->RunFrame();

	// clear font texture cache
	ResetFontCaches();
}

// Causes fonts to get reloaded, etc.
void CMatSystemSurface::ResetFontCaches()
{
	// Don't do this on x360!!!
	if ( IsX360() )
		return;

	// clear font texture cache
	g_FontTextureCache.Clear();
	m_iBoundTexture = -1;

	// reload fonts
	FontManager().ClearAllFonts();
	scheme()->ReloadFonts();
	
	// Run a frame of the GUI to notify all subwindows of the message size change
	ivgui()->RunFrame();
}

//-----------------------------------------------------------------------------
// Returns the size of the embedded panel
//-----------------------------------------------------------------------------
void CMatSystemSurface::GetWorkspaceBounds(int &x, int &y, int &iWide, int &iTall)
{
	if ( m_ScreenSizeOverride.m_bActive )
	{
		x = y = 0;
		iWide = m_ScreenSizeOverride.m_nValue[ 0 ];
		iTall = m_ScreenSizeOverride.m_nValue[ 1 ];
		return;
	}
	// NOTE: This is equal to the viewport size by default,
	// but other embedded panels can be used
	x = m_WorkSpaceInsets[0];
	y = m_WorkSpaceInsets[1];
	g_pVGuiPanel->GetSize(m_pEmbeddedPanel, iWide, iTall);

	iWide -= m_WorkSpaceInsets[2];
	iTall -= m_WorkSpaceInsets[3];
}


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CMatSystemSurface::SetWorkspaceInsets( int left, int top, int right, int bottom )
{
	m_WorkSpaceInsets[0] = left;
	m_WorkSpaceInsets[1] = top;
	m_WorkSpaceInsets[2] = right;
	m_WorkSpaceInsets[3] = bottom;
}

//-----------------------------------------------------------------------------
// A bunch of methods needed for the windows version only
//-----------------------------------------------------------------------------
void CMatSystemSurface::SetAsTopMost(VPANEL panel, bool state)
{
}

void CMatSystemSurface::SetAsToolBar(VPANEL panel, bool state)		// removes the window's task bar entry (for context menu's, etc.)
{
}

void CMatSystemSurface::SetForegroundWindow (VPANEL panel)
{
	BringToFront(panel);
}

void CMatSystemSurface::SetPanelVisible(VPANEL panel, bool state)
{
}

void CMatSystemSurface::SetMinimized(VPANEL panel, bool state)
{
	if (state)
	{
		g_pVGuiPanel->SetPlat(panel, VPANEL_MINIMIZED);
		g_pVGuiPanel->SetVisible(panel, false);
	}
	else
	{
		g_pVGuiPanel->SetPlat(panel, VPANEL_NORMAL);
	}
}

bool CMatSystemSurface::IsMinimized(vgui::VPANEL panel)
{
	return (g_pVGuiPanel->Plat(panel) == VPANEL_MINIMIZED);

}

void CMatSystemSurface::FlashWindow(VPANEL panel, bool state)
{
}


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CMatSystemSurface::SetTitle(VPANEL panel, const wchar_t *title)
{
	int entry = GetTitleEntry( panel );
	if ( entry == -1 )
	{
		entry = m_Titles.AddToTail();
	}

	TitleEntry *e = &m_Titles[ entry ];
	Assert( e );
	wcsncpy( e->title, title, sizeof( e->title )/ sizeof( wchar_t ) );
	e->panel = panel;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
wchar_t const *CMatSystemSurface::GetTitle( VPANEL panel )
{
	int entry = GetTitleEntry( panel );
	if ( entry != -1 )
	{
		TitleEntry *e = &m_Titles[ entry ];
		return e->title;
	}

	return NULL;
}

//-----------------------------------------------------------------------------
// Purpose: Private lookup method
// Input  : *panel - 
// Output : TitleEntry
//-----------------------------------------------------------------------------
int CMatSystemSurface::GetTitleEntry( vgui::VPANEL panel )
{
	for ( int i = 0; i < m_Titles.Count(); i++ )
	{
		TitleEntry* entry = &m_Titles[ i ];
		if ( entry->panel == panel )
			return i;
	}
	return -1;
}

void CMatSystemSurface::SwapBuffers(VPANEL panel)
{
}

void CMatSystemSurface::Invalidate(VPANEL panel)
{
}

void CMatSystemSurface::ApplyChanges()
{
}

// notify icons?!?
VPANEL CMatSystemSurface::GetNotifyPanel()
{
	return NULL;
}

void CMatSystemSurface::SetNotifyIcon(VPANEL context, HTexture icon, VPANEL panelToReceiveMessages, const char *text)
{
}

bool CMatSystemSurface::IsWithin(int x, int y)
{
	return true;
}

bool CMatSystemSurface::ShouldPaintChildPanel(VPANEL childPanel)
{
	if ( m_pRestrictedPanel && ( m_pRestrictedPanel != childPanel ) && 
		 !g_pVGuiPanel->HasParent( childPanel, m_pRestrictedPanel ) )
	{
		return false;
	}

	bool isPopup = ipanel()->IsPopup(childPanel);
	return !isPopup;
}

bool CMatSystemSurface::RecreateContext(VPANEL panel)
{
	return false;
}

//-----------------------------------------------------------------------------
// Focus-related methods
//-----------------------------------------------------------------------------
bool CMatSystemSurface::HasFocus()
{
	return true;
}

void CMatSystemSurface::BringToFront(VPANEL panel)
{
	// move panel to top of list
	g_pVGuiPanel->MoveToFront(panel);

	// move panel to top of popup list
	if ( g_pVGuiPanel->IsPopup( panel ) )
	{
		MovePopupToFront( panel );
	}
}


// engine-only focus handling (replacing WM_FOCUS windows handling)
void CMatSystemSurface::SetTopLevelFocus(VPANEL pSubFocus)
{
	// walk up the hierarchy until we find what popup panel belongs to
	while (pSubFocus)
	{
		if (ipanel()->IsPopup(pSubFocus) && ipanel()->IsMouseInputEnabled(pSubFocus))
		{
			BringToFront(pSubFocus);
			break;
		}
		
		pSubFocus = ipanel()->GetParent(pSubFocus);
	}
}


//-----------------------------------------------------------------------------
// Installs a function to play sounds
//-----------------------------------------------------------------------------
void CMatSystemSurface::InstallPlaySoundFunc( PlaySoundFunc_t soundFunc )
{
	m_PlaySoundFunc = soundFunc;
}


//-----------------------------------------------------------------------------
// plays a sound
//-----------------------------------------------------------------------------
void CMatSystemSurface::PlaySound(const char *pFileName)
{
	if (m_PlaySoundFunc)
		m_PlaySoundFunc( pFileName );
}


//-----------------------------------------------------------------------------
// handles mouse movement
//-----------------------------------------------------------------------------
void CMatSystemSurface::SetCursorPos(int x, int y)
{
	CursorSetPos( m_HWnd, x, y );
}

void CMatSystemSurface::GetCursorPos(int &x, int &y)
{
	CursorGetPos( m_HWnd, x, y );
}

void CMatSystemSurface::SetCursor(HCursor hCursor)
{
	if ( IsCursorLocked() )
		return;

	if ( _currentCursor != hCursor )
	{
		_currentCursor = hCursor;
		CursorSelect( hCursor );
	}
}

void CMatSystemSurface::EnableMouseCapture( VPANEL panel, bool state )
{
#ifdef WIN32
	if ( state )
	{
		::SetCapture( reinterpret_cast< HWND >( m_HWnd ) );
	}
	else
	{
		::ReleaseCapture();
	}
#elif defined( POSIX )
	// SetCapture on Win32 makes all the mouse messages (move and button up/down) head to
	//	the captured window. From what I can tell, this routine is called for modal dialogs
	//	when you click down on a button. However the current behavior is to highlight the
	//	buttons when you're over them, and trigger when you mouse up over the top - so I
	//	don't believe that SetCapture is needed on Windows, and Linux is behaving exactly
	//	the same as Win32 in all the tests I've run so far. (I've clicked on a lot of dialogs).
	// I talked with Alfred about this and we haven't done any SetCapture stuff on OSX ever
	//  and he says nobody has ever reported any regressions.
	// So I've removed the Assert. 8/32/2012 - mikesart.
#else
#error
#endif
}

//-----------------------------------------------------------------------------
// Purpose: Turns the panel into a standalone window
//-----------------------------------------------------------------------------
void CMatSystemSurface::CreatePopup(VPANEL panel, bool minimized,  bool showTaskbarIcon, bool disabled , bool mouseInput , bool kbInput)
{
	if (!g_pVGuiPanel->GetParent(panel))
	{
		g_pVGuiPanel->SetParent(panel, GetEmbeddedPanel());
	}
	((VPanel *)panel)->SetPopup(true);
	((VPanel *)panel)->SetKeyBoardInputEnabled(kbInput);
	((VPanel *)panel)->SetMouseInputEnabled(mouseInput);

	HPanel p = ivgui()->PanelToHandle( panel );

	if ( m_PopupList.Find( p ) == m_PopupList.InvalidIndex() )
	{
		m_PopupList.AddToTail( p );
	}
	else
	{
		MovePopupToFront( panel );
	}
}


//-----------------------------------------------------------------------------
// Create/destroy panels..
//-----------------------------------------------------------------------------
void CMatSystemSurface::AddPanel(VPANEL panel)
{
	if (g_pVGuiPanel->IsPopup(panel))
	{
		// turn it into a popup menu
		CreatePopup(panel, false);
	}
}

void CMatSystemSurface::ReleasePanel(VPANEL panel)
{
	// Remove from popup list if needed and remove any dead popups while we're at it
	RemovePopup( panel );

	int entry = GetTitleEntry( panel );
	if ( entry != -1 )
	{
		m_Titles.Remove( entry );
	}
}


//-----------------------------------------------------------------------------
// Popup accessors used by VGUI
//-----------------------------------------------------------------------------
int CMatSystemSurface::GetPopupCount(  )
{
	return m_PopupList.Count();
}

VPANEL CMatSystemSurface::GetPopup(  int index )
{
	HPanel p = m_PopupList[ index ];
	VPANEL panel = ivgui()->HandleToPanel( p );
	return panel;
}

void CMatSystemSurface::ResetPopupList(  )
{
	m_PopupList.RemoveAll();
}

void CMatSystemSurface::AddPopup( VPANEL panel )
{
	HPanel p = ivgui()->PanelToHandle( panel );

	if ( m_PopupList.Find( p ) == m_PopupList.InvalidIndex() )
	{
		m_PopupList.AddToTail( p );
	}
}


void CMatSystemSurface::RemovePopup( vgui::VPANEL panel )
{
	// Remove from popup list if needed and remove any dead popups while we're at it
	int c = GetPopupCount();

	for ( int i = c -  1; i >= 0 ; i-- )
	{
		VPANEL popup = GetPopup(i );
		if ( popup && ( popup != panel ) )
			continue;

		m_PopupList.Remove( i );
		break;
	}
}

//-----------------------------------------------------------------------------
// Methods associated with iterating + drawing the panel tree
//-----------------------------------------------------------------------------
void CMatSystemSurface::AddPopupsToList( VPANEL panel )
{
	if (!g_pVGuiPanel->IsVisible(panel))
		return;

	// Add to popup list as we visit popups
	// Note:  popup list is cleared in RunFrame which occurs before this call!!!
	if ( g_pVGuiPanel->IsPopup( panel ) )
	{
		AddPopup( panel );
	}

	int count = g_pVGuiPanel->GetChildCount(panel);
	for (int i = 0; i < count; ++i)
	{
		VPANEL child = g_pVGuiPanel->GetChild(panel, i);
		AddPopupsToList( child );
	}
}


//-----------------------------------------------------------------------------
// Purpose: recurses the panels calculating absolute positions
//			parents must be solved before children
//-----------------------------------------------------------------------------
void CMatSystemSurface::InternalSolveTraverse(VPANEL panel)
{
	VPanel * RESTRICT vp = (VPanel *)panel;

	vp->TraverseLevel( 1 );
	tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "%s - %s", __FUNCTION__, vp->GetName() );

	// solve the parent
	vp->Solve();
	
	CUtlVector< VPanel * > &children = vp->GetChildren();

	// WARNING: Some of the think functions add/remove children, so make sure we
	//  explicitly check for children.Count().
	for ( int i = 0; i < children.Count(); ++i )
	{
		VPanel *child = children[ i ];
		if (child->IsVisible())
		{
			InternalSolveTraverse( (VPANEL)child );
		}
	}

	vp->TraverseLevel( -1 );
}

//-----------------------------------------------------------------------------
// Purpose: recurses the panels giving them a chance to do a user-defined think,
//			PerformLayout and ApplySchemeSettings
//			must be done child before parent
//-----------------------------------------------------------------------------
void CMatSystemSurface::InternalThinkTraverse(VPANEL panel)
{
	VPanel * RESTRICT vp = (VPanel *)panel;

	vp->TraverseLevel( 1 );
	tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "%s - %s", __FUNCTION__, vp->GetName() );

	// think the parent
	vp->Client()->Think();

	CUtlVector< VPanel * > &children = vp->GetChildren();

	// WARNING: Some of the think functions add/remove children, so make sure we
	//  explicitly check for children.Count().
	for ( int i = 0; i < children.Count(); ++i )
	{
		VPanel *child = children[ i ];
		if ( child->IsVisible() )
		{
			InternalThinkTraverse( (VPANEL)child );
		}
	}
	
	vp->TraverseLevel( -1 );
}

//-----------------------------------------------------------------------------
// Purpose: recurses the panels giving them a chance to do apply settings,
//-----------------------------------------------------------------------------
void CMatSystemSurface::InternalSchemeSettingsTraverse(VPANEL panel, bool forceApplySchemeSettings)
{
	VPanel * RESTRICT vp = (VPanel *)panel;

	vp->TraverseLevel( 1 );
	tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "%s - %s", __FUNCTION__, vp->GetName() );

	CUtlVector< VPanel * > &children = vp->GetChildren();

	// apply to the children...
	for ( int i = 0; i < children.Count(); ++i )
	{
		VPanel *child = children[ i ];
		if ( forceApplySchemeSettings || child->IsVisible() )
		{	
			InternalSchemeSettingsTraverse((VPANEL)child, forceApplySchemeSettings);
		}
	}
	// and then the parent
	vp->Client()->PerformApplySchemeSettings();

	vp->TraverseLevel( -1 );
}

//-----------------------------------------------------------------------------
// Purpose: Walks through the panel tree calling Solve() on them all, in order
//-----------------------------------------------------------------------------
void CMatSystemSurface::SolveTraverse(VPANEL panel, bool forceApplySchemeSettings)
{
	{
		VPROF( "InternalSchemeSettingsTraverse" );
		tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "%s - InternalSchemeSettingsTraverse", __FUNCTION__ );
		InternalSchemeSettingsTraverse(panel, forceApplySchemeSettings);
	}

	{
		VPROF( "InternalThinkTraverse" );
		tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "%s - InternalThinkTraverse", __FUNCTION__ );
		InternalThinkTraverse(panel);
	}

	{
		VPROF( "InternalSolveTraverse" );
		tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "%s - InternalSolveTraverse", __FUNCTION__ );
		InternalSolveTraverse(panel);
	}
}

//-----------------------------------------------------------------------------
// Purpose: Restricts rendering to a single panel
//-----------------------------------------------------------------------------
void CMatSystemSurface::RestrictPaintToSinglePanel(VPANEL panel)
{
	if ( panel && m_pRestrictedPanel && m_pRestrictedPanel == input()->GetAppModalSurface() )
	{
		return;	// don't restrict drawing to a panel other than the modal one - that's a good way to hang the game.
	}

	m_pRestrictedPanel = panel;

	if ( !input()->GetAppModalSurface() )
	{
		input()->SetAppModalSurface( panel );	// if painting is restricted to this panel, it had better be modal, or else you can get in some bad state...
	}
}


//-----------------------------------------------------------------------------
// Is a panel under the restricted panel?
//-----------------------------------------------------------------------------
bool CMatSystemSurface::IsPanelUnderRestrictedPanel( VPANEL panel )
{
	if ( !m_pRestrictedPanel )
		return true;

	while ( panel )
	{
		if ( panel == m_pRestrictedPanel )
			return true;

		panel = ipanel()->GetParent( panel );
	}
	return false;
}


//-----------------------------------------------------------------------------
// Main entry point for painting
//-----------------------------------------------------------------------------
void CMatSystemSurface::PaintTraverseEx(VPANEL panel, bool paintPopups /*= false*/ )
{
	MAT_FUNC;

	if ( !ipanel()->IsVisible( panel ) )
		return;

	VPROF( "CMatSystemSurface::PaintTraverse" );
	CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
	bool bTopLevelDraw = false;

	if ( g_bInDrawing == false )
	{
		// only set the 2d ortho mode once
		bTopLevelDraw = true;
		StartDrawing();

		// clear z + stencil buffer
		// NOTE: Stencil is used to get 3D painting in vgui panels working correctly 
		pRenderContext->ClearBuffers( false, true, true );
		pRenderContext->SetStencilEnable( true );
		pRenderContext->SetStencilFailOperation( STENCILOPERATION_KEEP );
		pRenderContext->SetStencilZFailOperation( STENCILOPERATION_KEEP );
		pRenderContext->SetStencilPassOperation( STENCILOPERATION_REPLACE );
		pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_GREATEREQUAL );
		pRenderContext->SetStencilReferenceValue( 0 );
		pRenderContext->SetStencilTestMask( 0xFFFFFFFF );
		pRenderContext->SetStencilWriteMask( 0xFFFFFFFF );
	}

	float flOldZPos = m_flZPos;

	// NOTE You might expect we'd have to draw these under the popups so they would occlude
	// them, but there are a few things we do have to draw on top of, esp. the black
	// panel that draws over the top of the engine to darken everything.
	m_flZPos = 0.0f;								
	if ( panel == GetEmbeddedPanel() )
	{
		if ( m_pRestrictedPanel )
		{
			// Paint the restricted panel, and its parent.
			// NOTE: This call has guards to not draw popups. If the restricted panel
			// is a popup, it won't draw here.
			ipanel()->PaintTraverse( ipanel()->GetParent( m_pRestrictedPanel ), true );
		}
		else
		{
			// paint traverse the root panel, painting all children
			VPROF( "ipanel()->PaintTraverse" );
			ipanel()->PaintTraverse( panel, true );
		}
	}
	else
	{
		// If it's a popup, it should already have been painted above
		VPROF( "ipanel()->PaintTraverse" );
		if ( !paintPopups || !ipanel()->IsPopup( panel ) )
		{
			ipanel()->PaintTraverse( panel, true );
		}
	}

	// draw the popups
	if ( paintPopups )
	{
		// now draw the popups front to back
		// since depth-test and depth-write are on, the front panels will occlude the underlying ones
		{
			VPROF( "CMatSystemSurface::PaintTraverse popups loop" );
			int popups = GetPopupCount();
			if ( popups > 254 )
			{
				Warning( "Too many popups! Rendering will be bad!\n" );
			}

			// HACK! Using stencil ref 254 so drag/drop helper can use 255.
			int nStencilRef = 254;
			for ( int i = popups - 1; i >= 0; --i )
			{
				VPANEL popupPanel = GetPopup( i );

				if ( !popupPanel )
					continue;

				if ( !ipanel()->IsFullyVisible( popupPanel ) )
					continue;

				if ( !IsPanelUnderRestrictedPanel( popupPanel ) )
					continue;

				// This makes sure the drag/drop helper is always the first thing drawn
				bool bIsTopmostPopup = ( (VPanel *)popupPanel )->IsTopmostPopup();

				// set our z position
				pRenderContext->SetStencilReferenceValue( bIsTopmostPopup ? 255 : nStencilRef );
				--nStencilRef;

				m_flZPos = ((float)(i) / (float)popups);
				ipanel()->PaintTraverse( popupPanel, true );
			}
		}
	}

	// Restore the old Z Pos
	m_flZPos = flOldZPos;

	if ( bTopLevelDraw )
	{
		// only undo the 2d ortho mode once
		VPROF( "FinishDrawing" );

		// Reset stencil to normal state
		pRenderContext->SetStencilEnable( false );

		FinishDrawing();
	}
}

//-----------------------------------------------------------------------------
// Draw a panel
//-----------------------------------------------------------------------------
void CMatSystemSurface::PaintTraverse(VPANEL panel)
{
	PaintTraverseEx( panel, false );
}


//-----------------------------------------------------------------------------
// Begins, ends 3D painting from within a panel paint() method
//-----------------------------------------------------------------------------
void CMatSystemSurface::Begin3DPaint( int iLeft, int iTop, int iRight, int iBottom, bool bRenderToTexture )
{
	MAT_FUNC;

	if ( IsX360() )
	{
		Assert( 0 );
		return;
	}

	Assert( iRight > iLeft );
	Assert( iBottom > iTop );

	// Can't use this while drawing in the 3D world since it relies on
	// whacking the shared depth buffer
	Assert( !m_bDrawingIn3DWorld );
	if ( m_bDrawingIn3DWorld )
		return;

	m_n3DLeft = iLeft;
	m_n3DRight = iRight;
	m_n3DTop = iTop;
	m_n3DBottom = iBottom;

	// Can't use this feature when drawing into the 3D world
	Assert( !m_bDrawingIn3DWorld );
	Assert( !m_bIn3DPaintMode );
	m_bIn3DPaintMode = true;
	m_b3DPaintRenderToTexture = bRenderToTexture;

	// Save off the matrices in case the painting method changes them.
	CMatRenderContextPtr pRenderContext( g_pMaterialSystem );

	pRenderContext->MatrixMode( MATERIAL_MODEL );
	pRenderContext->PushMatrix();

	pRenderContext->MatrixMode( MATERIAL_VIEW );
	pRenderContext->PushMatrix();

	pRenderContext->MatrixMode( MATERIAL_PROJECTION );
	pRenderContext->PushMatrix();

	if ( bRenderToTexture )
	{

		// For 3d painting, use the off-screen render target the material system allocates
		// NOTE: We have to grab it here, as opposed to during init,
		// because the mode hasn't been set by now.
		if ( !m_FullScreenBuffer )
		{
			m_FullScreenBuffer.Init( materials->FindTexture( m_FullScreenBufferName, "render targets" ) );
		}

		// FIXME: Set the viewport to match the clip rectangle?
		// Set the viewport to match the scissor rectangle
		pRenderContext->PushRenderTargetAndViewport( m_FullScreenBuffer, 
			0, 0, iRight - iLeft, iBottom - iTop );

		// NOTE: Stencil is used to get 3D painting in vgui panels working correctly 
		pRenderContext->SetStencilFailOperation( STENCILOPERATION_KEEP );
		pRenderContext->SetStencilZFailOperation( STENCILOPERATION_KEEP );
		pRenderContext->SetStencilPassOperation( STENCILOPERATION_REPLACE );
		pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_EQUAL );

		// Don't draw the 3D scene w/ stencil
		pRenderContext->SetStencilEnable( false );
	}
	else
	{
		int clipLeft, clipTop, clipRight, clipBottom;
		bool clipEnabled;
		GetScissorRect( clipLeft, clipTop, clipRight, clipBottom, clipEnabled );
		pRenderContext->PushRenderTargetAndViewport();
		pRenderContext->Viewport( clipLeft + iLeft, clipTop + iTop, iRight - iLeft, iBottom - iTop );
	}

	pRenderContext->CullMode( MATERIAL_CULLMODE_CW );

	pRenderContext->Flush();
}

void CMatSystemSurface::End3DPaint()
{
	MAT_FUNC;

	if ( IsX360() )
	{
		Assert( 0 );
		return;
	}

	// Can't use this feature when drawing into the 3D world
	Assert( !m_bDrawingIn3DWorld );
	Assert( m_bIn3DPaintMode );
	m_bIn3DPaintMode = false;

	// Reset stencil to set stencil everywhere we draw 
	CMatRenderContextPtr pRenderContext( g_pMaterialSystem );

	pRenderContext->SetStencilEnable( true );
	pRenderContext->SetStencilFailOperation( STENCILOPERATION_KEEP );
	pRenderContext->SetStencilZFailOperation( STENCILOPERATION_KEEP );
	pRenderContext->SetStencilPassOperation( STENCILOPERATION_REPLACE );
	pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_GREATEREQUAL );

	// Restore the matrices
	pRenderContext->MatrixMode( MATERIAL_MODEL );
	pRenderContext->PopMatrix();

	pRenderContext->MatrixMode( MATERIAL_VIEW );
	pRenderContext->PopMatrix();

	pRenderContext->MatrixMode( MATERIAL_PROJECTION );
	pRenderContext->PopMatrix();

	// Restore the viewport (it was stored off in StartDrawing)
	pRenderContext->PopRenderTargetAndViewport();
	pRenderContext->CullMode(MATERIAL_CULLMODE_CCW);

	// Draw the full-screen buffer into the panel, if we rendering
	// to a texture
	if ( m_b3DPaintRenderToTexture )
		DrawFullScreenBuffer( m_n3DLeft, m_n3DTop, m_n3DRight, m_n3DBottom );

	// ReSet the material state
	InternalSetMaterial( NULL );
}


//-----------------------------------------------------------------------------
// skin composition, force drawing
//-----------------------------------------------------------------------------
void CMatSystemSurface::BeginSkinCompositionPainting()
{
	g_bInDrawing = true;
}


//-----------------------------------------------------------------------------
// end drawing when finish skin composition
//-----------------------------------------------------------------------------
void CMatSystemSurface::EndSkinCompositionPainting()
{
	g_bInDrawing = false;
}


//-----------------------------------------------------------------------------
// Gets texture coordinates for drawing the full screen buffer
//-----------------------------------------------------------------------------
void CMatSystemSurface::GetFullScreenTexCoords( int x, int y, int w, int h, float *pMinU, float *pMinV, float *pMaxU, float *pMaxV )
{
	int nTexWidth = m_FullScreenBuffer->GetActualWidth();
	int nTexHeight = m_FullScreenBuffer->GetActualHeight();
	float flOOWidth = 1.0f / nTexWidth;
	float flOOHeight = 1.0f / nTexHeight;

	*pMinU = ( (float)x + 0.5f ) * flOOWidth;
	*pMinV = ( (float)y + 0.5f ) * flOOHeight;
	*pMaxU = ( (float)(x+w) - 0.5f ) * flOOWidth;
	*pMaxV = ( (float)(y+h) - 0.5f ) * flOOHeight;	
}


//-----------------------------------------------------------------------------
// Draws the fullscreen buffer into the panel
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawFullScreenBuffer( int nLeft, int nTop, int nRight, int nBottom )
{
	MAT_FUNC;

	// Draw a textured rectangle over the area
	if ( m_nFullScreenBufferMaterialId == -1 )
	{
		m_nFullScreenBufferMaterialId = CreateNewTextureID();
		DrawSetTextureMaterial( m_nFullScreenBufferMaterialId, m_FullScreenBufferMaterial );
	}

	float flGetAlphaMultiplier = DrawGetAlphaMultiplier();
	unsigned char oldColor[4];
	oldColor[0] = m_DrawColor[0];
	oldColor[1] = m_DrawColor[1];
	oldColor[2] = m_DrawColor[2];
	oldColor[3] = m_DrawColor[3];

	DrawSetAlphaMultiplier( 1.0f );
	DrawSetColor( 255, 255, 255, 255 );

	DrawSetTexture( m_nFullScreenBufferMaterialId );

	float u0, u1, v0, v1;
	GetFullScreenTexCoords( 0, 0, nRight - nLeft, nBottom - nTop, &u0, &v0, &u1, &v1 );
	DrawTexturedSubRect( nLeft, nTop, nRight, nBottom, u0, v0, u1, v1 );

	m_DrawColor[0] = oldColor[0];
	m_DrawColor[1] = oldColor[1];
	m_DrawColor[2] = oldColor[2];
	m_DrawColor[3] = oldColor[3];
	DrawSetAlphaMultiplier( flGetAlphaMultiplier );
}


//-----------------------------------------------------------------------------
// Draws a rectangle, setting z to the current value
//-----------------------------------------------------------------------------
float CMatSystemSurface::GetZPos() const
{
	return m_flZPos;
}


//-----------------------------------------------------------------------------
// Some drawing methods that cannot be accomplished under Win32
//-----------------------------------------------------------------------------
#define CIRCLE_POINTS		360

void CMatSystemSurface::DrawColoredCircle( int centerx, int centery, float radius, int r, int g, int b, int a )
{
	MAT_FUNC;

	Assert( g_bInDrawing );
	// Draw a circle
	int iDegrees = 0;
	Vector vecPoint, vecLastPoint(0,0,0);
	vecPoint.z = 0.0f;
	Color clr;
	clr.SetColor( r, g, b, a );
	DrawSetColor( clr );

	for ( int i = 0; i < CIRCLE_POINTS; i++ )
	{
		float flRadians = DEG2RAD( iDegrees );
		iDegrees += (360 / CIRCLE_POINTS);

		float ca = cos( flRadians );
		float sa = sin( flRadians );
					 
		// Rotate it around the circle
		vecPoint.x = centerx + (radius * sa);
		vecPoint.y = centery - (radius * ca);

		// Draw the point, if it's not on the previous point, to avoid smaller circles being brighter
		if ( vecLastPoint != vecPoint )
		{
			DrawFilledRect( vecPoint.x, vecPoint.y,  vecPoint.x + 1, vecPoint.y + 1 );
		}

		vecLastPoint = vecPoint;
	}
}

//-----------------------------------------------------------------------------
// Purpose: Draws colored text to a vgui panel
// Input  : *font - font to use
//			x - position of text
//			y - 
//			r - color of text
//			g - 
//			b - 
//			a - alpha ( 255 = opaque, 0 = transparent )
//			*fmt - va_* text string
//			... - 
// Output : int - horizontal # of pixels drawn
//-----------------------------------------------------------------------------
int CMatSystemSurface::DrawColoredText( vgui::HFont font, int x, int y, int r, int g, int b, int a, const char *fmt, va_list argptr )
{
	MAT_FUNC;
	Assert( g_bInDrawing );
	int len;
	char data[1024];

	DrawSetTextPos( x, y );
	DrawSetTextColor( r, g, b, a );

	len = Q_vsnprintf(data, sizeof( data ), fmt, argptr);

	DrawSetTextFont( font );

	wchar_t szconverted[ 1024 ];
	g_pVGuiLocalize->ConvertANSIToUnicode( data, szconverted, 1024 );
	DrawPrintText( szconverted, wcslen(szconverted ) );

	int totalLength = DrawTextLen( font, data );

	return x + totalLength;
}

int CMatSystemSurface::DrawColoredText( vgui::HFont font, int x, int y, int r, int g, int b, int a, const char *fmt, ... )
{
	MAT_FUNC;

	va_list argptr;
	va_start( argptr, fmt );
	int ret = DrawColoredText( font, x, y, r, g, b, a, fmt, argptr );
	va_end(argptr);
	return ret;
}


//-----------------------------------------------------------------------------
// Draws text with current font at position and wordwrapped to the rect using color values specified
//-----------------------------------------------------------------------------
void CMatSystemSurface::SearchForWordBreak( vgui::HFont font, char *text, int& chars, int& pixels )
{
	chars = pixels = 0;
	while ( 1 )
	{
		char ch = text[ chars ];
		int a, b, c;
		GetCharABCwide( font, ch, a, b, c );

		if ( ch == 0 || ch <= 32 )
		{
			if ( ch == 32 && chars == 0 )
			{
				pixels += ( b + c );
				chars++;
			}
			break;
		}

		pixels += ( b + c );
		chars++;
	}
}

//-----------------------------------------------------------------------------
// Purpose: If text width is specified, reterns height of text at that width
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawTextHeight( vgui::HFont font, int w, int& h, const char *fmt, ... )
{
	if ( !font )
		return;

	int len;
	char data[8192];

	va_list argptr;
	va_start( argptr, fmt );
	len = Q_vsnprintf( data, sizeof( data ), fmt, argptr );
	va_end( argptr );

	int x = 0;
	int y = 0;

	int ystep = GetFontTall( font );
	int startx = x;
	int endx = x + w;
	//int endy = y + h;
	int endy = 0;

	int chars = 0;
	int pixels = 0;
	for ( int i = 0 ; i < len; i += chars )
	{
		SearchForWordBreak( font, &data[ i ], chars, pixels );

		if ( data[ i ] == '\n' )
		{
			x = startx;
			y += ystep;
			chars = 1;
			continue;
		}

		if ( x + ( pixels ) >= endx )
		{
			x = startx;
			// No room even on new line!!!
			if ( x + pixels >= endx )
				break;

			y += ystep;
		}

		for ( int j = 0 ; j < chars; j++ )
		{
			int a, b, c;
			char ch = data[ i + j ];

			GetCharABCwide( font, ch, a, b, c );
	
			x += a + b + c;
		}
	}

	endy = y+ystep;

	h = endy;
}


//-----------------------------------------------------------------------------
// Draws text with current font at position and wordwrapped to the rect using color values specified
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawColoredTextRect( vgui::HFont font, int x, int y, int w, int h, int r, int g, int b, int a, const char *fmt, ... )
{
	MAT_FUNC;

	Assert( g_bInDrawing );
	if ( !font )
		return;

	int len;
	char data[8192];

	va_list argptr;
	va_start( argptr, fmt );
	len = Q_vsnprintf( data, sizeof( data ), fmt, argptr );
	va_end( argptr );

	DrawSetTextPos( x, y );
	DrawSetTextColor( r, g, b, a );
	DrawSetTextFont( font );

	int ystep = GetFontTall( font );
	int startx = x;
	int endx = x + w;
	int endy = y + h;

	int chars = 0;
	int pixels = 0;

	char word[ 512 ];
	char space[ 2 ];
	space[1] = 0;
	space[0] = ' ';

	for ( int i = 0 ; i < len; i += chars )
	{
		SearchForWordBreak( font, &data[ i ], chars, pixels );

		if ( data[ i ] == '\n' )
		{
			x = startx;
			y += ystep;
			chars = 1;
			continue;
		}

		if ( x + ( pixels ) >= endx )
		{
			x = startx;
			// No room even on new line!!!
			if ( x + pixels >= endx )
				break;

			y += ystep;
		}

		if ( y + ystep >= endy )
			break;


		if ( chars <= 0 )
			continue;

		Q_strncpy( word, &data[ i ], chars + 1 );

		DrawSetTextPos( x, y );

		wchar_t szconverted[ 1024 ];
		g_pVGuiLocalize->ConvertANSIToUnicode( word, szconverted, 1024 );
		DrawPrintText( szconverted, wcslen(szconverted ) );

		// Leave room for space, too
		x += DrawTextLen( font, word );
	}
}


//-----------------------------------------------------------------------------
// Purpose: Determine length of text string
//-----------------------------------------------------------------------------
int	CMatSystemSurface::DrawTextLen( vgui::HFont font, const char *fmt, ... )
{
	va_list argptr;
	char data[1024];
	int len;

	va_start(argptr, fmt);
	len = Q_vsnprintf(data, sizeof( data ), fmt, argptr);
	va_end(argptr);

	int i;
	int x = 0;

	for ( i = 0 ; i < len; i++ )
	{
		int a, b, c;
		GetCharABCwide( font, data[i], a, b, c );

		// Ignore a
		//	x += a;
		x += b;
		x += c;
	}

	return x;
}

//-----------------------------------------------------------------------------
// Disable clipping during rendering
//-----------------------------------------------------------------------------
void CMatSystemSurface::DisableClipping( bool bDisable )
{
	// when the clipping rules change. flush any text we've
	// queued up to draw so it gets clipped appropriatesly
	DrawFlushText();

	EnableScissor( !bDisable );
}


//-----------------------------------------------------------------------------
// Fetch current clipping rectangle
//-----------------------------------------------------------------------------
void CMatSystemSurface::GetClippingRect( int &left, int &top, int &right, int &bottom, bool &bClippingDisabled )
{
	bool bEnabled = true;
	GetScissorRect( left, top, right, bottom, bEnabled );
	bClippingDisabled = !bEnabled;
}

//-----------------------------------------------------------------------------
// Set clipping rectangle
//-----------------------------------------------------------------------------
void CMatSystemSurface::SetClippingRect( int left, int top, int right, int bottom )
{
	SetScissorRect( left, top, right, bottom );
}

//-----------------------------------------------------------------------------
// Purpose: unlocks the cursor state
//-----------------------------------------------------------------------------
bool CMatSystemSurface::IsCursorLocked() const
{
	return ::IsCursorLocked();
}


//-----------------------------------------------------------------------------
// Sets the mouse Get + Set callbacks
//-----------------------------------------------------------------------------
void CMatSystemSurface::SetMouseCallbacks( GetMouseCallback_t GetFunc, SetMouseCallback_t SetFunc )
{
	// FIXME: Remove! This is obsolete
	Assert(0);
}


//-----------------------------------------------------------------------------
// Tells the surface to ignore windows messages
//-----------------------------------------------------------------------------
void CMatSystemSurface::EnableWindowsMessages( bool bEnable )
{
	EnableInput( bEnable );
}

void CMatSystemSurface::MovePopupToFront(VPANEL panel)
{
	HPanel p = ivgui()->PanelToHandle( panel );

	int index = m_PopupList.Find( p );
	if ( index == m_PopupList.InvalidIndex() )
		return;

	m_PopupList.Remove( index );
	m_PopupList.AddToTail( p );

	if ( g_bSpewFocus )
	{
		char const *pName = ipanel()->GetName( panel );
		Msg( "%s moved to front\n", pName ? pName : "(no name)" ); 
	}

	// If the modal panel isn't a parent, restore it to the top, to prevent a hard lock
	if ( input()->GetAppModalSurface() )
	{
		if ( !g_pVGuiPanel->HasParent(panel, input()->GetAppModalSurface()) )
		{
			HPanel p = ivgui()->PanelToHandle( input()->GetAppModalSurface() );
			index = m_PopupList.Find( p );
			if ( index != m_PopupList.InvalidIndex() )
			{
				m_PopupList.Remove( index );
				m_PopupList.AddToTail( p );
			}
		}
	}

	ivgui()->PostMessage(panel, new KeyValues("OnMovedPopupToFront"), NULL);
}

void CMatSystemSurface::MovePopupToBack(VPANEL panel)
{
	HPanel p = ivgui()->PanelToHandle( panel );

	int index = m_PopupList.Find( p );
	if ( index == m_PopupList.InvalidIndex() )
	{
		return;
	}

	m_PopupList.Remove( index );
	m_PopupList.AddToHead( p );
}


bool CMatSystemSurface::IsInThink( VPANEL panel)
{
	if ( m_bInThink )
	{
		if ( panel == m_CurrentThinkPanel ) // HasParent() returns true if you pass yourself in
		{
			return false;
		}

		return ipanel()->HasParent( panel, m_CurrentThinkPanel);
	}
	return false;
}


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool CMatSystemSurface::IsCursorVisible()
{
	return m_cursorAlwaysVisible || (_currentCursor != dc_none);
}

void CMatSystemSurface::SetCursorAlwaysVisible( bool visible )
{
	m_cursorAlwaysVisible = visible;
	CursorSelect( visible ? dc_alwaysvisible_push : dc_alwaysvisible_pop );
}

bool CMatSystemSurface::IsTextureIDValid(int id)
{
	// FIXME:
	return true;
}

void CMatSystemSurface::SetAllowHTMLJavaScript( bool state )
{ 
	m_bAllowJavaScript = state; 
}

IHTML *CMatSystemSurface::CreateHTMLWindow(vgui::IHTMLEvents *events,VPANEL context)
{
	Assert( !"CMatSystemSurface::CreateHTMLWindow" );
	return NULL;
}


void CMatSystemSurface::DeleteHTMLWindow(IHTML *htmlwin)
{
}



void CMatSystemSurface::PaintHTMLWindow(IHTML *htmlwin)
{
}

bool CMatSystemSurface::BHTMLWindowNeedsPaint(IHTML *htmlwin)
{
	return false;
}

//-----------------------------------------------------------------------------
/*void CMatSystemSurface::DrawSetTextureRGBA( int id, const unsigned char* rgba, int wide, int tall )
{
	TextureDictionary()->SetTextureRGBAEx( id, (const char *)rgba, wide, tall, IMAGE_FORMAT_RGBA8888 );
}*/

void CMatSystemSurface::DrawSetTextureRGBA(int id, const unsigned char* rgba, int wide, int tall, int hardwareFilter, bool forceUpload)
{
	TextureDictionary()->SetTextureRGBAEx( id, (const char *)rgba, wide, tall, IMAGE_FORMAT_RGBA8888, false );
}

void CMatSystemSurface::DrawSetTextureRGBAEx( int id, const unsigned char* rgba, int wide, int tall, ImageFormat format )
{
	TextureDictionary()->SetTextureRGBAEx( id, (const char *)rgba, wide, tall, format, true );
}

void CMatSystemSurface::DrawSetSubTextureRGBA(int textureID, int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall)
{
	TextureDictionary()->SetSubTextureRGBA( textureID, drawX, drawY, rgba, subTextureWide, subTextureTall );
}

void CMatSystemSurface::DrawUpdateRegionTextureRGBA( int nTextureID, int x, int y, const unsigned char *pchData, int wide, int tall, ImageFormat imageFormat )
{
	TextureDictionary()->UpdateSubTextureRGBA( nTextureID, x, y, pchData, wide, tall, imageFormat );
}

void CMatSystemSurface::SetModalPanel(VPANEL )
{
}

VPANEL CMatSystemSurface::GetModalPanel()
{
	return 0;
}

void CMatSystemSurface::UnlockCursor()
{
	::LockCursor( false );
}

void CMatSystemSurface::LockCursor()
{
	::LockCursor( true );
}

void CMatSystemSurface::SetTranslateExtendedKeys(bool state)
{
}

VPANEL CMatSystemSurface::GetTopmostPopup()
{
	return 0;
}

//-----------------------------------------------------------------------------
// Purpose: gets the absolute coordinates of the screen (in screen space)
//-----------------------------------------------------------------------------
void CMatSystemSurface::GetAbsoluteWindowBounds(int &x, int &y, int &wide, int &tall)
{
	// always work in full window screen space
	x = 0;
	y = 0;
	GetScreenSize(wide, tall);
}

// returns true if the specified panel is a child of the current modal panel
// if no modal panel is set, then this always returns TRUE
static bool IsChildOfModalSubTree(VPANEL panel)
{
	if ( !panel )
		return true;

	VPANEL modalSubTree = input()->GetModalSubTree();

	if ( modalSubTree )
	{
		bool restrictMessages = input()->ShouldModalSubTreeReceiveMessages();

		// If panel is child of modal subtree, the allow messages to route to it if restrict messages is set
		bool isChildOfModal = ipanel()->HasParent( panel, modalSubTree );
		if ( isChildOfModal )
		{
			return restrictMessages;
		}
		// If panel is not a child of modal subtree, then only allow messages if we're not restricting them to the modal subtree
		else
		{
			return !restrictMessages;
		}
	}

	return true;
}

void CMatSystemSurface::CalculateMouseVisible()
{
	int i;
	m_bNeedsMouse = false;
	m_bNeedsKeyboard = false;

	if ( input()->GetMouseCapture() != 0 )
		return;

	int c = surface()->GetPopupCount();

	VPANEL modalSubTree = input()->GetModalSubTree();
	if ( modalSubTree )
	{
		for (i = 0 ; i < c ; i++ )
		{
			VPanel *pop = (VPanel *)surface()->GetPopup(i) ;
			bool isChildOfModalSubPanel = IsChildOfModalSubTree( (VPANEL)pop );
			if ( !isChildOfModalSubPanel )
				continue;

			bool isVisible=pop->IsVisible();
			VPanel *p= pop->GetParent();

			while (p && isVisible)
			{
				if( p->IsVisible()==false)
				{
					isVisible=false;
					break;
				}
				p=p->GetParent();
			}

			if ( isVisible )
			{
				m_bNeedsMouse = m_bNeedsMouse || pop->IsMouseInputEnabled();
				m_bNeedsKeyboard = m_bNeedsKeyboard || pop->IsKeyBoardInputEnabled();

				// Seen enough!!!
				if ( m_bNeedsMouse && m_bNeedsKeyboard )
					break;
			}
		}
	}
	else
	{
		for (i = 0 ; i < c ; i++ )
		{
			VPanel *pop = (VPanel *)surface()->GetPopup(i) ;
			
			bool isVisible=pop->IsVisible();
			VPanel *p= pop->GetParent();

			while (p && isVisible)
			{
				if( p->IsVisible()==false)
				{
					isVisible=false;
					break;
				}
				p=p->GetParent();
			}
		
			if ( isVisible )
			{
				m_bNeedsMouse = m_bNeedsMouse || pop->IsMouseInputEnabled();
				m_bNeedsKeyboard = m_bNeedsKeyboard || pop->IsKeyBoardInputEnabled();

				// Seen enough!!!
				if ( m_bNeedsMouse && m_bNeedsKeyboard )
					break;
			}
		}
	}

	if (m_bNeedsMouse)
	{
		// NOTE: We must unlock the cursor *before* the set call here.
		// Failing to do this causes s_bCursorVisible to not be set correctly
		// (UnlockCursor fails to set it correctly)
		UnlockCursor();
		if ( _currentCursor == vgui::dc_none )
		{
			SetCursor(vgui::dc_arrow);
		}
	}
	else
	{
		SetCursor(vgui::dc_none);
		LockCursor();
	}
}

bool CMatSystemSurface::NeedKBInput()
{
	return m_bNeedsKeyboard;
}

void CMatSystemSurface::SurfaceGetCursorPos(int &x, int &y)
{
	GetCursorPos( x, y );
}
void CMatSystemSurface::SurfaceSetCursorPos(int x, int y)
{
	SetCursorPos( x, y );
}

//-----------------------------------------------------------------------------
// Purpose: global alpha setting functions
//-----------------------------------------------------------------------------
void CMatSystemSurface::DrawSetAlphaMultiplier( float alpha /* [0..1] */ )
{
	m_flAlphaMultiplier = clamp(alpha, 0.0f, 1.0f);
}

//-----------------------------------------------------------------------------
// Purpose: data accessor
//-----------------------------------------------------------------------------
float CMatSystemSurface::DrawGetAlphaMultiplier()
{
	return m_flAlphaMultiplier;
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *curOrAniFile - 
// Output : vgui::HCursor
//-----------------------------------------------------------------------------
vgui::HCursor CMatSystemSurface::CreateCursorFromFile( char const *curOrAniFile, char const *pPathID )
{
	return Cursor_CreateCursorFromFile( curOrAniFile, pPathID );
}

void CMatSystemSurface::SetPanelForInput( VPANEL vpanel )
{
	g_pIInput->AssociatePanelWithInputContext( DEFAULT_INPUT_CONTEXT, vpanel );
	if ( vpanel )
	{
		m_bNeedsKeyboard = true;
	}
	else
	{
		m_bNeedsKeyboard = false;
	}
}

#if defined( WIN32 ) && !defined( _X360 )
static bool GetIconSize( ICONINFO& iconInfo, int& w, int& h )
{
	w = h = 0;

	HBITMAP bitmap = iconInfo.hbmColor;
	BITMAP bm;
	if ( 0 == GetObject((HGDIOBJ)bitmap, sizeof(BITMAP), (LPVOID)&bm) ) 
	{
        return false; 
	}

	w = bm.bmWidth;
	h = bm.bmHeight;

	return true;
}

// If rgba is NULL, bufsize gets filled in w/ # of bytes required
static bool GetIconBits( HDC hdc, ICONINFO& iconInfo, int& w, int& h, unsigned char *rgba, size_t& bufsize )
{
	if ( !iconInfo.hbmColor || !iconInfo.hbmMask )
		return false;

	if ( !rgba )
	{
		if ( !GetIconSize( iconInfo, w, h ) )
			return false;
		
		bufsize = (size_t)( ( w * h ) << 2 );
		return true;
	}

	bool bret = false;

	Assert( w > 0 );
	Assert( h > 0 );
	Assert( bufsize == (size_t)( ( w * h ) << 2 ) );

	DWORD *maskData = new DWORD[ w * h ];
	DWORD *colorData =  new DWORD[ w * h ];
	DWORD *output = (DWORD *)rgba;

	BITMAPINFO bmInfo;

	memset( &bmInfo, 0, sizeof( bmInfo ) );
	bmInfo.bmiHeader.biSize = sizeof( bmInfo.bmiHeader );
	bmInfo.bmiHeader.biWidth = w; 
    bmInfo.bmiHeader.biHeight = h; 
    bmInfo.bmiHeader.biPlanes = 1; 
    bmInfo.bmiHeader.biBitCount = 32; 
    bmInfo.bmiHeader.biCompression = BI_RGB; 

	// Get the info about the bits
	if ( GetDIBits( hdc, iconInfo.hbmMask, 0, h, maskData, &bmInfo, DIB_RGB_COLORS ) == h &&
         GetDIBits( hdc, iconInfo.hbmColor, 0, h, colorData, &bmInfo, DIB_RGB_COLORS ) == h )
	{
		bret = true;

		for ( int row = 0; row < h; ++row )
		{
			// Invert
			int r = ( h - row - 1 );
			int rowstart = r * w;

			DWORD *color = &colorData[ rowstart ];
			DWORD *mask = &maskData[ rowstart ];
			DWORD *outdata = &output[ row * w ];

			for ( int col = 0; col < w; ++col )
			{
				unsigned char *cr = ( unsigned char * )&color[ col ];

				// Set alpha
				cr[ 3 ] =  mask[ col ] == 0 ? 0xff : 0x00;
				
				// Swap blue and red
				unsigned char t = cr[ 2 ];
				cr[ 2 ] = cr[ 0 ];
				cr[ 0 ] = t;

				*( unsigned int *)&outdata[ col ] = *( unsigned int * )cr;
			}
		}
	}

	delete[] colorData;
	delete[] maskData;

	return bret;
}

static bool ShouldMakeUnique( char const *extension )
{
	if ( !Q_stricmp( extension, "cur" ) )
		return true;
	if ( !Q_stricmp( extension, "ani" ) )
		return true;
	return false;
}
#endif // !_X360

vgui::IImage *CMatSystemSurface::GetIconImageForFullPath( char const *pFullPath )
{
	vgui::IImage *newIcon = NULL;

#if defined( WIN32 ) && !defined( _X360 )
	SHFILEINFO info = { 0 };
	DWORD_PTR dwResult = SHGetFileInfo( 
		pFullPath,
		0,
		&info,
		sizeof( info ),
		SHGFI_TYPENAME | SHGFI_ICON | SHGFI_SMALLICON | SHGFI_SHELLICONSIZE 
	);
	if ( dwResult )
	{
		if ( info.szTypeName[ 0 ] != 0 )
		{
			char ext[ 32 ];
			Q_ExtractFileExtension( pFullPath, ext, sizeof( ext ) );

			char lookup[ 512 ];
			Q_snprintf( lookup, sizeof( lookup ), "%s", ShouldMakeUnique( ext ) ? pFullPath : info.szTypeName );
			
			// Now check the dictionary
			unsigned short idx = m_FileTypeImages.Find( lookup );
			if ( idx == m_FileTypeImages.InvalidIndex() )
			{
				ICONINFO iconInfo;
				if ( 0 != GetIconInfo( info.hIcon, &iconInfo ) )
				{
					int w, h;
					size_t bufsize = 0;
					
					HDC hdc = ::GetDC(reinterpret_cast<HWND>(m_HWnd));

					if ( GetIconBits( hdc, iconInfo, w, h, NULL, bufsize ) )
					{
						byte *bits = new byte[ bufsize ];
						if ( bits && GetIconBits( hdc, iconInfo, w, h, bits, bufsize ) )
						{
							newIcon = new MemoryBitmap( bits, w, h );
						}
						delete[] bits;
					}

					::ReleaseDC( reinterpret_cast<HWND>(m_HWnd), hdc );
				}

				idx = m_FileTypeImages.Insert( lookup, newIcon );
			}

			newIcon = m_FileTypeImages[ idx ];
		}

		DestroyIcon( info.hIcon );
	}
#endif
	return newIcon;
}

const char *CMatSystemSurface::GetResolutionKey( void ) const
{
	Assert( !IsPC() );
	int x, y, width, height;
	CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
	pRenderContext->GetViewport( x, y, width, height );
	if( height <= 480 )
	{
		return "_lodef";
	}
	else
	{
		return "_hidef";
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CMatSystemSurface::Set3DPaintTempRenderTarget( const char *pRenderTargetName )
{
	MAT_FUNC;

	Assert( !m_bUsingTempFullScreenBufferMaterial );
	m_bUsingTempFullScreenBufferMaterial = true;

	InitFullScreenBuffer( pRenderTargetName );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CMatSystemSurface::Reset3DPaintTempRenderTarget( void )
{
	MAT_FUNC;

	Assert( m_bUsingTempFullScreenBufferMaterial );
	m_bUsingTempFullScreenBufferMaterial = false;

	InitFullScreenBuffer( "_rt_FullScreen" );
}


//-----------------------------------------------------------------------------
// Purpose: Sets the origin of the viewport to render into if we were 
//			rendering into the frame buffer. This version of the function is 
//			mostly here for backward compatibility and always uses a NULL
//			render target (i.e. the frame buffer.)
//-----------------------------------------------------------------------------
void CMatSystemSurface::SetFullscreenViewport( int x, int y, int w, int h )
{
	SetFullscreenViewportAndRenderTarget( x, y, w, h, NULL );
}


//-----------------------------------------------------------------------------
// Purpose: Sets the origin of the viewport to render into if we were 
//			rendering into the frame buffer. We might actually be generally
//			using a render target but need to switch back to the frame buffer
//			for some panels.
//-----------------------------------------------------------------------------
void CMatSystemSurface::SetFullscreenViewportAndRenderTarget( int x, int y, int w, int h, ITexture *pRenderTarget ) 
{ 
	m_nFullscreenViewportX = x; 
	m_nFullscreenViewportY = y; 
	m_nFullscreenViewportWidth = w; 
	m_nFullscreenViewportHeight = h; 
	m_pFullscreenRenderTarget = pRenderTarget;
}


//-----------------------------------------------------------------------------
// Purpose: Gets the origin of the viewport to render into if we were 
//			rendering into the frame buffer. We might actually be generally
//			using a render target but need to switch back to the frame buffer
//			for some panels.
//-----------------------------------------------------------------------------
void CMatSystemSurface::GetFullscreenViewportAndRenderTarget( int & x, int & y, int & w, int & h, ITexture **ppRenderTarget ) 
{ 
	if( m_nFullscreenViewportHeight == 0 )
	{
		// this can't actually be zero. If it is, use the height of the screen instead
		x = y = 0;
		GetScreenSize( w, h );
		if( ppRenderTarget)
			*ppRenderTarget = NULL;
	}
	else
	{
		x = m_nFullscreenViewportX; 
		y = m_nFullscreenViewportY; 
		w = m_nFullscreenViewportWidth; 
		h = m_nFullscreenViewportHeight;  
		if( ppRenderTarget)
			*ppRenderTarget = m_pFullscreenRenderTarget;
	}
}
void CMatSystemSurface::GetFullscreenViewport( int & x, int & y, int & w, int & h ) 
{
	GetFullscreenViewportAndRenderTarget( x, y, w, h, NULL );
}


//-----------------------------------------------------------------------------
// Purpose: Handle switching in and out of "render to fullscreen" mode. We don't
//			actually support this mode in tools.
//-----------------------------------------------------------------------------
void CMatSystemSurface::PushFullscreenViewport()
{
	CMatRenderContextPtr pRenderContext( materials );

	// the viewport x/y will be wrong because the render target is only for one eye. 
	// Ask the surface for that information instead.
	int vx, vy, vw, vh;
	ITexture *pRenderTarget;
	GetFullscreenViewportAndRenderTarget( vx, vy, vw, vh, &pRenderTarget );
	pRenderContext->PushRenderTargetAndViewport( pRenderTarget, NULL, vx, vy, vw, vh );

	pRenderContext->MatrixMode( MATERIAL_PROJECTION );
	pRenderContext->PushMatrix();
	pRenderContext->LoadIdentity();
	pRenderContext->Scale( 1, -1, 1 );
	
	//___stop___();
	pRenderContext->Ortho( g_flPixelOffsetX, g_flPixelOffsetY, vw + g_flPixelOffsetX, vh + g_flPixelOffsetY, -1.0f, 1.0f ); 

	DisableClipping( true );
}

void CMatSystemSurface::PopFullscreenViewport()
{
	CMatRenderContextPtr pRenderContext( materials );

	pRenderContext->PopRenderTargetAndViewport();

	pRenderContext->MatrixMode( MATERIAL_PROJECTION );
	pRenderContext->PopMatrix();

	DisableClipping( false );
}


//-----------------------------------------------------------------------------
// Purpose: Handle switching in and out of "render to fullscreen" mode. We don't
//			actually support this mode in tools.
//-----------------------------------------------------------------------------
void CMatSystemSurface::SetSoftwareCursor( bool bUseSoftwareCursor )
{
	EnableSoftwareCursor( bUseSoftwareCursor );
}

void CMatSystemSurface::PaintSoftwareCursor()
{
	if( !ShouldDrawSoftwareCursor() )
		return;

	// this asks Windows for the position RIGHT NOW, which should be the least 
	// latent notion we have of where to draw the cursor
	int x, y;
	GetCursorPos( x, y );

	Color clr( 255, 255, 255, 255 );

	float uOffset, vOffset;
	int nTextureID = GetSoftwareCursorTexture( &uOffset, &vOffset );
	if( nTextureID <= 0 )
		return;

	int w, h;
	DrawGetTextureSize( nTextureID, w, h );

	// the cursors are actually pretty big. Make them smaller.
	w /= 2;
	h /= 2;

	int xOffset = (int)(uOffset * (float)w);
	int yOffset = (int)(vOffset * (float)h);

	Assert( !g_bInDrawing );
	StartDrawing();

	PaintState_t paintState;
	paintState.m_iTranslateX = paintState.m_iTranslateY = 0;
	paintState.m_iScissorLeft = paintState.m_iScissorTop = 0;
	GetScreenSize( paintState.m_iScissorRight, paintState.m_iScissorBottom );

	SetupPaintState( paintState );

	DrawSetColor( clr );
	DrawSetTexture( nTextureID );
	DrawTexturedRect( x + xOffset, y + yOffset, x + xOffset + w, y + yOffset + h );
	DrawSetTexture(0);

	FinishDrawing();
}

int CMatSystemSurface::GetTextureNumFrames( int id )
{
	IMaterial *pMaterial = TextureDictionary()->GetTextureMaterial( id );
	if ( !pMaterial )
	{
		return 0;
	}
	return pMaterial->GetNumAnimationFrames();
}

void CMatSystemSurface::DrawSetTextureFrame( int id, int nFrame, unsigned int *pFrameCache )
{
	IMaterial *pMaterial = TextureDictionary()->GetTextureMaterial( id );
	if ( !pMaterial )
	{
		return;
	}

	int nTotalFrames = pMaterial->GetNumAnimationFrames();
	if ( !nTotalFrames )
	{
		return;
	}

	IMaterialVar *pFrameVar = pMaterial->FindVarFast( "$frame", pFrameCache );
	if ( pFrameVar )
	{
		pFrameVar->SetIntValue( nFrame % nTotalFrames );
	}
}