This commit is contained in:
FluorescentCIAAfricanAmerican
2020-04-22 12:56:21 -04:00
commit 3bf9df6b27
15370 changed files with 5489726 additions and 0 deletions

457
vguimatsurface/Clip2D.cpp Normal file
View File

@ -0,0 +1,457 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Contains 2D clipping routines
//
// $Revision: $
// $NoKeywords: $
//=============================================================================//
#include <vgui/ISurface.h>
#include "Clip2D.h"
#include "tier0/dbg.h"
#include "utlvector.h"
#if defined( _X360 )
#include "materialsystem/imaterialsystem.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Stretch texture to fit window ( before scissoring )
//-----------------------------------------------------------------------------
static bool g_bStretchTexture = false;
//-----------------------------------------------------------------------------
// Max # of vertices for clipping
//-----------------------------------------------------------------------------
enum
{
VGUI_VERTEX_TEMP_COUNT = 48,
};
//-----------------------------------------------------------------------------
// For simulated scissor tests...
//-----------------------------------------------------------------------------
struct ScissorRect_t
{
int left;
int top;
int right;
int bottom;
};
static ScissorRect_t g_ScissorRect;
static bool g_bScissor = false;
static bool g_bFullScreenScissor = false;
//-----------------------------------------------------------------------------
// Enable/disable scissoring...
//-----------------------------------------------------------------------------
void EnableScissor( bool enable )
{
g_bScissor = enable;
}
void SetScissorRect( int left, int top, int right, int bottom )
{
// Check for a valid rectangle...
Assert( left <= right );
Assert( top <= bottom );
if ( g_ScissorRect.left == left && g_ScissorRect.right == right &&
g_ScissorRect.top == top && g_ScissorRect.bottom == bottom )
return;
g_ScissorRect.left = left;
g_ScissorRect.top = top;
g_ScissorRect.right = right;
g_ScissorRect.bottom = bottom;
#if defined( _X360 )
// no reason to waste cpu on full screen scissor, gpu does it
CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
int vx, vy, vw, vh;
pRenderContext->GetViewport( vx, vy, vw, vh );
g_bFullScreenScissor = (left <= vx && top <= vy && right >= vw && bottom >= vh );
#endif
}
void GetScissorRect( int &left, int &top, int &right, int &bottom, bool &enabled )
{
left = g_ScissorRect.left;
top = g_ScissorRect.top;
right = g_ScissorRect.right;
bottom = g_ScissorRect.bottom;
enabled = g_bScissor;
}
//-----------------------------------------------------------------------------
// Used to clip the shadow decals
//-----------------------------------------------------------------------------
struct PolygonClipState_t
{
int m_CurrVert;
int m_TempCount;
int m_ClipCount;
vgui::Vertex_t m_pTempVertices[VGUI_VERTEX_TEMP_COUNT];
vgui::Vertex_t* m_ppClipVertices[2][VGUI_VERTEX_TEMP_COUNT];
};
//-----------------------------------------------------------------------------
// Clipping methods for 2D
//-----------------------------------------------------------------------------
class CClipTop
{
public:
static inline bool Inside( vgui::Vertex_t const& vert )
{
return vert.m_Position.y >= g_ScissorRect.top;
}
static inline float Clip( const Vector2D& one, const Vector2D& two )
{
return (g_ScissorRect.top - one.y) / (two.y - one.y);
}
};
class CClipLeft
{
public:
static inline bool Inside( vgui::Vertex_t const& vert )
{
return vert.m_Position.x >= g_ScissorRect.left;
}
static inline float Clip( const Vector2D& one, const Vector2D& two )
{
return (one.x - g_ScissorRect.left) / (one.x - two.x);
}
};
class CClipRight
{
public:
static inline bool Inside( vgui::Vertex_t const& vert )
{
return vert.m_Position.x < g_ScissorRect.right;
}
static inline float Clip( const Vector2D& one, const Vector2D& two )
{
return (g_ScissorRect.right - one.x) / (two.x - one.x);
}
};
class CClipBottom
{
public:
static inline bool Inside( vgui::Vertex_t const& vert )
{
return vert.m_Position.y < g_ScissorRect.bottom;
}
static inline float Clip( const Vector2D& one, const Vector2D& two )
{
return (one.y - g_ScissorRect.bottom) / (one.y - two.y);
}
};
template <class Clipper>
static inline void Intersect( const vgui::Vertex_t& start, const vgui::Vertex_t& end, vgui::Vertex_t* pOut, Clipper& clipper )
{
// Clip to the scissor rectangle
float t = Clipper::Clip( start.m_Position, end.m_Position );
Vector2DLerp( start.m_Position, end.m_Position, t, pOut->m_Position );
Vector2DLerp( start.m_TexCoord, end.m_TexCoord, t, pOut->m_TexCoord );
}
//-----------------------------------------------------------------------------
// Clips a line segment to a single plane
//-----------------------------------------------------------------------------
template< class Clipper >
bool ClipLineToPlane( Clipper &clipper, const vgui::Vertex_t *pInVerts, vgui::Vertex_t* pOutVerts )
{
bool startInside = Clipper::Inside( pInVerts[0] );
bool endInside = Clipper::Inside( pInVerts[1] );
// Cull
if (!startInside && !endInside)
return false;
if (startInside && endInside)
{
pOutVerts[0] = pInVerts[0];
pOutVerts[1] = pInVerts[1];
}
else
{
int inIndex = startInside ? 0 : 1;
pOutVerts[inIndex] = pInVerts[inIndex];
Intersect( pInVerts[0], pInVerts[1], &pOutVerts[1 - inIndex], clipper );
}
return true;
}
//-----------------------------------------------------------------------------
// Clips a line segment to the current scissor rectangle
//-----------------------------------------------------------------------------
bool ClipLine( const vgui::Vertex_t *pInVerts, vgui::Vertex_t* pOutVerts )
{
if ( g_bScissor && !g_bFullScreenScissor )
{
// Clippers...
CClipTop top;
CClipBottom bottom;
CClipLeft left;
CClipRight right;
// Sutherland-hodgman clip, not particularly efficient but that's ok for now
vgui::Vertex_t tempVerts[2];
if (!ClipLineToPlane( top, pInVerts, tempVerts ))
return false;
if (!ClipLineToPlane( bottom, tempVerts, pOutVerts ))
return false;
if (!ClipLineToPlane( left, pOutVerts, tempVerts ))
return false;
if (!ClipLineToPlane( right, tempVerts, pOutVerts ))
return false;
return true;
}
else
{
pOutVerts[0] = pInVerts[0];
pOutVerts[1] = pInVerts[1];
return true;
}
}
//-----------------------------------------------------------------------------
// Methods associated with clipping 2D polygons
//-----------------------------------------------------------------------------
struct ScreenClipState_t
{
int m_iCurrVert;
int m_iTempCount;
int m_iClipCount;
CUtlVector<vgui::Vertex_t> m_pTempVertices;
CUtlVector<vgui::Vertex_t*> m_ppClipVertices[2];
};
template <class Clipper>
static void ScreenClip( ScreenClipState_t& clip, Clipper& clipper )
{
if (clip.m_iClipCount < 3)
return;
// Ye Olde Sutherland-Hodgman clipping algorithm
int numOutVerts = 0;
vgui::Vertex_t** pSrcVert = clip.m_ppClipVertices[clip.m_iCurrVert].Base();
vgui::Vertex_t** pDestVert = clip.m_ppClipVertices[!clip.m_iCurrVert].Base();
int numVerts = clip.m_iClipCount;
vgui::Vertex_t* pStart = pSrcVert[numVerts-1];
bool startInside = Clipper::Inside( *pStart );
for (int i = 0; i < numVerts; ++i)
{
vgui::Vertex_t* pEnd = pSrcVert[i];
bool endInside = Clipper::Inside( *pEnd );
if (endInside)
{
if (!startInside)
{
// Started outside, ended inside, need to clip the edge
Assert( clip.m_iTempCount <= clip.m_pTempVertices.Count() );
// Allocate a new clipped vertex
pDestVert[numOutVerts] = &clip.m_pTempVertices[clip.m_iTempCount++];
// Clip the edge to the clip plane
Intersect( *pStart, *pEnd, pDestVert[numOutVerts], clipper );
++numOutVerts;
}
pDestVert[numOutVerts++] = pEnd;
}
else
{
if (startInside)
{
// Started inside, ended outside, need to clip the edge
Assert( clip.m_iTempCount <= clip.m_pTempVertices.Count() );
// Allocate a new clipped vertex
pDestVert[numOutVerts] = &clip.m_pTempVertices[clip.m_iTempCount++];
// Clip the edge to the clip plane
Intersect( *pStart, *pEnd, pDestVert[numOutVerts], clipper );
++numOutVerts;
}
}
pStart = pEnd;
startInside = endInside;
}
// Switch source lists
clip.m_iCurrVert = 1 - clip.m_iCurrVert;
clip.m_iClipCount = numOutVerts;
}
//-----------------------------------------------------------------------------
// Clips a polygon to the screen area
//-----------------------------------------------------------------------------
int ClipPolygon( int iCount, vgui::Vertex_t *pVerts, int iTranslateX, int iTranslateY, vgui::Vertex_t ***pppOutVertex )
{
static ScreenClipState_t clip;
// Allocate enough room in the clip state...
// Having no reallocations during clipping
clip.m_pTempVertices.EnsureCount( iCount * 4 );
clip.m_ppClipVertices[0].EnsureCount( iCount * 4 );
clip.m_ppClipVertices[1].EnsureCount( iCount * 4 );
// Copy the initial verts in...
for (int i = 0; i < iCount; ++i)
{
// NOTE: This only works because we EnsuredCount above
clip.m_pTempVertices[i] = pVerts[i];
clip.m_pTempVertices[i].m_Position.x += iTranslateX;
clip.m_pTempVertices[i].m_Position.y += iTranslateY;
clip.m_ppClipVertices[0][i] = &clip.m_pTempVertices[i];
}
if ( !g_bScissor || g_bFullScreenScissor )
{
Assert(pppOutVertex);
*pppOutVertex = clip.m_ppClipVertices[0].Base();
return iCount;
}
clip.m_iClipCount = iCount;
clip.m_iTempCount = iCount;
clip.m_iCurrVert = 0;
// Clippers...
CClipTop top;
CClipBottom bottom;
CClipLeft left;
CClipRight right;
// Sutherland-hodgman clip
ScreenClip( clip, top );
ScreenClip( clip, bottom );
ScreenClip( clip, left );
ScreenClip( clip, right );
if (clip.m_iClipCount < 3)
return 0;
// Return a pointer to the array of clipped vertices...
Assert(pppOutVertex);
*pppOutVertex = clip.m_ppClipVertices[clip.m_iCurrVert].Base();
return clip.m_iClipCount;
}
//-----------------------------------------------------------------------------
// Purpose: Used for clipping, produces an interpolated texture coordinate
//-----------------------------------------------------------------------------
inline float InterpTCoord(float val, float mins, float maxs, float tMin, float tMax)
{
float flPercent;
if (mins != maxs)
flPercent = (float)(val - mins) / (maxs - mins);
else
flPercent = 0.5f;
return tMin + (tMax - tMin) * flPercent;
}
//-----------------------------------------------------------------------------
// Purpose: Does a scissor clip of the input rectangle.
// Returns false if it is completely clipped off.
//-----------------------------------------------------------------------------
bool ClipRect( const vgui::Vertex_t &inUL, const vgui::Vertex_t &inLR,
vgui::Vertex_t *pOutUL, vgui::Vertex_t *pOutLR )
{
// Check for a valid rectangle...
// Assert( inUL.m_Position.x <= inLR.m_Position.x );
// Assert( inUL.m_Position.y <= inLR.m_Position.y );
if ( IsX360() && ( !g_bScissor || g_bFullScreenScissor ||
( inUL.m_Position.x >= g_ScissorRect.left && inLR.m_Position.x <= g_ScissorRect.right && inUL.m_Position.y >= g_ScissorRect.top && inLR.m_Position.y <= g_ScissorRect.bottom ) ) )
{
// clipping is not needed
// either full screen, and hw will do it or rect is inscribed, and operation is meaningless
*pOutUL = inUL;
*pOutLR = inLR;
return true;
}
if ( g_bScissor )
{
// Pick whichever left side is larger
if (g_ScissorRect.left > inUL.m_Position.x)
pOutUL->m_Position.x = g_ScissorRect.left;
else
pOutUL->m_Position.x = inUL.m_Position.x;
// Pick whichever right side is smaller
if (g_ScissorRect.right <= inLR.m_Position.x)
pOutLR->m_Position.x = g_ScissorRect.right;
else
pOutLR->m_Position.x = inLR.m_Position.x;
// Pick whichever top side is larger
if (g_ScissorRect.top > inUL.m_Position.y)
pOutUL->m_Position.y = g_ScissorRect.top;
else
pOutUL->m_Position.y = inUL.m_Position.y;
// Pick whichever bottom side is smaller
if (g_ScissorRect.bottom <= inLR.m_Position.y)
pOutLR->m_Position.y = g_ScissorRect.bottom;
else
pOutLR->m_Position.y = inLR.m_Position.y;
// Check for non-intersecting
if ( (pOutUL->m_Position.x > pOutLR->m_Position.x) ||
(pOutUL->m_Position.y > pOutLR->m_Position.y) )
{
return false;
}
if ( !g_bStretchTexture )
{
pOutUL->m_TexCoord.x = InterpTCoord(pOutUL->m_Position.x,
inUL.m_Position.x, inLR.m_Position.x, inUL.m_TexCoord.x, inLR.m_TexCoord.x);
pOutLR->m_TexCoord.x = InterpTCoord(pOutLR->m_Position.x,
inUL.m_Position.x, inLR.m_Position.x, inUL.m_TexCoord.x, inLR.m_TexCoord.x);
pOutUL->m_TexCoord.y = InterpTCoord(pOutUL->m_Position.y,
inUL.m_Position.y, inLR.m_Position.y, inUL.m_TexCoord.y, inLR.m_TexCoord.y);
pOutLR->m_TexCoord.y = InterpTCoord(pOutLR->m_Position.y,
inUL.m_Position.y, inLR.m_Position.y, inUL.m_TexCoord.y, inLR.m_TexCoord.y);
}
else
{
// FIXME, this isn't right
pOutUL->m_TexCoord = inUL.m_TexCoord;
pOutLR->m_TexCoord = inLR.m_TexCoord;
}
}
else
{
*pOutUL = inUL;
*pOutLR = inLR;
}
return true;
}

46
vguimatsurface/Clip2D.h Normal file
View File

@ -0,0 +1,46 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Contains 2D clipping routines
//
// $Revision: $
// $NoKeywords: $
//=============================================================================//
#ifndef CLIP2D_H
#define CLIP2D_H
namespace vgui
{
struct Vertex_t;
}
//-----------------------------------------------------------------------------
// Enable/disable scissoring...
//-----------------------------------------------------------------------------
void EnableScissor( bool enable );
//-----------------------------------------------------------------------------
// For simulated scissor tests...
//-----------------------------------------------------------------------------
void SetScissorRect( int left, int top, int right, int bottom );
void GetScissorRect( int &left, int &top, int &right, int &bottom, bool &enabled );
//-----------------------------------------------------------------------------
// Clips a line segment to the current scissor rectangle
//-----------------------------------------------------------------------------
bool ClipLine( const vgui::Vertex_t *pInVerts, vgui::Vertex_t* pOutVerts );
//-----------------------------------------------------------------------------
// Purpose: Does a scissor clip of the input rectangle.
// Returns false if it is completely clipped off.
//-----------------------------------------------------------------------------
bool ClipRect( const vgui::Vertex_t &inUL, const vgui::Vertex_t &inLR,
vgui::Vertex_t *pOutUL, vgui::Vertex_t *pOutLR );
//-----------------------------------------------------------------------------
// Clips a polygon to the screen area
//-----------------------------------------------------------------------------
int ClipPolygon( int iCount, vgui::Vertex_t *pVerts, int iTranslateX, int iTranslateY, vgui::Vertex_t ***pppOutVertex );
#endif // CLIP2D_H

565
vguimatsurface/Cursor.cpp Normal file
View File

@ -0,0 +1,565 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Methods associated with the cursor
//
// $Revision: $
// $NoKeywords: $
//===========================================================================//
#if !defined( _X360 )
#define OEMRESOURCE //for OCR_* cursor junk
#include "winlite.h"
#endif
#include <appframework/ilaunchermgr.h>
#if defined( USE_SDL )
#undef M_PI
#include "SDL.h"
#endif
#include "tier0/dbg.h"
#include "tier0/vcrmode.h"
#include "tier0/icommandline.h"
#include "tier1/utldict.h"
#include "Cursor.h"
#include "vguimatsurface.h"
#include "MatSystemSurface.h"
#include "filesystem.h"
#if defined( _X360 )
#include "xbox/xbox_win32stubs.h"
#endif
#if defined( USE_SDL )
#include "materialsystem/imaterialsystem.h"
#endif
#include "inputsystem/iinputsystem.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
using namespace vgui;
#if defined( USE_SDL )
static SDL_Cursor *s_pDefaultCursor[ dc_last ];
static SDL_Cursor *s_hCurrentCursor = NULL;
static SDL_Cursor *s_hCurrentlySetCursor = NULL;
#elif defined( WIN32 )
static HICON s_pDefaultCursor[ dc_last ];
static HICON s_hCurrentCursor = NULL;
#endif
static bool s_bCursorLocked = false;
static bool s_bCursorVisible = true;
static int s_nForceCursorVisibleCount = 0;
static bool s_bSoftwareCursorActive = false;
static int s_nSoftwareCursorTexture = -1;
static float s_fSoftwareCursorOffsetX = 0;
static float s_fSoftwareCursorOffsetY = 0;
static int s_rnSoftwareCursorID[20];
static float s_rfSoftwareCursorOffset[20][2];
static bool s_bSoftwareCursorsInitialized = false;
extern CMatSystemSurface g_MatSystemSurface;
//-----------------------------------------------------------------------------
// Initializes cursors
//-----------------------------------------------------------------------------
void InitCursors()
{
// load up all default cursors
#if defined( USE_SDL )
s_pDefaultCursor[ dc_none ] = NULL;
s_pDefaultCursor[ dc_arrow ] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_ARROW );
s_pDefaultCursor[ dc_ibeam ] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_IBEAM );
s_pDefaultCursor[ dc_hourglass ]= SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_WAIT );
s_pDefaultCursor[ dc_crosshair ]= SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_CROSSHAIR );
s_pDefaultCursor[ dc_waitarrow ]= SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_WAITARROW );
s_pDefaultCursor[ dc_sizenwse ] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_SIZENWSE );
s_pDefaultCursor[ dc_sizenesw ] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_SIZENESW );
s_pDefaultCursor[ dc_sizewe ] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_SIZEWE );
s_pDefaultCursor[ dc_sizens ] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_SIZENS );
s_pDefaultCursor[ dc_sizeall ] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_SIZEALL );
s_pDefaultCursor[ dc_no ] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_NO );
s_pDefaultCursor[ dc_hand ] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_HAND );
s_hCurrentCursor = s_pDefaultCursor[ dc_arrow ];
#elif defined( WIN32 )
s_pDefaultCursor[ dc_none ] = NULL;
s_pDefaultCursor[ dc_arrow ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_NORMAL);
s_pDefaultCursor[ dc_ibeam ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_IBEAM);
s_pDefaultCursor[ dc_hourglass ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_WAIT);
s_pDefaultCursor[ dc_crosshair ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_CROSS);
s_pDefaultCursor[ dc_waitarrow ] =(HICON)LoadCursor(NULL, (LPCTSTR)32650);
s_pDefaultCursor[ dc_up ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_UP);
s_pDefaultCursor[ dc_sizenwse ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_SIZENWSE);
s_pDefaultCursor[ dc_sizenesw ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_SIZENESW);
s_pDefaultCursor[ dc_sizewe ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_SIZEWE);
s_pDefaultCursor[ dc_sizens ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_SIZENS);
s_pDefaultCursor[ dc_sizeall ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_SIZEALL);
s_pDefaultCursor[ dc_no ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_NO);
s_pDefaultCursor[ dc_hand ] =(HICON)LoadCursor(NULL, (LPCTSTR)32649);
s_hCurrentCursor = s_pDefaultCursor[ dc_arrow ];
#endif
s_bCursorLocked = false;
s_bCursorVisible = true;
s_nForceCursorVisibleCount = 0;
}
#define USER_CURSOR_MASK 0x80000000
#ifdef WIN32
//-----------------------------------------------------------------------------
// Purpose: Simple manager for user loaded windows cursors in vgui
//-----------------------------------------------------------------------------
class CUserCursorManager
{
public:
void Shutdown();
vgui::HCursor CreateCursorFromFile( char const *curOrAniFile, char const *pPathID );
bool LookupCursor( vgui::HCursor cursor, HCURSOR& handle );
private:
CUtlDict< HCURSOR, int > m_UserCursors;
};
void CUserCursorManager::Shutdown()
{
for ( int i = m_UserCursors.First() ; i != m_UserCursors.InvalidIndex(); i = m_UserCursors.Next( i ) )
{
::DestroyCursor( m_UserCursors[ i ] );
}
m_UserCursors.RemoveAll();
}
vgui::HCursor CUserCursorManager::CreateCursorFromFile( char const *curOrAniFile, char const *pPathID )
{
char fn[ 512 ];
Q_strncpy( fn, curOrAniFile, sizeof( fn ) );
Q_strlower( fn );
Q_FixSlashes( fn );
int cursorIndex = m_UserCursors.Find( fn );
if ( cursorIndex != m_UserCursors.InvalidIndex() )
{
return cursorIndex | USER_CURSOR_MASK;
}
g_pFullFileSystem->GetLocalCopy( fn );
char fullpath[ 512 ];
g_pFullFileSystem->RelativePathToFullPath( fn, pPathID, fullpath, sizeof( fullpath ) );
HCURSOR newCursor = (HCURSOR)LoadCursorFromFile( fullpath );
cursorIndex = m_UserCursors.Insert( fn, newCursor );
return cursorIndex | USER_CURSOR_MASK;
}
bool CUserCursorManager::LookupCursor( vgui::HCursor cursor, HCURSOR& handle )
{
if ( !( (int)cursor & USER_CURSOR_MASK ) )
{
handle = 0;
return false;
}
int cursorIndex = (int)cursor & ~USER_CURSOR_MASK;
if ( !m_UserCursors.IsValidIndex( cursorIndex ) )
{
handle = 0;
return false;
}
handle = m_UserCursors[ cursorIndex ];
return true;
}
static CUserCursorManager g_UserCursors;
#endif
vgui::HCursor Cursor_CreateCursorFromFile( char const *curOrAniFile, char const *pPathID )
{
#ifdef WIN32
return g_UserCursors.CreateCursorFromFile( curOrAniFile, pPathID );
#else
return dc_user;
#endif
}
void Cursor_ClearUserCursors()
{
#ifdef WIN32
g_UserCursors.Shutdown();
#endif
}
//-----------------------------------------------------------------------------
// Initializes all the textures for software cursors
//-----------------------------------------------------------------------------
int InitSoftwareCursorTexture( const char *pchFilename )
{
if( !pchFilename || !*pchFilename )
return -1;
int nTextureID = g_MatSystemSurface.DrawGetTextureId( pchFilename );
if( nTextureID == -1 )
{
nTextureID = g_MatSystemSurface.CreateNewTextureID();
g_MatSystemSurface.DrawSetTextureFile( nTextureID, pchFilename, true, false );
}
return nTextureID;
}
void InitSoftwareCursors()
{
if( s_bSoftwareCursorsInitialized )
return;
memset( s_rfSoftwareCursorOffset, 0, sizeof( s_rfSoftwareCursorOffset ) );
s_rnSoftwareCursorID[dc_none] = -1;
s_rnSoftwareCursorID[dc_arrow] =InitSoftwareCursorTexture( "vgui/cursors/arrow" );
s_rnSoftwareCursorID[dc_ibeam] =InitSoftwareCursorTexture( "vgui/cursors/ibeam" );
s_rnSoftwareCursorID[dc_hourglass]=InitSoftwareCursorTexture( "vgui/cursors/hourglass" );
s_rnSoftwareCursorID[dc_crosshair]=InitSoftwareCursorTexture( "vgui/cursors/crosshair" );
s_rnSoftwareCursorID[dc_waitarrow]=InitSoftwareCursorTexture( "vgui/cursors/waitarrow" );
s_rnSoftwareCursorID[dc_up] =InitSoftwareCursorTexture( "vgui/cursors/up" );
s_rnSoftwareCursorID[dc_sizenwse] =InitSoftwareCursorTexture( "vgui/cursors/sizenwse" );
s_rnSoftwareCursorID[dc_sizenesw] =InitSoftwareCursorTexture( "vgui/cursors/sizenesw" );
s_rnSoftwareCursorID[dc_sizewe] =InitSoftwareCursorTexture( "vgui/cursors/sizewe" );
s_rnSoftwareCursorID[dc_sizens] =InitSoftwareCursorTexture( "vgui/cursors/sizens" );
s_rnSoftwareCursorID[dc_sizeall] =InitSoftwareCursorTexture( "vgui/cursors/sizeall" );
s_rnSoftwareCursorID[dc_no] =InitSoftwareCursorTexture( "vgui/cursors/no" );
s_rnSoftwareCursorID[dc_hand] =InitSoftwareCursorTexture( "vgui/cursors/hand" );
// handle the cursor hotspots not being at their origin
s_rfSoftwareCursorOffset[dc_arrow][0] = -0.1;
s_rfSoftwareCursorOffset[dc_arrow][1] = -0.1;
s_rfSoftwareCursorOffset[dc_ibeam][0] = -0.5;
s_rfSoftwareCursorOffset[dc_ibeam][1] = -0.8;
s_rfSoftwareCursorOffset[dc_hourglass][0] = -0.5;
s_rfSoftwareCursorOffset[dc_hourglass][1] = -0.5;
s_rfSoftwareCursorOffset[dc_crosshair][0] = -0.5;
s_rfSoftwareCursorOffset[dc_crosshair][1] = -0.5;
s_rfSoftwareCursorOffset[dc_waitarrow][0] = -0.1;
s_rfSoftwareCursorOffset[dc_waitarrow][1] = -0.1;
s_rfSoftwareCursorOffset[dc_up][0] = -0.5;
s_rfSoftwareCursorOffset[dc_up][1] = -0.5;
s_rfSoftwareCursorOffset[dc_sizenwse][0] = -0.5;
s_rfSoftwareCursorOffset[dc_sizenwse][1] = -0.5;
s_rfSoftwareCursorOffset[dc_sizenesw][0] = -0.5;
s_rfSoftwareCursorOffset[dc_sizenesw][1] = -0.5;
s_rfSoftwareCursorOffset[dc_sizewe][0] = -0.5;
s_rfSoftwareCursorOffset[dc_sizewe][1] = -0.5;
s_rfSoftwareCursorOffset[dc_sizens][0] = -0.5;
s_rfSoftwareCursorOffset[dc_sizens][1] = -0.5;
s_rfSoftwareCursorOffset[dc_sizeall][0] = -0.5;
s_rfSoftwareCursorOffset[dc_sizeall][1] = -0.5;
s_rfSoftwareCursorOffset[dc_no][0] = -0.5;
s_rfSoftwareCursorOffset[dc_no][1] = -0.5;
s_rfSoftwareCursorOffset[dc_hand][0] = -0.5;
s_rfSoftwareCursorOffset[dc_hand][1] = -0.5;
s_bSoftwareCursorsInitialized = true;
}
//-----------------------------------------------------------------------------
// Selects a cursor
//-----------------------------------------------------------------------------
void CursorSelect(HCursor hCursor)
{
if ( ( hCursor == dc_alwaysvisible_push ) || ( hCursor == dc_alwaysvisible_pop ) )
{
// CConPanel in engine/console.cpp does a SetCursor(null). So when the TF2 chat window pops up
// and there are console commands showing and fading out in the top left, our chat window
// will have a cursor show/hide fight with them. So the cursor flickers or doesn't show up
// at all. Unfortunately on Linux, it's even worse since we recenter the mouse when it's
// not shown - so we added this API call which causes cursor.cpp to always show the cursor.
s_nForceCursorVisibleCount += ( hCursor == dc_alwaysvisible_push ? 1 : -1 );
Assert( s_nForceCursorVisibleCount >= 0 );
if( ( s_nForceCursorVisibleCount && !s_bCursorVisible ) ||
( !s_nForceCursorVisibleCount && s_bCursorVisible ) )
{
ActivateCurrentCursor();
}
return;
}
if (s_bCursorLocked)
return;
#if defined( WIN32 ) && !defined( USE_SDL )
s_bCursorVisible = true;
switch (hCursor)
{
case dc_user:
case dc_none:
case dc_blank:
s_bCursorVisible = false;
break;
case dc_arrow:
case dc_waitarrow:
case dc_ibeam:
case dc_hourglass:
case dc_crosshair:
case dc_up:
case dc_sizenwse:
case dc_sizenesw:
case dc_sizewe:
case dc_sizens:
case dc_sizeall:
case dc_no:
case dc_hand:
if( !s_bSoftwareCursorActive )
{
s_hCurrentCursor = s_pDefaultCursor[hCursor];
}
else
{
s_nSoftwareCursorTexture = s_rnSoftwareCursorID[ hCursor ];
s_fSoftwareCursorOffsetX = s_rfSoftwareCursorOffset[ hCursor ][0];
s_fSoftwareCursorOffsetY = s_rfSoftwareCursorOffset[ hCursor ][1];
}
break;
default:
{
HCURSOR custom = 0;
if ( g_UserCursors.LookupCursor( hCursor, custom ) && custom != 0 )
{
s_hCurrentCursor = custom;
}
else
{
s_bCursorVisible = false;
Assert(0);
}
}
break;
}
ActivateCurrentCursor();
#elif defined( USE_SDL )
switch (hCursor)
{
case dc_user:
case dc_none:
case dc_blank:
s_bCursorVisible = false;
break;
default:
// We don't support custom cursors at the moment (but could, if necessary).
// Fall through and use the arrow for now...
Assert(0);
hCursor = dc_arrow;
case dc_arrow:
case dc_waitarrow:
case dc_ibeam:
case dc_hourglass:
case dc_crosshair:
case dc_up:
case dc_sizenwse:
case dc_sizenesw:
case dc_sizewe:
case dc_sizens:
case dc_sizeall:
case dc_no:
case dc_hand:
s_bCursorVisible = true;
if( !s_bSoftwareCursorActive )
{
s_hCurrentCursor = s_pDefaultCursor[hCursor];
}
else
{
s_nSoftwareCursorTexture = s_rnSoftwareCursorID[ hCursor ];
s_fSoftwareCursorOffsetX = s_rfSoftwareCursorOffset[ hCursor ][0];
s_fSoftwareCursorOffsetY = s_rfSoftwareCursorOffset[ hCursor ][1];
}
break;
}
ActivateCurrentCursor();
#else
#error
#endif
}
//-----------------------------------------------------------------------------
// Hides the hardware cursor
//-----------------------------------------------------------------------------
void HideHardwareCursor()
{
#if defined( WIN32 ) && !defined( USE_SDL )
::SetCursor(NULL);
#elif defined( USE_SDL )
//if ( s_hCurrentlySetCursor != s_pDefaultCursor[ dc_none ] )
{
s_hCurrentlySetCursor = s_pDefaultCursor[ dc_none ];
g_pLauncherMgr->SetMouseCursor( s_hCurrentlySetCursor );
g_pLauncherMgr->SetMouseVisible( false );
}
#else
#error
#endif
}
//-----------------------------------------------------------------------------
// Activates the current cursor
//-----------------------------------------------------------------------------
void ActivateCurrentCursor()
{
if( s_bSoftwareCursorActive )
{
HideHardwareCursor();
return;
}
if ( s_bCursorVisible || ( s_nForceCursorVisibleCount > 0 ) )
{
#if defined( WIN32 ) && !defined( USE_SDL )
::SetCursor(s_hCurrentCursor);
#elif defined( USE_SDL )
if (s_hCurrentlySetCursor != s_hCurrentCursor )
{
s_hCurrentlySetCursor = s_hCurrentCursor;
g_pLauncherMgr->SetMouseCursor( s_hCurrentlySetCursor );
g_pLauncherMgr->SetMouseVisible( true );
}
#else
#error
#endif
}
else
{
HideHardwareCursor();
}
}
//-----------------------------------------------------------------------------
// Purpose: prevents vgui from changing the cursor
//-----------------------------------------------------------------------------
void LockCursor( bool bEnable )
{
s_bCursorLocked = bEnable;
ActivateCurrentCursor();
}
//-----------------------------------------------------------------------------
// Purpose: unlocks the cursor state
//-----------------------------------------------------------------------------
bool IsCursorLocked()
{
return s_bCursorLocked;
}
//-----------------------------------------------------------------------------
// handles mouse movement
//-----------------------------------------------------------------------------
void CursorSetPos( void *hwnd, int x, int y )
{
#if defined( USE_SDL )
if ( s_bCursorVisible )
#endif
g_pInputSystem->SetCursorPosition( x, y );
}
void CursorGetPos(void *hwnd, int &x, int &y)
{
#if defined ( USE_SDL ) && !defined( PLATFORM_WINDOWS )
if ( s_bCursorVisible )
{
SDL_GetMouseState( &x, &y );
int windowHeight = 0;
int windowWidth = 0;
//unsigned int ignored;
SDL_GetWindowSize( ( SDL_Window * )g_pLauncherMgr->GetWindowRef(), &windowWidth, &windowHeight );
CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
int rx, ry, width, height;
pRenderContext->GetViewport( rx, ry, width, height );
if ( !s_bSoftwareCursorActive && (width != windowWidth || height != windowHeight ) )
{
// scale the x/y back into the co-ords of the back buffer, not the scaled up window
//DevMsg( "Mouse x:%d y:%d %d %d %d %d\n", x, y, width, windowWidth, height, abs( height - windowHeight ) );
x = x * (float)width/windowWidth;
y = y * (float)height/windowHeight;
}
}
else
{
// cursor is invisible, just say we have it pinned to the middle of the screen
CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
int rx, ry, width, height;
pRenderContext->GetViewport( rx, ry, width, height );
x = rx + width/2;
y = ry + height/2;
//printf( "Mouse(inv) x:%d y:%d %d %d\n", x, y, width, height );
}
#else
POINT pt;
// Default implementation
VCRHook_GetCursorPos( &pt );
VCRHook_ScreenToClient((HWND)hwnd, &pt);
x = pt.x; y = pt.y;
#endif
}
void EnableSoftwareCursor( bool bEnable )
{
if( bEnable )
InitSoftwareCursors();
bool bWasEnabled = s_bSoftwareCursorActive;
s_bSoftwareCursorActive = bEnable;
// set the cursor to the arrow (or none if appropriate) if we're activating the
// software cursor. VGUI will likely update it again soon, but this will give
// us some kind of cursor in the meantime
if( !bWasEnabled && bEnable )
{
if( s_bCursorVisible )
CursorSelect( dc_arrow );
}
}
bool ShouldDrawSoftwareCursor()
{
return s_bSoftwareCursorActive && s_bCursorVisible;
}
int GetSoftwareCursorTexture( float *px, float *py )
{
if( px && py )
{
*px = s_fSoftwareCursorOffsetX;
*py = s_fSoftwareCursorOffsetY;
}
return s_nSoftwareCursorTexture;
}

75
vguimatsurface/Cursor.h Normal file
View File

@ -0,0 +1,75 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Methods associated with the cursor
//
// $Revision: $
// $NoKeywords: $
//=============================================================================//
#ifndef MATSURFACE_CURSOR_H
#define MATSURFACE_CURSOR_H
#ifdef _WIN32
#pragma once
#endif
#include "VGuiMatSurface/IMatSystemSurface.h"
#include <vgui/Cursor.h>
//-----------------------------------------------------------------------------
// Initializes cursors
//-----------------------------------------------------------------------------
void InitCursors();
//-----------------------------------------------------------------------------
// Selects a cursor
//-----------------------------------------------------------------------------
void CursorSelect(vgui::HCursor hCursor);
//-----------------------------------------------------------------------------
// Activates the current cursor
//-----------------------------------------------------------------------------
void ActivateCurrentCursor();
//-----------------------------------------------------------------------------
// Handles software cursors
//-----------------------------------------------------------------------------
void EnableSoftwareCursor( bool bEnable );
bool ShouldDrawSoftwareCursor();
int GetSoftwareCursorTexture( float *px, float *py );
//-----------------------------------------------------------------------------
// handles mouse movement
//-----------------------------------------------------------------------------
void CursorSetPos(void *hwnd, int x, int y);
void CursorGetPos(void *hwnd, int &x, int &y);
//-----------------------------------------------------------------------------
// Purpose: prevents vgui from changing the cursor
//-----------------------------------------------------------------------------
void LockCursor( bool bEnable );
//-----------------------------------------------------------------------------
// Purpose: unlocks the cursor state
//-----------------------------------------------------------------------------
bool IsCursorLocked();
//-----------------------------------------------------------------------------
// Purpose: loads a custom cursor file from the file system
//-----------------------------------------------------------------------------
vgui::HCursor Cursor_CreateCursorFromFile( char const *curOrAniFile, char const *pPathID );
// Helper for shutting down cursors
void Cursor_ClearUserCursors();
#endif // MATSURFACE_CURSOR_H

View File

@ -0,0 +1,512 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#if defined ( WIN32 ) && !defined( _X360 )
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#elif defined( OSX )
#include <Carbon/Carbon.h>
#elif defined( LINUX )
//#error
#elif defined( _X360 )
#else
#error
#endif
#include "FontTextureCache.h"
#include "MatSystemSurface.h"
#include <vgui_surfacelib/BitmapFont.h>
#include <vgui/IVGui.h>
#include <vgui_controls/Controls.h>
#include "bitmap/imageformat.h"
#include "vtf/vtf.h"
#include "materialsystem/imaterialvar.h"
#include "materialsystem/itexture.h"
#include "tier1/KeyValues.h"
#include "tier1/utlbuffer.h"
#include "pixelwriter.h"
#include "tier0/icommandline.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern CMatSystemSurface g_MatSystemSurface;
static int g_FontRenderBoundingBoxes = -1;
#define TEXTURE_PAGE_WIDTH 256
#define TEXTURE_PAGE_HEIGHT 256
// row size
int CFontTextureCache::s_pFontPageSize[FONT_PAGE_SIZE_COUNT] =
{
16,
32,
64,
128,
256,
};
static bool g_mat_texture_outline_fonts = false;
CON_COMMAND( mat_texture_outline_fonts, "Outline fonts textures." )
{
g_mat_texture_outline_fonts = !g_mat_texture_outline_fonts;
Msg( "mat_texture_outline_fonts: %d\n", g_mat_texture_outline_fonts );
g_MatSystemSurface.ResetFontCaches();
}
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CFontTextureCache::CFontTextureCache()
: m_CharCache(0, 256, CacheEntryLessFunc)
{
Clear();
}
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CFontTextureCache::~CFontTextureCache()
{
}
//-----------------------------------------------------------------------------
// Purpose: Resets the cache
//-----------------------------------------------------------------------------
void CFontTextureCache::Clear()
{
// remove all existing data
m_CharCache.RemoveAll();
m_PageList.RemoveAll();
// reinitialize
CacheEntry_t listHead = { 0, 0 };
m_LRUListHeadIndex = m_CharCache.Insert(listHead);
m_CharCache[m_LRUListHeadIndex].nextEntry = m_LRUListHeadIndex;
m_CharCache[m_LRUListHeadIndex].prevEntry = m_LRUListHeadIndex;
for (int i = 0; i < FONT_PAGE_SIZE_COUNT; ++i)
{
m_pCurrPage[i] = -1;
}
m_FontPages.SetLessFunc( DefLessFunc( vgui::HFont ) );
m_FontPages.RemoveAll();
}
//-----------------------------------------------------------------------------
// Purpose: comparison function for cache entries
//-----------------------------------------------------------------------------
bool CFontTextureCache::CacheEntryLessFunc(CacheEntry_t const &lhs, CacheEntry_t const &rhs)
{
if (lhs.font < rhs.font)
return true;
else if (lhs.font > rhs.font)
return false;
return (lhs.wch < rhs.wch);
}
//-----------------------------------------------------------------------------
// Purpose: returns the texture info for the given char & font
//-----------------------------------------------------------------------------
bool CFontTextureCache::GetTextureForChar( vgui::HFont font, vgui::FontDrawType_t type, wchar_t wch, int *textureID, float **texCoords )
{
// Ask for just one character
return GetTextureForChars( font, type, &wch, textureID, texCoords, 1 );
}
//-----------------------------------------------------------------------------
// Purpose: returns the texture info for the given chars & font
//-----------------------------------------------------------------------------
bool CFontTextureCache::GetTextureForChars( vgui::HFont font, vgui::FontDrawType_t type, const wchar_t *wch, int *textureID, float **texCoords, int numChars )
{
Assert( wch && textureID && texCoords );
Assert( numChars >= 1 );
if ( type == vgui::FONT_DRAW_DEFAULT )
{
type = g_MatSystemSurface.IsFontAdditive( font ) ? vgui::FONT_DRAW_ADDITIVE : vgui::FONT_DRAW_NONADDITIVE;
}
int typePage = (int)type - 1;
typePage = clamp( typePage, 0, (int)vgui::FONT_DRAW_TYPE_COUNT - 1 );
if ( FontManager().IsBitmapFont( font ) )
{
const int MAX_BITMAP_CHARS = 256;
if ( numChars > MAX_BITMAP_CHARS )
{
// Increase MAX_BITMAP_CHARS
Assert( 0 );
return false;
}
for ( int i = 0; i < numChars; i++ )
{
static float sTexCoords[ 4*MAX_BITMAP_CHARS ];
CBitmapFont *pWinFont;
float left, top, right, bottom;
int index;
Page_t *pPage;
pWinFont = reinterpret_cast< CBitmapFont* >( FontManager().GetFontForChar( font, wch[i] ) );
if ( !pWinFont )
{
// bad font handle
return false;
}
// get the texture coords
pWinFont->GetCharCoords( wch[i], &left, &top, &right, &bottom );
sTexCoords[i*4 + 0] = left;
sTexCoords[i*4 + 1] = top;
sTexCoords[i*4 + 2] = right;
sTexCoords[i*4 + 3] = bottom;
// find font handle in our list of ready pages
index = m_FontPages.Find( font );
if ( index == m_FontPages.InvalidIndex() )
{
// not found, create the texture id and its materials
index = m_FontPages.Insert( font );
pPage = &m_FontPages.Element( index );
for (int type = 0; type < FONT_DRAW_TYPE_COUNT; ++type )
{
pPage->textureID[type] = g_MatSystemSurface.CreateNewTextureID( false );
}
CreateFontMaterials( *pPage, pWinFont->GetTexturePage(), true );
}
texCoords[i] = &(sTexCoords[ i*4 ]);
textureID[i] = m_FontPages.Element( index ).textureID[typePage];
}
}
else
{
struct newPageEntry_t
{
int page; // The font page a new character will go in
int drawX; // X location within the font page
int drawY; // Y location within the font page
};
// Determine how many characters need to have their texture generated
int numNewChars = 0;
int maxNewCharTexels = 0;
int totalNewCharTexels = 0;
newChar_t *newChars = (newChar_t *)_alloca( numChars*sizeof( newChar_t ) );
newPageEntry_t *newEntries = (newPageEntry_t *)_alloca( numChars*sizeof( newPageEntry_t ) );
font_t *winFont = FontManager().GetFontForChar( font, wch[0] );
if ( !winFont )
return false;
for ( int i = 0; i < numChars; i++ )
{
CacheEntry_t cacheItem;
cacheItem.font = font;
cacheItem.wch = wch[i];
HCacheEntry cacheHandle = m_CharCache.Find( cacheItem );
if ( ! m_CharCache.IsValidIndex( cacheHandle ) )
{
// All characters must come out of the same font
if ( winFont != FontManager().GetFontForChar( font, wch[i] ) )
return false;
// get the char details
int a, b, c;
winFont->GetCharABCWidths( wch[i], a, b, c );
int fontWide = max( b, 1 );
int fontTall = max( winFont->GetHeight(), 1 );
if ( winFont->GetUnderlined() )
{
fontWide += ( a + c );
}
// Get a texture to render into
int page, drawX, drawY, twide, ttall;
if ( !AllocatePageForChar( fontWide, fontTall, page, drawX, drawY, twide, ttall ) )
return false;
// accumulate data to pass to GetCharsRGBA below
newEntries[ numNewChars ].page = page;
newEntries[ numNewChars ].drawX = drawX;
newEntries[ numNewChars ].drawY = drawY;
newChars[ numNewChars ].wch = wch[i];
newChars[ numNewChars ].fontWide = fontWide;
newChars[ numNewChars ].fontTall = fontTall;
newChars[ numNewChars ].offset = 4*totalNewCharTexels;
totalNewCharTexels += fontWide*fontTall;
maxNewCharTexels = max( maxNewCharTexels, fontWide*fontTall );
numNewChars++;
// set the cache info
cacheItem.page = page;
// the 0.5 texel offset is done in CMatSystemTexture::SetMaterial() / CMatSystemSurface::StartDrawing()
double adjust = 0.0f;
cacheItem.texCoords[0] = (float)( (double)drawX / ((double)twide + adjust) );
cacheItem.texCoords[1] = (float)( (double)drawY / ((double)ttall + adjust) );
cacheItem.texCoords[2] = (float)( (double)(drawX + fontWide) / (double)twide );
cacheItem.texCoords[3] = (float)( (double)(drawY + fontTall) / (double)ttall );
m_CharCache.Insert(cacheItem);
cacheHandle = m_CharCache.Find( cacheItem );
Assert( m_CharCache.IsValidIndex( cacheHandle ) );
}
int page = m_CharCache[cacheHandle].page;
textureID[i] = m_PageList[page].textureID[typePage];
texCoords[i] = m_CharCache[cacheHandle].texCoords;
}
// Generate texture data for all newly-encountered characters
if ( numNewChars > 0 )
{
#ifdef _X360
if ( numNewChars > 1 )
{
MEM_ALLOC_CREDIT();
// Use the 360 fast path that generates multiple characters at once
int newCharDataSize = totalNewCharTexels*4;
CUtlBuffer newCharData( newCharDataSize, newCharDataSize, 0 );
unsigned char *pRGBA = (unsigned char *)newCharData.Base();
winFont->GetCharsRGBA( newChars, numNewChars, pRGBA );
// Copy the data into our font pages
for ( int i = 0; i < numNewChars; i++ )
{
newChar_t & newChar = newChars[i];
newPageEntry_t & newEntry = newEntries[i];
// upload the new sub texture
// NOTE: both textureIDs reference the same ITexture, so we're ok
g_MatSystemSurface.DrawSetTexture( m_PageList[newEntry.page].textureID[typePage] );
unsigned char *characterRGBA = pRGBA + newChar.offset;
g_MatSystemSurface.DrawSetSubTextureRGBA( m_PageList[newEntry.page].textureID[typePage], newEntry.drawX, newEntry.drawY, characterRGBA, newChar.fontWide, newChar.fontTall );
}
}
else
#endif
{
// create a buffer for new characters to be rendered into
int nByteCount = maxNewCharTexels * 4;
unsigned char *pRGBA = (unsigned char *)_alloca( nByteCount );
// Generate characters individually
for ( int i = 0; i < numNewChars; i++ )
{
newChar_t & newChar = newChars[i];
newPageEntry_t & newEntry = newEntries[i];
// render the character into the buffer
Q_memset( pRGBA, 0, nByteCount );
winFont->GetCharRGBA( newChar.wch, newChar.fontWide, newChar.fontTall, pRGBA );
if ( g_mat_texture_outline_fonts )
{
int width = newChar.fontWide;
int height = newChar.fontTall;
CPixelWriter pixelWriter;
pixelWriter.SetPixelMemory( IMAGE_FORMAT_RGBA8888, pRGBA, width * sizeof( BGRA8888_t ) );
for( int x = 0; x < width; x++ )
{
pixelWriter.Seek( x, 0 );
pixelWriter.WritePixel( 255, 0, 255, 255 );
pixelWriter.Seek( x, height - 1 );
pixelWriter.WritePixel( 255, 0, 255, 255 );
}
for( int y = 0; y < height; y++ )
{
if ( y < 4 || y > height - 4 )
{
pixelWriter.Seek( 0, y );
pixelWriter.WritePixel( 255, 0, 255, 255 );
pixelWriter.Seek( width - 1, y );
pixelWriter.WritePixel( 255, 0, 255, 255 );
}
}
}
// upload the new sub texture
// NOTE: both textureIDs reference the same ITexture, so we're ok)
g_MatSystemSurface.DrawSetTexture( m_PageList[newEntry.page].textureID[typePage] );
g_MatSystemSurface.DrawSetSubTextureRGBA( m_PageList[newEntry.page].textureID[typePage], newEntry.drawX, newEntry.drawY, pRGBA, newChar.fontWide, newChar.fontTall );
}
}
}
}
return true;
}
//-----------------------------------------------------------------------------
// Creates font materials
//-----------------------------------------------------------------------------
void CFontTextureCache::CreateFontMaterials( Page_t &page, ITexture *pFontTexture, bool bitmapFont )
{
// The normal material
KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" );
pVMTKeyValues->SetInt( "$vertexcolor", 1 );
pVMTKeyValues->SetInt( "$vertexalpha", 1 );
pVMTKeyValues->SetInt( "$ignorez", 1 );
pVMTKeyValues->SetInt( "$no_fullbright", 1 );
pVMTKeyValues->SetInt( "$translucent", 1 );
pVMTKeyValues->SetString( "$basetexture", pFontTexture->GetName() );
IMaterial *pMaterial = g_pMaterialSystem->CreateMaterial( "__fontpage", pVMTKeyValues );
pMaterial->Refresh();
int typePageNonAdditive = (int)vgui::FONT_DRAW_NONADDITIVE-1;
g_MatSystemSurface.DrawSetTextureMaterial( page.textureID[typePageNonAdditive], pMaterial );
pMaterial->DecrementReferenceCount();
// The additive material
pVMTKeyValues = new KeyValues( "UnlitGeneric" );
pVMTKeyValues->SetInt( "$vertexcolor", 1 );
pVMTKeyValues->SetInt( "$vertexalpha", 1 );
pVMTKeyValues->SetInt( "$ignorez", 1 );
pVMTKeyValues->SetInt( "$no_fullbright", 1 );
pVMTKeyValues->SetInt( "$translucent", 1 );
pVMTKeyValues->SetInt( "$additive", 1 );
pVMTKeyValues->SetString( "$basetexture", pFontTexture->GetName() );
pMaterial = g_pMaterialSystem->CreateMaterial( "__fontpage_additive", pVMTKeyValues );
pMaterial->Refresh();
int typePageAdditive = (int)vgui::FONT_DRAW_ADDITIVE-1;
if ( bitmapFont )
{
g_MatSystemSurface.DrawSetTextureMaterial( page.textureID[typePageAdditive], pMaterial );
}
else
{
g_MatSystemSurface.ReferenceProceduralMaterial( page.textureID[typePageAdditive], page.textureID[typePageNonAdditive], pMaterial );
}
pMaterial->DecrementReferenceCount();
}
//-----------------------------------------------------------------------------
// Computes the page size given a character height
//-----------------------------------------------------------------------------
int CFontTextureCache::ComputePageType( int charTall ) const
{
for (int i = 0; i < FONT_PAGE_SIZE_COUNT; ++i)
{
if ( charTall < s_pFontPageSize[i] )
return i;
}
return -1;
}
//-----------------------------------------------------------------------------
// Purpose: allocates a new page for a given character
//-----------------------------------------------------------------------------
bool CFontTextureCache::AllocatePageForChar(int charWide, int charTall, int &pageIndex, int &drawX, int &drawY, int &twide, int &ttall)
{
// see if there is room in the last page for this character
int nPageType = ComputePageType( charTall );
if ( nPageType < 0 )
{
Assert( !"Font is too tall for texture cache of glyphs\n" );
return false;
}
pageIndex = m_pCurrPage[nPageType];
int nNextX = 0;
bool bNeedsNewPage = true;
if ( pageIndex > -1 )
{
Page_t &page = m_PageList[ pageIndex ];
nNextX = page.nextX + charWide;
// make sure we have room on the current line of the texture page
if ( nNextX > page.wide )
{
// move down a line
page.nextX = 0;
nNextX = charWide;
page.nextY += page.tallestCharOnLine;
page.tallestCharOnLine = charTall;
}
page.tallestCharOnLine = max( page.tallestCharOnLine, (short)charTall );
bNeedsNewPage = ((page.nextY + page.tallestCharOnLine) > page.tall);
}
if ( bNeedsNewPage )
{
// allocate a new page
pageIndex = m_PageList.AddToTail();
Page_t &newPage = m_PageList[pageIndex];
m_pCurrPage[nPageType] = pageIndex;
for (int i = 0; i < FONT_DRAW_TYPE_COUNT; ++i )
{
newPage.textureID[i] = g_MatSystemSurface.CreateNewTextureID( true );
}
newPage.maxFontHeight = s_pFontPageSize[nPageType];
newPage.wide = TEXTURE_PAGE_WIDTH;
newPage.tall = TEXTURE_PAGE_HEIGHT;
newPage.nextX = 0;
newPage.nextY = 0;
newPage.tallestCharOnLine = charTall;
nNextX = charWide;
static int nFontPageId = 0;
char pTextureName[64];
Q_snprintf( pTextureName, 64, "__font_page_%d", nFontPageId );
++nFontPageId;
MEM_ALLOC_CREDIT();
ITexture *pTexture = g_pMaterialSystem->CreateProceduralTexture(
pTextureName,
TEXTURE_GROUP_VGUI,
newPage.wide,
newPage.tall,
IMAGE_FORMAT_RGBA8888,
TEXTUREFLAGS_POINTSAMPLE | TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT |
TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_NOLOD | TEXTUREFLAGS_PROCEDURAL | TEXTUREFLAGS_SINGLECOPY );
CreateFontMaterials( newPage, pTexture );
pTexture->DecrementReferenceCount();
if ( IsPC() || !IsDebug() )
{
// clear the texture from the inital checkerboard to black
// allocate for 32bpp format
int nByteCount = TEXTURE_PAGE_WIDTH * TEXTURE_PAGE_HEIGHT * 4;
unsigned char *pRGBA = (unsigned char *)_alloca( nByteCount );
Q_memset( pRGBA, 0, nByteCount );
int typePageNonAdditive = (int)(vgui::FONT_DRAW_NONADDITIVE)-1;
g_MatSystemSurface.DrawSetTextureRGBA( newPage.textureID[typePageNonAdditive], pRGBA, newPage.wide, newPage.tall, false, false );
}
}
// output the position
Page_t &page = m_PageList[ pageIndex ];
drawX = page.nextX;
drawY = page.nextY;
twide = page.wide;
ttall = page.tall;
// Update the next position to draw in
page.nextX = nNextX + 1;
return true;
}

View File

@ -0,0 +1,102 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef FONTTEXTURECACHE_H
#define FONTTEXTURECACHE_H
#ifdef _WIN32
#pragma once
#endif
#include "vgui_surfacelib/FontManager.h"
#include "utlrbtree.h"
#include <vgui/ISurface.h>
#include "utlmap.h"
class ITexture;
//-----------------------------------------------------------------------------
// Purpose: manages texture memory for unicode fonts in vgui
//-----------------------------------------------------------------------------
class CFontTextureCache
{
public:
CFontTextureCache();
~CFontTextureCache();
// returns a texture ID and a pointer to an array of 4 texture coords for the given character & font
// generates+uploads more texture if necessary
bool GetTextureForChar( vgui::HFont font, vgui::FontDrawType_t type, wchar_t wch, int *textureID, float **texCoords );
// for each character in an array (not assumed to be a NULL-terminated string), returns a
// texture ID and a pointer to an array of 4 texture coords for the given character & font
// generates+uploads more texture if necessary
bool GetTextureForChars( vgui::HFont font, vgui::FontDrawType_t type, const wchar_t *wch, int *textureID, float **texCoords, int numChars = 1 );
// clears the cache
void Clear();
private:
// NOTE: If you change this, change s_pFontPageSize
enum
{
FONT_PAGE_SIZE_16,
FONT_PAGE_SIZE_32,
FONT_PAGE_SIZE_64,
FONT_PAGE_SIZE_128,
FONT_PAGE_SIZE_256,
FONT_PAGE_SIZE_COUNT,
};
// a single character in the cache
typedef unsigned short HCacheEntry;
struct CacheEntry_t
{
vgui::HFont font;
wchar_t wch;
unsigned char page;
float texCoords[4];
// doubly-linked list for use in the LRU
HCacheEntry nextEntry;
HCacheEntry prevEntry;
};
// a single texture page
struct Page_t
{
short textureID[vgui::FONT_DRAW_TYPE_COUNT];
short maxFontHeight;
short tallestCharOnLine;
short wide, tall; // total size of the page
short nextX, nextY; // position to draw any new character positions
};
// allocates a new page for a given character
bool AllocatePageForChar(int charWide, int charTall, int &pageIndex, int &drawX, int &drawY, int &twide, int &ttall);
// Creates font materials
void CreateFontMaterials( Page_t &page, ITexture *pFontTexture, bool bitmapFont = false );
// Computes the page size given a character height
int ComputePageType( int charTall ) const;
static bool CacheEntryLessFunc(const CacheEntry_t &lhs, const CacheEntry_t &rhs);
CUtlRBTree<CacheEntry_t, HCacheEntry> m_CharCache;
// cache
typedef CUtlVector<Page_t> FontPageList_t;
FontPageList_t m_PageList;
int m_pCurrPage[FONT_PAGE_SIZE_COUNT];
HCacheEntry m_LRUListHeadIndex;
static int s_pFontPageSize[FONT_PAGE_SIZE_COUNT];
CUtlMap< vgui::HFont, Page_t > m_FontPages;
};
#endif // FONTTEXTURECACHE_H

524
vguimatsurface/Input.cpp Normal file
View File

@ -0,0 +1,524 @@
//========= 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>
#include <zmouse.h>
#endif
#include "inputsystem/iinputsystem.h"
#include "tier2/tier2.h"
#include "Input.h"
#include "vguimatsurface.h"
#include "../vgui2/src/VPanel.h"
#include <vgui/KeyCode.h>
#include <vgui/MouseCode.h>
#include <vgui/IVGui.h>
#include <vgui/IPanel.h>
#include <vgui/ISurface.h>
#include <vgui/IClientPanel.h>
#include "inputsystem/ButtonCode.h"
#include "Cursor.h"
#include "tier0/dbg.h"
#include "../vgui2/src/vgui_key_translation.h"
#include <vgui/IInputInternal.h>
#include "tier0/icommandline.h"
#ifdef _X360
#include "xbox/xbox_win32stubs.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
using namespace vgui;
//-----------------------------------------------------------------------------
// Vgui input events
//-----------------------------------------------------------------------------
enum VguiInputEventType_t
{
IE_Close = IE_FirstVguiEvent,
IE_LocateMouseClick,
IE_SetCursor,
IE_KeyTyped,
IE_KeyCodeTyped,
IE_InputLanguageChanged,
IE_IMESetWindow,
IE_IMEStartComposition,
IE_IMEComposition,
IE_IMEEndComposition,
IE_IMEShowCandidates,
IE_IMEChangeCandidates,
IE_IMECloseCandidates,
IE_IMERecomputeModes,
};
void InitInput()
{
EnableInput( true );
}
static bool s_bInputEnabled = true;
#ifdef WIN32
//-----------------------------------------------------------------------------
// Translates actual keys into VGUI ids
//-----------------------------------------------------------------------------
static WNDPROC s_ChainedWindowProc = NULL;
extern HWND thisWindow;
//-----------------------------------------------------------------------------
// Initializes the input system
//-----------------------------------------------------------------------------
static bool s_bIMEComposing = false;
static HWND s_hLastHWnd = 0;
//-----------------------------------------------------------------------------
// Handles input messages
//-----------------------------------------------------------------------------
static LRESULT CALLBACK MatSurfaceWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
if ( !s_bInputEnabled )
goto chainWndProc;
InputEvent_t event;
memset( &event, 0, sizeof(event) );
event.m_nTick = g_pInputSystem->GetPollTick();
if ( hwnd != s_hLastHWnd )
{
s_hLastHWnd = hwnd;
event.m_nType = IE_IMESetWindow;
event.m_nData = (int)s_hLastHWnd;
g_pInputSystem->PostUserEvent( event );
}
switch(uMsg)
{
case WM_QUIT:
// According to windows docs, WM_QUIT should never be passed to wndprocs
Assert( 0 );
break;
case WM_CLOSE:
// Handle close messages
{
LONG_PTR wndProc = GetWindowLongPtrW( hwnd, GWLP_WNDPROC );
if ( wndProc == (LONG_PTR)MatSurfaceWindowProc )
{
event.m_nType = IE_Close;
g_pInputSystem->PostUserEvent( event );
}
}
return 0;
// All mouse messages need to mark where the click occurred before chaining down
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN:
case MS_WM_XBUTTONDOWN:
case WM_LBUTTONUP:
case WM_RBUTTONUP:
case WM_MBUTTONUP:
case MS_WM_XBUTTONUP:
case WM_LBUTTONDBLCLK:
case WM_RBUTTONDBLCLK:
case WM_MBUTTONDBLCLK:
case MS_WM_XBUTTONDBLCLK:
event.m_nType = IE_LocateMouseClick;
event.m_nData = (short)LOWORD(lParam);
event.m_nData2 = (short)HIWORD(lParam);
g_pInputSystem->PostUserEvent( event );
break;
case WM_SETCURSOR:
event.m_nType = IE_SetCursor;
g_pInputSystem->PostUserEvent( event );
break;
case WM_XCONTROLLER_KEY:
if ( IsX360() )
{
// First have to insert the edge case event
int nRetVal = 0;
if ( s_ChainedWindowProc )
{
nRetVal = CallWindowProcW( s_ChainedWindowProc, hwnd, uMsg, wParam, lParam );
}
// xboxissue - as yet HL2 input hasn't been made aware of analog inputs or ports
// so just digital step on the sample range
int sample = LOWORD( lParam );
if ( sample )
{
event.m_nType = IE_KeyCodeTyped;
event.m_nData = (vgui::KeyCode)wParam;
g_pInputSystem->PostUserEvent( event );
}
}
break;
// Need to deal with key repeat for keydown since inputsystem doesn't
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
{
// First have to insert the edge case event
int nRetVal = 0;
if ( s_ChainedWindowProc )
{
nRetVal = CallWindowProcW( s_ChainedWindowProc, hwnd, uMsg, wParam, lParam );
}
int nKeyRepeat = LOWORD( lParam );
for ( int i = 0; i < nKeyRepeat; ++i )
{
event.m_nType = IE_KeyCodeTyped;
event.m_nData = KeyCode_VirtualKeyToVGUI( wParam );
g_pInputSystem->PostUserEvent( event );
}
return nRetVal;
}
case WM_SYSCHAR:
case WM_CHAR:
if ( !s_bIMEComposing )
{
event.m_nType = IE_KeyTyped;
event.m_nData = (int)wParam;
g_pInputSystem->PostUserEvent( event );
}
break;
case WM_INPUTLANGCHANGE:
event.m_nType = IE_InputLanguageChanged;
g_pInputSystem->PostUserEvent( event );
break;
case WM_IME_STARTCOMPOSITION:
s_bIMEComposing = true;
event.m_nType = IE_IMEStartComposition;
g_pInputSystem->PostUserEvent( event );
return TRUE;
case WM_IME_COMPOSITION:
event.m_nType = IE_IMEComposition;
event.m_nData = (int)lParam;
g_pInputSystem->PostUserEvent( event );
return TRUE;
case WM_IME_ENDCOMPOSITION:
s_bIMEComposing = false;
event.m_nType = IE_IMEEndComposition;
g_pInputSystem->PostUserEvent( event );
return TRUE;
case WM_IME_NOTIFY:
{
switch (wParam)
{
default:
break;
case 14: // Chinese Traditional IMN_PRIVATE...
break;
case IMN_OPENCANDIDATE:
event.m_nType = IE_IMEShowCandidates;
g_pInputSystem->PostUserEvent( event );
return 1;
case IMN_CHANGECANDIDATE:
event.m_nType = IE_IMEChangeCandidates;
g_pInputSystem->PostUserEvent( event );
return 0;
case IMN_CLOSECANDIDATE:
event.m_nType = IE_IMECloseCandidates;
g_pInputSystem->PostUserEvent( event );
break;
// To detect the change of IME mode, or the toggling of Japanese IME
case IMN_SETCONVERSIONMODE:
case IMN_SETSENTENCEMODE:
case IMN_SETOPENSTATUS:
event.m_nType = IE_IMERecomputeModes;
g_pInputSystem->PostUserEvent( event );
if ( wParam == IMN_SETOPENSTATUS )
return 0;
break;
case IMN_CLOSESTATUSWINDOW:
case IMN_GUIDELINE:
case IMN_OPENSTATUSWINDOW:
case IMN_SETCANDIDATEPOS:
case IMN_SETCOMPOSITIONFONT:
case IMN_SETCOMPOSITIONWINDOW:
case IMN_SETSTATUSWINDOWPOS:
break;
}
}
case WM_IME_SETCONTEXT:
// We draw all IME windows ourselves
lParam &= ~ISC_SHOWUICOMPOSITIONWINDOW;
lParam &= ~ISC_SHOWUIGUIDELINE;
lParam &= ~ISC_SHOWUIALLCANDIDATEWINDOW;
break;
case WM_IME_CHAR:
// We need to process this message so that the IME doesn't double convert the unicode IME characters into garbage characters and post
// them to our window... (get ? marks after text entry ).
return 0;
}
chainWndProc:
if ( s_ChainedWindowProc )
return CallWindowProcW( s_ChainedWindowProc, hwnd, uMsg, wParam, lParam );
// This means the application is driving the messages (calling our window procedure manually)
// rather than us hooking their window procedure. The engine needs to do this in order for VCR
// mode to play back properly.
return 0;
}
#endif
//-----------------------------------------------------------------------------
// Enables/disables input (enabled by default)
//-----------------------------------------------------------------------------
void EnableInput( bool bEnable )
{
#if 0 // #ifdef BENCHMARK
s_bInputEnabled = false;
#else
s_bInputEnabled = bEnable;
#endif
}
#ifdef WIN32
//-----------------------------------------------------------------------------
// Hooks input listening up to a window
//-----------------------------------------------------------------------------
void InputAttachToWindow(void *hwnd)
{
#if !defined( USE_SDL )
s_ChainedWindowProc = (WNDPROC)GetWindowLongPtrW( (HWND)hwnd, GWLP_WNDPROC );
SetWindowLongPtrW( (HWND)hwnd, GWLP_WNDPROC, (LONG_PTR)MatSurfaceWindowProc );
#endif
}
void InputDetachFromWindow(void *hwnd)
{
if (!hwnd)
return;
if ( s_ChainedWindowProc )
{
SetWindowLongPtrW( (HWND)hwnd, GWLP_WNDPROC, (LONG_PTR) s_ChainedWindowProc );
s_ChainedWindowProc = NULL;
}
}
#else
void InputAttachToWindow(void *hwnd)
{
#if !defined( OSX ) && !defined( LINUX )
if ( hwnd && !HushAsserts() )
{
// under OSX we use the Cocoa mgr to route events rather than hooking winprocs
// and under Linux we use SDL
Assert( !"Implement me" );
}
#endif
}
void InputDetachFromWindow(void *hwnd)
{
#if !defined( OSX ) && !defined( LINUX )
if ( hwnd && !HushAsserts() )
{
// under OSX we use the Cocoa mgr to route events rather than hooking winprocs
// and under Linux we use SDL
Assert( !"Implement me" );
}
#endif
}
#endif
//-----------------------------------------------------------------------------
// Converts an input system button code to a vgui key code
// FIXME: Remove notion of vgui::KeyCode + vgui::MouseCode altogether
//-----------------------------------------------------------------------------
static vgui::KeyCode ButtonCodeToKeyCode( ButtonCode_t buttonCode )
{
return ( vgui::KeyCode )buttonCode;
}
static vgui::MouseCode ButtonCodeToMouseCode( ButtonCode_t buttonCode )
{
return ( vgui::MouseCode )buttonCode;
}
//-----------------------------------------------------------------------------
// Handles an input event, returns true if the event should be filtered
// from the rest of the game
//-----------------------------------------------------------------------------
bool InputHandleInputEvent( const InputEvent_t &event )
{
switch( event.m_nType )
{
case IE_ButtonPressed:
{
// NOTE: data2 is the virtual key code (data1 contains the scan-code one)
ButtonCode_t code = (ButtonCode_t)event.m_nData2;
if ( IsKeyCode( code ) || IsJoystickCode( code ) )
{
vgui::KeyCode keyCode = ButtonCodeToKeyCode( code );
return g_pIInput->InternalKeyCodePressed( keyCode );
}
if ( IsJoystickCode( code ) )
{
vgui::KeyCode keyCode = ButtonCodeToKeyCode( code );
return g_pIInput->InternalKeyCodePressed( keyCode );
}
if ( IsMouseCode( code ) )
{
vgui::MouseCode mouseCode = ButtonCodeToMouseCode( code );
return g_pIInput->InternalMousePressed( mouseCode );
}
}
break;
case IE_ButtonReleased:
{
// NOTE: data2 is the virtual key code (data1 contains the scan-code one)
ButtonCode_t code = (ButtonCode_t)event.m_nData2;
if ( IsKeyCode( code ) || IsJoystickCode( code ) )
{
vgui::KeyCode keyCode = ButtonCodeToKeyCode( code );
return g_pIInput->InternalKeyCodeReleased( keyCode );
}
if ( IsJoystickCode( code ) )
{
vgui::KeyCode keyCode = ButtonCodeToKeyCode( code );
return g_pIInput->InternalKeyCodeReleased( keyCode );
}
if ( IsMouseCode( code ) )
{
vgui::MouseCode mouseCode = ButtonCodeToMouseCode( code );
return g_pIInput->InternalMouseReleased( mouseCode );
}
}
break;
case IE_ButtonDoubleClicked:
{
// NOTE: data2 is the virtual key code (data1 contains the scan-code one)
ButtonCode_t code = (ButtonCode_t)event.m_nData2;
if ( IsMouseCode( code ) )
{
vgui::MouseCode mouseCode = ButtonCodeToMouseCode( code );
return g_pIInput->InternalMouseDoublePressed( mouseCode );
}
}
break;
case IE_AnalogValueChanged:
{
if ( event.m_nData == MOUSE_WHEEL )
return g_pIInput->InternalMouseWheeled( event.m_nData3 );
if ( event.m_nData == MOUSE_XY )
return g_pIInput->InternalCursorMoved( event.m_nData2, event.m_nData3 );
}
break;
case IE_KeyCodeTyped:
{
vgui::KeyCode code = (vgui::KeyCode)event.m_nData;
g_pIInput->InternalKeyCodeTyped( code );
}
return true;
case IE_KeyTyped:
{
vgui::KeyCode code = (vgui::KeyCode)event.m_nData;
g_pIInput->InternalKeyTyped( code );
}
return true;
case IE_Quit:
g_pVGui->Stop();
#if defined( USE_SDL )
return false; // also let higher layers consume it
#else
return true;
#endif
case IE_Close:
// FIXME: Change this so we don't stop until 'save' occurs, etc.
g_pVGui->Stop();
return true;
case IE_SetCursor:
ActivateCurrentCursor();
return true;
case IE_IMESetWindow:
g_pIInput->SetIMEWindow( (void *)event.m_nData );
return true;
case IE_LocateMouseClick:
g_pIInput->InternalCursorMoved( event.m_nData, event.m_nData2 );
return true;
case IE_InputLanguageChanged:
g_pIInput->OnInputLanguageChanged();
return true;
case IE_IMEStartComposition:
g_pIInput->OnIMEStartComposition();
return true;
case IE_IMEComposition:
g_pIInput->OnIMEComposition( event.m_nData );
return true;
case IE_IMEEndComposition:
g_pIInput->OnIMEEndComposition();
return true;
case IE_IMEShowCandidates:
g_pIInput->OnIMEShowCandidates();
return true;
case IE_IMEChangeCandidates:
g_pIInput->OnIMEChangeCandidates();
return true;
case IE_IMECloseCandidates:
g_pIInput->OnIMECloseCandidates();
return true;
case IE_IMERecomputeModes:
g_pIInput->OnIMERecomputeModes();
return true;
}
return false;
}

47
vguimatsurface/Input.h Normal file
View File

@ -0,0 +1,47 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Methods related to input
//
// $Revision: $
// $NoKeywords: $
//===========================================================================//
#ifndef INPUT_H
#define INPUT_H
#ifdef _WIN32
#pragma once
#endif
struct InputEvent_t;
//-----------------------------------------------------------------------------
// Initializes the input system
//-----------------------------------------------------------------------------
void InitInput();
//-----------------------------------------------------------------------------
// Hooks input listening up to a window
//-----------------------------------------------------------------------------
void InputAttachToWindow(void *hwnd);
void InputDetachFromWindow(void *hwnd);
// If input isn't hooked, this forwards messages to vgui.
void InputHandleWindowMessage( void *hwnd, unsigned int uMsg, unsigned int wParam, long lParam );
//-----------------------------------------------------------------------------
// Handles an input event, returns true if the event should be filtered
// from the rest of the game
//-----------------------------------------------------------------------------
bool InputHandleInputEvent( const InputEvent_t &event );
//-----------------------------------------------------------------------------
// Enables/disables input (enabled by default)
//-----------------------------------------------------------------------------
void EnableInput( bool bEnable );
#endif // INPUT_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,643 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//===========================================================================//
#ifndef MATSYSTEMSURFACE_H
#define MATSYSTEMSURFACE_H
#ifdef _WIN32
#pragma once
#endif
#include <vgui/VGUI.h>
#include <vgui/ISurface.h>
#include <vgui/IPanel.h>
#include <vgui/IClientPanel.h>
#include <vgui_controls/Panel.h>
#include <vgui/IInput.h>
#include <vgui_controls/Controls.h>
#include <vgui/Point.h>
#include "materialsystem/imaterialsystem.h"
#include "VGuiMatSurface/IMatSystemSurface.h"
#include "materialsystem/imesh.h"
#include "materialsystem/imaterial.h"
#include "utlvector.h"
#include "utlsymbol.h"
#include "materialsystem/MaterialSystemUtil.h"
#include "tier1/utldict.h"
#include "tier3/tier3.h"
using namespace vgui;
class IImage;
extern class IMaterialSystem *g_pMaterialSystem;
//-----------------------------------------------------------------------------
// The default material system embedded panel
//-----------------------------------------------------------------------------
class CMatEmbeddedPanel : public vgui::Panel
{
typedef vgui::Panel BaseClass;
public:
CMatEmbeddedPanel();
virtual void OnThink();
VPANEL IsWithinTraverse(int x, int y, bool traversePopups);
};
//-----------------------------------------------------------------------------
//
// Implementation of the VGUI surface on top of the material system
//
//-----------------------------------------------------------------------------
class CMatSystemSurface : public CTier3AppSystem< IMatSystemSurface >
{
typedef CTier3AppSystem< IMatSystemSurface > BaseClass;
public:
CMatSystemSurface();
virtual ~CMatSystemSurface();
// Methods of IAppSystem
virtual bool Connect( CreateInterfaceFn factory );
virtual void Disconnect();
virtual void *QueryInterface( const char *pInterfaceName );
virtual InitReturnVal_t Init();
virtual void Shutdown();
// initialization
virtual void SetEmbeddedPanel(vgui::VPANEL pEmbeddedPanel);
// returns true if a panel is minimzed
bool IsMinimized(vgui::VPANEL panel);
// Sets the only panel to draw. Set to NULL to clear.
void RestrictPaintToSinglePanel(vgui::VPANEL panel);
// frame
virtual void RunFrame();
// implementation of vgui::ISurface
virtual vgui::VPANEL GetEmbeddedPanel();
// drawing context
virtual void PushMakeCurrent(vgui::VPANEL panel,bool useInSets);
virtual void PopMakeCurrent(vgui::VPANEL panel);
// rendering functions
virtual void DrawSetColor(int r,int g,int b,int a);
virtual void DrawSetColor(Color col);
virtual void DrawLine( int x0, int y0, int x1, int y1 );
virtual void DrawTexturedLine( const vgui::Vertex_t &a, const vgui::Vertex_t &b );
virtual void DrawPolyLine(int *px, int *py, int numPoints);
virtual void DrawTexturedPolyLine( const vgui::Vertex_t *p, int n );
virtual void DrawFilledRect(int x0, int y0, int x1, int y1);
virtual void DrawFilledRectArray( IntRect *pRects, int numRects );
virtual void DrawFilledRectFastFade( int x0, int y0, int x1, int y1, int fadeStartPt, int fadeEndPt, unsigned int alpha0, unsigned int alpha1, bool bHorizontal );
virtual void DrawFilledRectFade( int x0, int y0, int x1, int y1, unsigned int alpha0, unsigned int alpha1, bool bHorizontal );
virtual void DrawOutlinedRect(int x0, int y0, int x1, int y1);
virtual void DrawOutlinedCircle(int x, int y, int radius, int segments);
// textured rendering functions
virtual int CreateNewTextureID( bool procedural = false );
virtual bool IsTextureIDValid(int id);
virtual bool DrawGetTextureFile(int id, char *filename, int maxlen );
virtual int DrawGetTextureId( char const *filename );
virtual int DrawGetTextureId( ITexture *pTexture );
virtual void DrawSetTextureFile(int id, const char *filename, int hardwareFilter, bool forceReload);
virtual void DrawSetTexture(int id);
virtual void DrawGetTextureSize(int id, int &wide, int &tall);
virtual bool DeleteTextureByID(int id);
virtual IVguiMatInfo *DrawGetTextureMatInfoFactory(int id);
virtual void DrawSetTextureRGBA(int id, const unsigned char *rgba, int wide, int tall, int hardwareFilter, bool forceReload);
virtual void DrawTexturedRect(int x0, int y0, int x1, int y1);
virtual void DrawTexturedSubRect( int x0, int y0, int x1, int y1, float texs0, float text0, float texs1, float text1 );
virtual void DrawTexturedPolygon(int n, vgui::Vertex_t *pVertices, bool bClipVertices = true );
virtual void DrawPrintText(const wchar_t *text, int textLen, FontDrawType_t drawType = FONT_DRAW_DEFAULT);
virtual void DrawUnicodeChar(wchar_t wch, FontDrawType_t drawType = FONT_DRAW_DEFAULT );
virtual void DrawUnicodeString( const wchar_t *pwString, FontDrawType_t drawType = FONT_DRAW_DEFAULT );
virtual void DrawSetTextFont(vgui::HFont font);
virtual void DrawFlushText();
virtual void DrawSetTextColor(int r, int g, int b, int a);
virtual void DrawSetTextColor(Color col);
virtual void DrawSetTextScale(float sx, float sy);
virtual void DrawSetTextPos(int x, int y);
virtual void DrawGetTextPos(int& x,int& y);
virtual vgui::IHTML *CreateHTMLWindow(vgui::IHTMLEvents *events,vgui::VPANEL context);
virtual void PaintHTMLWindow(vgui::IHTML *htmlwin);
virtual void DeleteHTMLWindow(vgui::IHTML *htmlwin);
virtual bool BHTMLWindowNeedsPaint(IHTML *htmlwin);
virtual void GetScreenSize(int &wide, int &tall);
virtual void SetAsTopMost(vgui::VPANEL panel, bool state);
virtual void BringToFront(vgui::VPANEL panel);
virtual void SetForegroundWindow (vgui::VPANEL panel);
virtual void SetPanelVisible(vgui::VPANEL panel, bool state);
virtual void SetMinimized(vgui::VPANEL panel, bool state);
virtual void FlashWindow(vgui::VPANEL panel, bool state);
virtual void SetTitle(vgui::VPANEL panel, const wchar_t *title);
virtual const wchar_t *GetTitle( vgui::VPANEL panel );
virtual void SetAsToolBar(vgui::VPANEL panel, bool state); // removes the window's task bar entry (for context menu's, etc.)
// windows stuff
virtual void CreatePopup(VPANEL panel, bool minimized, bool showTaskbarIcon = true, bool disabled = false, bool mouseInput = true , bool kbInput = true);
virtual void SwapBuffers(vgui::VPANEL panel);
virtual void Invalidate(vgui::VPANEL panel);
virtual void SetCursor(vgui::HCursor cursor);
virtual bool IsCursorVisible();
virtual void SetCursorAlwaysVisible(bool visible);
virtual void ApplyChanges();
virtual bool IsWithin(int x, int y);
virtual bool HasFocus();
virtual bool SupportsFeature(SurfaceFeature_e feature);
// engine-only focus handling (replacing WM_FOCUS windows handling)
virtual void SetTopLevelFocus(vgui::VPANEL panel);
// fonts
virtual vgui::HFont CreateFont();
virtual bool SetFontGlyphSet(vgui::HFont font, const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags, int nRangeMin = 0, int nRangeMax = 0);
virtual bool SetBitmapFontGlyphSet(vgui::HFont font, const char *windowsFontName, float scalex, float scaley, int flags);
virtual int GetFontTall(HFont font);
virtual int GetFontTallRequested(HFont font);
virtual int GetFontAscent(HFont font, wchar_t wch);
virtual bool IsFontAdditive(HFont font);
virtual void GetCharABCwide(HFont font, int ch, int &a, int &b, int &c);
virtual void GetTextSize(HFont font, const wchar_t *text, int &wide, int &tall);
virtual int GetCharacterWidth(vgui::HFont font, int ch);
virtual bool AddCustomFontFile(const char *fontName, const char *fontFileName);
virtual bool AddBitmapFontFile(const char *fontFileName);
virtual void SetBitmapFontName( const char *pName, const char *pFontFilename );
virtual const char *GetBitmapFontName( const char *pName );
virtual void PrecacheFontCharacters(HFont font, const wchar_t *pCharacters);
virtual void ClearTemporaryFontCache( void );
virtual const char *GetFontName( HFont font );
virtual const char *GetFontFamilyName( HFont font );
// GameUI-only accessed functions
// uploads a part of a texture, used for font rendering
void DrawSetSubTextureRGBA(int textureID, int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall);
void DrawUpdateRegionTextureRGBA( int nTextureID, int x, int y, const unsigned char *pchData, int wide, int tall, ImageFormat imageFormat );
// notify icons?!?
virtual vgui::VPANEL GetNotifyPanel();
virtual void SetNotifyIcon(vgui::VPANEL context, vgui::HTexture icon, vgui::VPANEL panelToReceiveMessages, const char *text);
// plays a sound
virtual void PlaySound(const char *fileName);
//!! these functions Should not be accessed directly, but only through other vgui items
//!! need to move these to seperate interface
virtual int GetPopupCount();
virtual vgui::VPANEL GetPopup( int index );
virtual bool ShouldPaintChildPanel(vgui::VPANEL childPanel);
virtual bool RecreateContext(vgui::VPANEL panel);
virtual void AddPanel(vgui::VPANEL panel);
virtual void ReleasePanel(vgui::VPANEL panel);
virtual void MovePopupToFront(vgui::VPANEL panel);
virtual void SolveTraverse(vgui::VPANEL panel, bool forceApplySchemeSettings);
virtual void PaintTraverse(vgui::VPANEL panel);
virtual void EnableMouseCapture(vgui::VPANEL panel, bool state);
virtual void SetWorkspaceInsets( int left, int top, int right, int bottom );
virtual void GetWorkspaceBounds(int &x, int &y, int &wide, int &tall);
// Hook needed to Get input to work
virtual void AttachToWindow( void *hwnd, bool bLetAppDriveInput );
virtual bool HandleInputEvent( const InputEvent_t &event );
void InitFullScreenBuffer( const char *pszRenderTargetName );
virtual void Set3DPaintTempRenderTarget( const char *pRenderTargetName );
virtual void Reset3DPaintTempRenderTarget( void );
// Begins, ends 3D painting
virtual void Begin3DPaint( int iLeft, int iTop, int iRight, int iBottom, bool bRenderToTexture = true );
virtual void End3DPaint();
virtual void BeginSkinCompositionPainting() OVERRIDE;
virtual void EndSkinCompositionPainting() OVERRIDE;
// Disable clipping during rendering
virtual void DisableClipping( bool bDisable ) OVERRIDE;
virtual void GetClippingRect( int &left, int &top, int &right, int &bottom, bool &bClippingDisabled ) OVERRIDE;
virtual void SetClippingRect( int left, int top, int right, int bottom ) OVERRIDE;
// Prevents vgui from changing the cursor
virtual bool IsCursorLocked() const;
// Sets the mouse Get + Set callbacks
virtual void SetMouseCallbacks( GetMouseCallback_t GetFunc, SetMouseCallback_t SetFunc );
// Tells the surface to ignore windows messages
virtual void EnableWindowsMessages( bool bEnable );
// Installs a function to play sounds
virtual void InstallPlaySoundFunc( PlaySoundFunc_t soundFunc );
// Some drawing methods that cannot be accomplished under Win32
virtual void DrawColoredCircle( int centerx, int centery, float radius, int r, int g, int b, int a );
virtual int DrawColoredText( vgui::HFont font, int x, int y, int r, int g, int b, int a, PRINTF_FORMAT_STRING const char *fmt, ... );
virtual void DrawColoredTextRect( vgui::HFont font, int x, int y, int w, int h, int r, int g, int b, int a, PRINTF_FORMAT_STRING const char *fmt, ... );
virtual void DrawTextHeight( vgui::HFont font, int w, int& h, PRINTF_FORMAT_STRING const char *fmt, ... );
// Returns the length in pixels of the text
virtual int DrawTextLen( vgui::HFont font, PRINTF_FORMAT_STRING const char *fmt, ... );
// Draws a panel in 3D space.
virtual void DrawPanelIn3DSpace( vgui::VPANEL pRootPanel, const VMatrix &panelCenterToWorld, int pw, int ph, float sw, float sh );
// Only visible within vguimatsurface
void DrawSetTextureMaterial(int id, IMaterial *pMaterial);
void ReferenceProceduralMaterial( int id, int referenceId, IMaterial *pMaterial );
// new stuff for Alfreds VGUI2 port!!
virtual bool InEngine() { return true; }
void GetProportionalBase( int &width, int &height ) { width = BASE_WIDTH; height = BASE_HEIGHT; }
virtual bool HasCursorPosFunctions() { return true; }
virtual void SetModalPanel(VPANEL );
virtual VPANEL GetModalPanel();
virtual void UnlockCursor();
virtual void LockCursor();
virtual void SetTranslateExtendedKeys(bool state);
virtual VPANEL GetTopmostPopup();
virtual void GetAbsoluteWindowBounds(int &x, int &y, int &wide, int &tall);
virtual void CalculateMouseVisible();
virtual bool NeedKBInput();
virtual void SurfaceGetCursorPos(int &x, int &y);
virtual void SurfaceSetCursorPos(int x, int y);
virtual void MovePopupToBack(VPANEL panel);
virtual bool IsInThink( VPANEL panel);
virtual bool DrawGetUnicodeCharRenderInfo( wchar_t ch, CharRenderInfo& info );
virtual void DrawRenderCharFromInfo( const CharRenderInfo& info );
// global alpha setting functions
// affect all subsequent draw calls - shouldn't normally be used directly, only in Panel::PaintTraverse()
virtual void DrawSetAlphaMultiplier( float alpha /* [0..1] */ );
virtual float DrawGetAlphaMultiplier();
// web browser
virtual void SetAllowHTMLJavaScript( bool state );
// video mode changing
virtual void OnScreenSizeChanged( int nOldWidth, int nOldHeight );
virtual vgui::HCursor CreateCursorFromFile( char const *curOrAniFile, char const *pPathID );
virtual void PaintTraverseEx(VPANEL panel, bool paintPopups = false );
virtual float GetZPos() const;
virtual void SetPanelForInput( VPANEL vpanel );
virtual vgui::IImage *GetIconImageForFullPath( char const *pFullPath );
virtual void DestroyTextureID( int id );
virtual const char *GetResolutionKey( void ) const;
virtual bool ForceScreenSizeOverride( bool bState, int wide, int tall );
// LocalToScreen, ParentLocalToScreen fixups for explicit PaintTraverse calls on Panels not at 0, 0 position
virtual bool ForceScreenPosOffset( bool bState, int x, int y );
virtual void OffsetAbsPos( int &x, int &y );
virtual void GetKernedCharWidth( HFont font, wchar_t ch, wchar_t chBefore, wchar_t chAfter, float &wide, float &flabcA );
virtual const char *GetWebkitHTMLUserAgentString() { return "Valve Client"; }
virtual void *Deprecated_AccessChromeHTMLController() { return NULL; }
virtual void SetFullscreenViewport( int x, int y, int w, int h ) OVERRIDE;
virtual void SetFullscreenViewportAndRenderTarget( int x, int y, int w, int h, ITexture *pRenderTarget ) OVERRIDE;
virtual void GetFullscreenViewportAndRenderTarget( int & x, int & y, int & w, int & h, ITexture **ppRenderTarget ) OVERRIDE;
virtual void GetFullscreenViewport( int & x, int & y, int & w, int & h ) OVERRIDE;
virtual void PushFullscreenViewport() OVERRIDE;
virtual void PopFullscreenViewport() OVERRIDE;
// support for software cursors
virtual void SetSoftwareCursor( bool bUseSoftwareCursor ) OVERRIDE;
virtual void PaintSoftwareCursor() OVERRIDE;
// Methods of ILocalizeTextQuery
public:
//virtual int ComputeTextWidth( const wchar_t *pString );
// Causes fonts to get reloaded, etc.
virtual void ResetFontCaches();
virtual bool IsScreenSizeOverrideActive( void );
virtual bool IsScreenPosOverrideActive( void );
virtual IMaterial *DrawGetTextureMaterial( int id );
virtual int GetTextureNumFrames( int id );
virtual void DrawSetTextureFrame( int id, int nFrame, unsigned int *pFrameCache );
private:
//void DrawRenderCharInternal( const FontCharRenderInfo& info );
void DrawRenderCharInternal( const CharRenderInfo& info );
private:
enum { BASE_HEIGHT = 480, BASE_WIDTH = 640 };
struct PaintState_t
{
vgui::VPANEL m_pPanel;
int m_iTranslateX;
int m_iTranslateY;
int m_iScissorLeft;
int m_iScissorRight;
int m_iScissorTop;
int m_iScissorBottom;
};
// material Setting method
void InternalSetMaterial( IMaterial *material = NULL );
// Draws the fullscreen buffer into the panel
void DrawFullScreenBuffer( int nLeft, int nTop, int nRight, int nBottom );
// Helper method to initialize vertices (transforms them into screen space too)
void InitVertex( vgui::Vertex_t &vertex, int x, int y, float u, float v );
// Draws a quad + quad array
void DrawQuad( const vgui::Vertex_t &ul, const vgui::Vertex_t &lr, unsigned char *pColor );
void DrawQuadArray( int numQuads, vgui::Vertex_t *pVerts, unsigned char *pColor, bool bShouldClip = true );
// Necessary to wrap the rendering
void StartDrawing( void );
void StartDrawingIn3DSpace( const VMatrix &screenToWorld, int pw, int ph, float sw, float sh );
void FinishDrawing( void );
// Sets up a particular painting state...
void SetupPaintState( const PaintState_t &paintState );
void ResetPopupList();
void AddPopup( vgui::VPANEL panel );
void RemovePopup( vgui::VPANEL panel );
void AddPopupsToList( vgui::VPANEL panel );
// Helper for drawing colored text
int DrawColoredText( vgui::HFont font, int x, int y, int r, int g, int b, int a, const char *fmt, va_list argptr );
void SearchForWordBreak( vgui::HFont font, char *text, int& chars, int& pixels );
void InternalThinkTraverse(VPANEL panel);
void InternalSolveTraverse(VPANEL panel);
void InternalSchemeSettingsTraverse(VPANEL panel, bool forceApplySchemeSettings);
// handles mouse movement
void SetCursorPos(int x, int y);
void GetCursorPos(int &x, int &y);
void DrawTexturedLineInternal( const Vertex_t &a, const Vertex_t &b );
// Gets texture coordinates for drawing the full screen buffer
void GetFullScreenTexCoords( int x, int y, int w, int h, float *pMinU, float *pMinV, float *pMaxU, float *pMaxV );
// Is a panel under the restricted panel?
bool IsPanelUnderRestrictedPanel( VPANEL panel );
// Point Translation for current panel
int m_nTranslateX;
int m_nTranslateY;
// alpha multiplier for current panel [0..1]
float m_flAlphaMultiplier;
// The size of the window to draw into
int m_pSurfaceExtents[4];
// Color for drawing all non-text things
unsigned char m_DrawColor[4];
// Color for drawing text
unsigned char m_DrawTextColor[4];
// Location of text rendering
int m_pDrawTextPos[2];
// Meshbuilder used for drawing
IMesh* m_pMesh;
CMeshBuilder meshBuilder;
// White material used for drawing non-textured things
CMaterialReference m_pWhite;
// Used for 3D-rendered images
CTextureReference m_FullScreenBuffer;
CMaterialReference m_FullScreenBufferMaterial;
int m_nFullScreenBufferMaterialId;
CUtlString m_FullScreenBufferName;
bool m_bUsingTempFullScreenBufferMaterial;
// Root panel
vgui::VPANEL m_pEmbeddedPanel;
vgui::Panel *m_pDefaultEmbeddedPanel;
vgui::VPANEL m_pRestrictedPanel;
// List of pop-up panels based on the type enum above (draw order vs last clicked)
CUtlVector<vgui::HPanel> m_PopupList;
// Stack of paint state...
CUtlVector< PaintState_t > m_PaintStateStack;
vgui::HFont m_hCurrentFont;
vgui::HCursor _currentCursor;
bool m_cursorAlwaysVisible;
// The currently bound texture
int m_iBoundTexture;
// font drawing batching code
enum { MAX_BATCHED_CHAR_VERTS = 4096 };
vgui::Vertex_t m_BatchedCharVerts[ MAX_BATCHED_CHAR_VERTS ];
int m_nBatchedCharVertCount;
// What's the rectangle we're drawing in 3D paint mode?
int m_n3DLeft, m_n3DRight, m_n3DTop, m_n3DBottom;
// Are we painting in 3D? (namely drawing 3D objects *inside* the vgui panel)
bool m_bIn3DPaintMode : 1;
// If we are in 3d Paint mode, are we rendering to a texture? (Or directly to the screen)
bool m_b3DPaintRenderToTexture : 1;
// Are we drawing the vgui panel in the 3D world somewhere?
bool m_bDrawingIn3DWorld : 1;
// Is the app gonna call HandleInputEvent?
bool m_bAppDrivesInput : 1;
// Are we currently in the think() loop
bool m_bInThink : 1;
bool m_bNeedsKeyboard : 1;
bool m_bNeedsMouse : 1;
bool m_bAllowJavaScript : 1;
int m_nLastInputPollCount;
VPANEL m_CurrentThinkPanel;
// The attached HWND
void *m_HWnd;
// Installed function to play sounds
PlaySoundFunc_t m_PlaySoundFunc;
int m_WorkSpaceInsets[4];
class TitleEntry
{
public:
TitleEntry()
{
panel = NULL;
title[0] = 0;
}
vgui::VPANEL panel;
wchar_t title[128];
};
CUtlVector< TitleEntry > m_Titles;
CUtlVector< CUtlSymbol > m_CustomFontFileNames;
CUtlVector< CUtlSymbol > m_BitmapFontFileNames;
CUtlDict< int, int > m_BitmapFontFileMapping;
float m_flZPos;
CUtlDict< vgui::IImage *, unsigned short > m_FileTypeImages;
int GetTitleEntry( vgui::VPANEL panel );
virtual void DrawSetTextureRGBAEx(int id, const unsigned char *rgba, int wide, int tall, ImageFormat format );
struct ScreenOverride_t
{
ScreenOverride_t() : m_bActive( false )
{
m_nValue[ 0 ] = m_nValue[ 1 ] = 0;
}
bool m_bActive;
int m_nValue[ 2 ];
};
ScreenOverride_t m_ScreenSizeOverride;
ScreenOverride_t m_ScreenPosOverride;
int m_nFullscreenViewportX;
int m_nFullscreenViewportY;
int m_nFullscreenViewportWidth;
int m_nFullscreenViewportHeight;
ITexture *m_pFullscreenRenderTarget;
#ifdef LINUX
struct font_entry
{
void *data;
int size;
};
static CUtlDict< font_entry, unsigned short > m_FontData;
static void *FontDataHelper( const char *pchFontName, int &size, const char *fontFileName );
#endif
};
#if GLMDEBUG
class MatSurfFuncLogger // rip off of GLMFuncLogger - figure out a way to reunify these soon
{
public:
// simple function log
MatSurfFuncLogger( char *funcName )
{
CMatRenderContextPtr prc( g_pMaterialSystem );
m_funcName = funcName;
m_earlyOut = false;
prc->Printf( ">%s", m_funcName );
};
// more advanced version lets you pass args (i.e. called parameters or anything else of interest)
// no macro for this one, since no easy way to pass through the args as well as the funcname
MatSurfFuncLogger( char *funcName, PRINTF_FORMAT_STRING const char *fmt, ... )
{
CMatRenderContextPtr prc( g_pMaterialSystem );
m_funcName = funcName;
m_earlyOut = false;
// this acts like GLMPrintf here
// all the indent policy is down in GLMPrintfVA
// which means we need to inject a ">" at the front of the format string to make this work... sigh.
char modifiedFmt[2000];
modifiedFmt[0] = '>';
strcpy( modifiedFmt+1, fmt );
va_list vargs;
va_start(vargs, fmt);
prc->PrintfVA( modifiedFmt, vargs );
va_end( vargs );
}
~MatSurfFuncLogger( )
{
CMatRenderContextPtr prc( g_pMaterialSystem );
if (m_earlyOut)
{
prc->Printf( "<%s (early out)", m_funcName );
}
else
{
prc->Printf( "<%s", m_funcName );
}
};
void EarlyOut( void )
{
m_earlyOut = true;
};
char *m_funcName; // set at construction time
bool m_earlyOut;
};
// handy macro to go with the helper class
#define MAT_FUNC MatSurfFuncLogger _logger_ ( __FUNCTION__ )
#else
#define MAT_FUNC
#endif
#endif // MATSYSTEMSURFACE_H

View File

@ -0,0 +1,991 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Contains all texture state for the material system surface to use
//
//===========================================================================//
#include "bitmap/imageformat.h"
#include "TextureDictionary.h"
#include "utllinkedlist.h"
#include "checksum_crc.h"
#include "materialsystem/imaterial.h"
#include "vguimatsurface.h"
#include "materialsystem/imaterialsystem.h"
#include "tier0/dbg.h"
#include "KeyValues.h"
#include "pixelwriter.h"
#include "materialsystem/imaterialvar.h"
#include "materialsystem/itexture.h"
#include "vtf/vtf.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define TEXTURE_ID_UNKNOWN -1
class CMatSystemTexture;
// Case-sensitive string checksum
static CRC32_t Texture_CRCName( const char *string )
{
CRC32_t crc;
CRC32_Init( &crc );
CRC32_ProcessBuffer( &crc, (void *)string, strlen( string ) );
CRC32_Final( &crc );
return crc;
}
class CFontTextureRegen;
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CMatSystemTexture
{
public:
CMatSystemTexture( void );
~CMatSystemTexture( void );
void SetId( int id ) { m_ID = id; };
CRC32_t GetCRC() const;
void SetCRC( CRC32_t val );
void SetMaterial( const char *pFileName );
void SetMaterial( IMaterial *pMaterial );
void SetTexture( ITexture *pTexture ) { SafeAssign( &m_pOverrideTexture, pTexture ); }
// This is used when we want different rendering state sharing the same procedural texture (fonts)
void ReferenceOtherProcedural( CMatSystemTexture *pTexture, IMaterial *pMaterial );
IMaterial *GetMaterial() { return m_pMaterial; }
int Width() const { return m_iWide; }
int Height() const { return m_iTall; }
bool IsProcedural( void ) const;
void SetProcedural( bool proc );
bool IsReference() const { return m_Flags & TEXTURE_IS_REFERENCE; }
void SetTextureRGBA( const char* rgba, int wide, int tall, ImageFormat format, bool bFixupTextCoordsForDimensions );
void SetSubTextureRGBA( int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall );
void SetSubTextureRGBAEx( int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall, ImageFormat imageFormat );
void UpdateSubTextureRGBA( int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall, ImageFormat imageFormat );
float m_s0, m_t0, m_s1, m_t1;
private:
void CreateRegen( int nWidth, int nHeight, ImageFormat format );
void ReleaseRegen( void );
void CleanUpMaterial();
ITexture *GetTextureValue( void );
private:
enum
{
TEXTURE_IS_PROCEDURAL = 0x1,
TEXTURE_IS_REFERENCE = 0x2
};
CRC32_t m_crcFile;
IMaterial *m_pMaterial;
ITexture *m_pTexture;
ITexture *m_pOverrideTexture;
int m_iWide;
int m_iTall;
int m_iInputWide;
int m_iInputTall;
int m_ID;
int m_Flags;
CFontTextureRegen *m_pRegen;
};
//-----------------------------------------------------------------------------
// A class that manages textures used by the material system surface
//-----------------------------------------------------------------------------
class CTextureDictionary : public ITextureDictionary
{
public:
CTextureDictionary( void );
// Create, destroy textures
int CreateTexture( bool procedural = false );
int CreateTextureByTexture( ITexture *pTexture, bool procedural = true ) OVERRIDE;
void DestroyTexture( int id );
void DestroyAllTextures();
// Is this a valid id?
bool IsValidId( int id ) const;
// Binds a material to a texture
virtual void BindTextureToFile( int id, const char *pFileName );
virtual void BindTextureToMaterial( int id, IMaterial *pMaterial );
virtual void BindTextureToMaterialReference( int id, int referenceId, IMaterial *pMaterial );
// Texture info
IMaterial *GetTextureMaterial( int id );
void GetTextureSize(int id, int& iWide, int& iTall );
void GetTextureTexCoords( int id, float &s0, float &t0, float &s1, float &t1 );
void SetTextureRGBA( int id, const char* rgba, int wide, int tall );
void SetTextureRGBAEx( int id, const char* rgba, int wide, int tall, ImageFormat format, bool bFixupTextCoordsForDimensions );
void SetSubTextureRGBA( int id, int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall );
void SetSubTextureRGBAEx( int id, int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall, ImageFormat imageFormat );
void UpdateSubTextureRGBA( int id, int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall, ImageFormat imageFormat );
int FindTextureIdForTextureFile( char const *pFileName );
public:
CMatSystemTexture *GetTexture( int id );
private:
CUtlLinkedList< CMatSystemTexture, unsigned short > m_Textures;
};
static CTextureDictionary s_TextureDictionary;
//-----------------------------------------------------------------------------
// A texture regenerator that holds onto the bits at all times
//-----------------------------------------------------------------------------
class CFontTextureRegen : public ITextureRegenerator
{
public:
CFontTextureRegen( int nWidth, int nHeight, ImageFormat format )
{
m_nFormat = format;
m_nWidth = nWidth;
m_nHeight = nHeight;
if ( IsPC() )
{
int size = ImageLoader::GetMemRequired( m_nWidth, m_nHeight, 1, m_nFormat, false );
m_pTextureBits = new unsigned char[size];
memset( m_pTextureBits, 0, size );
}
else
{
// will be allocated as needed
m_pTextureBits = NULL;
}
}
~CFontTextureRegen( void )
{
DeleteTextureBits();
}
void UpdateBackingBits( Rect_t &subRect, const unsigned char *pBits, Rect_t &uploadRect, ImageFormat format )
{
int size = ImageLoader::GetMemRequired( m_nWidth, m_nHeight, 1, m_nFormat, false );
if ( IsPC() )
{
if ( !m_pTextureBits )
return;
}
else
{
Assert( !m_pTextureBits );
m_pTextureBits = new unsigned char[size];
memset( m_pTextureBits, 0, size );
}
// Copy subrect into backing bits storage
// source data is expected to be in same format as backing bits
int y;
if ( ImageLoader::SizeInBytes( m_nFormat ) == 4 )
{
bool bIsInputFullRect = ( subRect.width != uploadRect.width || subRect.height != uploadRect.height );
Assert( (subRect.x >= 0) && (subRect.y >= 0) );
Assert( (subRect.x + subRect.width <= m_nWidth) && (subRect.y + subRect.height <= m_nHeight) );
for ( y=0; y < subRect.height; ++y )
{
int idx = ( (subRect.y + y) * m_nWidth + subRect.x ) << 2;
unsigned int *pDst = (unsigned int*)(&m_pTextureBits[ idx ]);
int offset = bIsInputFullRect ? (subRect.y+y)*uploadRect.width + subRect.x : y*uploadRect.width;
const unsigned int *pSrc = (const unsigned int *)(&pBits[ offset << 2 ]);
ImageLoader::ConvertImageFormat( (const unsigned char *)pSrc, format,(unsigned char *)pDst, m_nFormat, subRect.width, 1 );
}
}
else
{
// cannot subrect copy when format is not RGBA
if ( subRect.width != m_nWidth || subRect.height != m_nHeight )
{
Assert( 0 );
return;
}
Q_memcpy( m_pTextureBits, pBits, size );
}
}
virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pSubRect )
{
if ( !m_pTextureBits )
return;
Assert( (pVTFTexture->Width() == m_nWidth) && (pVTFTexture->Height() == m_nHeight) );
int nFormatBytes = ImageLoader::SizeInBytes( m_nFormat );
if ( nFormatBytes == 4 )
{
if ( m_nFormat == pVTFTexture->Format() )
{
int ymax = pSubRect->y + pSubRect->height;
for( int y = pSubRect->y; y < ymax; ++y )
{
// copy each row across for the update
char *pchData = (char *)pVTFTexture->ImageData( 0, 0, 0, 0, y ) + pSubRect->x *nFormatBytes;
int size = ImageLoader::GetMemRequired( pSubRect->width, 1, 1, m_nFormat, false );
V_memcpy( pchData, m_pTextureBits + (y * m_nWidth + pSubRect->x) * nFormatBytes, size );
}
}
else
{
// formats don't match so do a pixel by pixel swizel
CPixelWriter pixelWriter;
pixelWriter.SetPixelMemory(
pVTFTexture->Format(),
pVTFTexture->ImageData( 0, 0, 0 ),
pVTFTexture->RowSizeInBytes( 0 ) );
// Now upload the part we've been asked for
int xmax = pSubRect->x + pSubRect->width;
int ymax = pSubRect->y + pSubRect->height;
int x, y;
for( y = pSubRect->y; y < ymax; ++y )
{
pixelWriter.Seek( pSubRect->x, y );
unsigned char *rgba = &m_pTextureBits[ (y * m_nWidth + pSubRect->x) * nFormatBytes ];
for ( x=pSubRect->x; x < xmax; ++x )
{
pixelWriter.WritePixel( rgba[0], rgba[1], rgba[2], rgba[3] );
rgba += nFormatBytes;
}
}
}
}
else
{
// cannot subrect copy when format is not RGBA
if ( pSubRect->width != m_nWidth || pSubRect->height != m_nHeight )
{
Assert( 0 );
return;
}
int size = ImageLoader::GetMemRequired( m_nWidth, m_nHeight, 1, m_nFormat, false );
Q_memcpy( pVTFTexture->ImageData( 0, 0, 0 ), m_pTextureBits, size );
}
}
virtual void Release()
{
// Called by the material system when this needs to go away
DeleteTextureBits();
}
void DeleteTextureBits()
{
if ( m_pTextureBits )
{
delete [] m_pTextureBits;
m_pTextureBits = NULL;
}
}
private:
unsigned char *m_pTextureBits;
short m_nWidth;
short m_nHeight;
ImageFormat m_nFormat;
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CMatSystemTexture::CMatSystemTexture( void )
{
m_pMaterial = NULL;
m_pTexture = NULL;
m_pOverrideTexture = NULL;
m_crcFile = (CRC32_t)0;
m_iWide = m_iTall = 0;
m_s0 = m_t0 = 0;
m_s1 = m_t1 = 1;
m_Flags = 0;
m_pRegen = NULL;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CMatSystemTexture::~CMatSystemTexture( void )
{
if ( m_pOverrideTexture )
{
m_pOverrideTexture->Release();
m_pOverrideTexture->DeleteIfUnreferenced();
m_pOverrideTexture = NULL;
}
CleanUpMaterial();
}
bool CMatSystemTexture::IsProcedural( void ) const
{
return (m_Flags & TEXTURE_IS_PROCEDURAL) != 0;
}
void CMatSystemTexture::SetProcedural( bool proc )
{
if (proc)
{
m_Flags |= TEXTURE_IS_PROCEDURAL;
}
else
{
m_Flags &= ~TEXTURE_IS_PROCEDURAL;
}
}
void CMatSystemTexture::CleanUpMaterial()
{
if ( m_pMaterial )
{
// causes the underlying texture (if unreferenced) to be deleted as well
m_pMaterial->DecrementReferenceCount();
m_pMaterial->DeleteIfUnreferenced();
m_pMaterial = NULL;
}
if ( m_pTexture )
{
m_pTexture->SetTextureRegenerator( NULL );
m_pTexture->DecrementReferenceCount();
m_pTexture->DeleteIfUnreferenced();
m_pTexture = NULL;
}
ReleaseRegen();
}
void CMatSystemTexture::CreateRegen( int nWidth, int nHeight, ImageFormat format )
{
Assert( IsProcedural() );
if ( !m_pRegen )
{
m_pRegen = new CFontTextureRegen( nWidth, nHeight, format );
}
}
void CMatSystemTexture::ReleaseRegen( void )
{
if (m_pRegen)
{
if (!IsReference())
{
delete m_pRegen;
}
m_pRegen = NULL;
}
}
void CMatSystemTexture::SetTextureRGBA( const char *rgba, int wide, int tall, ImageFormat format, bool bFixupTextCoords )
{
Assert( IsProcedural() );
if ( !IsProcedural() )
return;
if ( !m_pMaterial )
{
int width = wide;
int height = tall;
// find the minimum power-of-two to fit this in
int i;
for ( i = 0; i < 32 ; i++ )
{
width = (1<<i);
if (width >= wide)
{
break;
}
}
for (i = 0; i < 32; i++ )
{
height= (1<<i);
if (height >= tall)
{
break;
}
}
// create a procedural material to fit this texture into
static int nTextureId = 0;
char pTextureName[64];
Q_snprintf( pTextureName, sizeof( pTextureName ), "__vgui_texture_%d", nTextureId );
++nTextureId;
ITexture *pTexture = g_pMaterialSystem->CreateProceduralTexture(
pTextureName,
TEXTURE_GROUP_VGUI,
width,
height,
format,
TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT |
TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_NOLOD |
TEXTUREFLAGS_PROCEDURAL | TEXTUREFLAGS_SINGLECOPY | TEXTUREFLAGS_POINTSAMPLE );
KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" );
pVMTKeyValues->SetInt( "$vertexcolor", 1 );
pVMTKeyValues->SetInt( "$vertexalpha", 1 );
pVMTKeyValues->SetInt( "$ignorez", 1 );
pVMTKeyValues->SetInt( "$no_fullbright", 1 );
pVMTKeyValues->SetInt( "$translucent", 1 );
pVMTKeyValues->SetString( "$basetexture", pTextureName );
IMaterial *pMaterial = g_pMaterialSystem->CreateMaterial( pTextureName, pVMTKeyValues );
pMaterial->Refresh();
// Has to happen after the refresh
pTexture->DecrementReferenceCount();
SetMaterial( pMaterial );
m_iInputTall = tall;
m_iInputWide = wide;
if ( bFixupTextCoords && ( wide != width || tall != height ) )
{
m_s1 = (double)wide / width;
m_t1 = (double)tall / height;
}
// undo the extra +1 refCount
pMaterial->DecrementReferenceCount();
}
Assert( wide <= m_iWide );
Assert( tall <= m_iTall );
// Just replace the whole thing
SetSubTextureRGBAEx( 0, 0, (const unsigned char *)rgba, wide, tall, format );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
ITexture *CMatSystemTexture::GetTextureValue( void )
{
Assert( IsProcedural() );
if ( !m_pMaterial )
return NULL;
if ( m_pOverrideTexture )
return m_pOverrideTexture;
return m_pTexture;
}
void CMatSystemTexture::SetSubTextureRGBA( int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall )
{
SetSubTextureRGBAEx( drawX, drawY, rgba, subTextureWide, subTextureTall, IMAGE_FORMAT_RGBA8888 );
}
void CMatSystemTexture::SetSubTextureRGBAEx( int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall, ImageFormat format )
{
ITexture *pTexture = GetTextureValue();
if ( !pTexture )
return;
Assert( IsProcedural() );
if ( !IsProcedural() )
return;
Assert( drawX < m_iWide );
Assert( drawY < m_iTall );
Assert( drawX + subTextureWide <= m_iWide );
Assert( drawY + subTextureTall <= m_iTall );
Assert( m_pRegen );
Assert( rgba );
Rect_t subRect;
subRect.x = drawX;
subRect.y = drawY;
subRect.width = subTextureWide;
subRect.height = subTextureTall;
Rect_t textureSize;
textureSize.x = 0;
textureSize.y = 0;
textureSize.width = subTextureWide;
textureSize.height = subTextureTall;
m_pRegen->UpdateBackingBits( subRect, rgba, textureSize, format );
pTexture->Download( &subRect );
if ( IsX360() )
{
// xboxissue - no need to persist "backing bits", saves memory
// the texture (commonly font page) "backing bits" are allocated during UpdateBackingBits() which get blitted
// into by procedural regeneration in preparation for download() which then subrect blits
// out of and into target texture (d3d upload)
// the "backing bits" are then no longer required
m_pRegen->DeleteTextureBits();
}
}
void CMatSystemTexture::UpdateSubTextureRGBA( int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall, ImageFormat imageFormat )
{
ITexture *pTexture = GetTextureValue();
if ( !pTexture )
return;
Assert( IsProcedural() );
if ( !IsProcedural() )
return;
Assert( drawX < m_iWide );
Assert( drawY < m_iTall );
Assert( drawX + subTextureWide <= m_iWide );
Assert( drawY + subTextureTall <= m_iTall );
Assert( m_pRegen );
Assert( rgba );
Rect_t subRect;
subRect.x = drawX;
subRect.y = drawY;
subRect.width = subTextureWide;
subRect.height = subTextureTall;
Rect_t textureSize;
textureSize.x = 0;
textureSize.y = 0;
textureSize.width = m_iInputWide;
textureSize.height = m_iInputTall;
m_pRegen->UpdateBackingBits( subRect, rgba, textureSize, imageFormat );
pTexture->Download( &subRect );
if ( IsX360() )
{
// xboxissue - no need to persist "backing bits", saves memory
// the texture (commonly font page) "backing bits" are allocated during UpdateBackingBits() which get blitted
// into by procedural regeneration in preparation for download() which then subrect blits
// out of and into target texture (d3d upload)
// the "backing bits" are then no longer required
m_pRegen->DeleteTextureBits();
}
}
void CMatSystemTexture::SetCRC( CRC32_t val )
{
m_crcFile = val;
}
CRC32_t CMatSystemTexture::GetCRC() const
{
return m_crcFile;
}
void CMatSystemTexture::SetMaterial( IMaterial *pMaterial )
{
// Decrement references to old texture
CleanUpMaterial();
m_pMaterial = pMaterial;
if (!m_pMaterial)
{
m_iWide = m_iTall = 0;
m_s0 = m_t0 = 0.0f;
m_s1 = m_t1 = 1.0f;
return;
}
// Increment its reference count
m_pMaterial->IncrementReferenceCount();
// Compute texture size
m_iWide = m_pMaterial->GetMappingWidth();
m_iTall = m_pMaterial->GetMappingHeight();
// Compute texture coordinates
float flPixelCenterX = 0.0f;
float flPixelCenterY = 0.0f;
if ( m_iWide > 0.0f && m_iTall > 0.0f)
{
flPixelCenterX = 0.5f / m_iWide;
flPixelCenterY = 0.5f / m_iTall;
}
m_s0 = flPixelCenterX;
m_t0 = flPixelCenterY;
// FIXME: Old code used +, it should be - yes?!??!
m_s1 = 1.0 - flPixelCenterX;
m_t1 = 1.0 - flPixelCenterY;
if ( IsProcedural() )
{
bool bFound;
IMaterialVar *tv = m_pMaterial->FindVar( "$baseTexture", &bFound );
if ( bFound && tv->IsTexture() )
{
m_pTexture = tv->GetTextureValue();
if ( m_pTexture )
{
m_pTexture->IncrementReferenceCount();
// Upload new data
CreateRegen( m_iWide, m_iTall, m_pTexture->GetImageFormat() );
m_pTexture->SetTextureRegenerator( m_pRegen );
}
}
}
}
//-----------------------------------------------------------------------------
// This is used when we want different rendering state sharing the same procedural texture (fonts)
//-----------------------------------------------------------------------------
void CMatSystemTexture::ReferenceOtherProcedural( CMatSystemTexture *pTexture, IMaterial *pMaterial )
{
// Decrement references to old texture
CleanUpMaterial();
Assert( pTexture->IsProcedural() );
m_Flags |= TEXTURE_IS_REFERENCE;
m_pMaterial = pMaterial;
if (!m_pMaterial)
{
m_iWide = m_iTall = 0;
m_s0 = m_t0 = 0.0f;
m_s1 = m_t1 = 1.0f;
return;
}
m_iWide = pTexture->m_iWide;
m_iTall = pTexture->m_iTall;
m_s0 = pTexture->m_s0;
m_t0 = pTexture->m_t0;
m_s1 = pTexture->m_s1;
m_t1 = pTexture->m_t1;
Assert( (pMaterial->GetMappingWidth() == m_iWide) && (pMaterial->GetMappingHeight() == m_iTall) );
// Increment its reference count
m_pMaterial->IncrementReferenceCount();
bool bFound;
IMaterialVar *tv = m_pMaterial->FindVar( "$baseTexture", &bFound );
if ( bFound )
{
m_pTexture = tv->GetTextureValue();
if ( m_pTexture )
{
m_pTexture->IncrementReferenceCount();
Assert( m_pTexture == pTexture->m_pTexture );
// Reference, but do *not* create a new one!!!
m_pRegen = pTexture->m_pRegen;
}
}
}
void CMatSystemTexture::SetMaterial( const char *pFileName )
{
// Get a pointer to the new material
IMaterial *pMaterial = g_pMaterialSystem->FindMaterial( pFileName, TEXTURE_GROUP_VGUI );
if ( IsErrorMaterial( pMaterial ) )
{
if (IsOSX())
{
printf( "\n ##### Missing Vgui material %s\n", pFileName );
}
Msg( "--- Missing Vgui material %s\n", pFileName );
}
SetMaterial( pMaterial );
}
//-----------------------------------------------------------------------------
// Singleton instance
//-----------------------------------------------------------------------------
ITextureDictionary *TextureDictionary()
{
return &s_TextureDictionary;
}
CTextureDictionary::CTextureDictionary( void )
{
// First entry is bogus texture
m_Textures.AddToTail();
}
//-----------------------------------------------------------------------------
// Create, destroy textures
//-----------------------------------------------------------------------------
int CTextureDictionary::CreateTexture( bool procedural /*=false*/ )
{
int idx = m_Textures.AddToTail();
CMatSystemTexture &texture = m_Textures[idx];
texture.SetProcedural( procedural );
texture.SetId( idx );
return idx;
}
int CTextureDictionary::CreateTextureByTexture( ITexture *pTexture, bool procedural /*= true*/ )
{
int idx = m_Textures.AddToTail();
CMatSystemTexture &texture = m_Textures[idx];
texture.SetProcedural( procedural );
texture.SetId( idx );
texture.SetTexture( pTexture );
return idx;
}
void CTextureDictionary::DestroyTexture( int id )
{
if ( m_Textures.Count() <= 1 )
{
// TextureDictionary already destroyed all the textures before this (something destructed late in shutdown)
return;
}
if (id != INVALID_TEXTURE_ID)
{
Assert( id != m_Textures.InvalidIndex() );
m_Textures.Remove( (unsigned short)id );
}
}
void CTextureDictionary::DestroyAllTextures()
{
m_Textures.RemoveAll();
// First entry is bogus texture
m_Textures.AddToTail();
CMatSystemTexture &texture = m_Textures[0];
texture.SetId( 0 );
}
void CTextureDictionary::SetTextureRGBA( int id, const char* rgba, int wide, int tall )
{
SetTextureRGBAEx( id, rgba, wide, tall, IMAGE_FORMAT_RGBA8888, false );
}
void CTextureDictionary::SetTextureRGBAEx( int id, const char* rgba, int wide, int tall, ImageFormat format, bool bFixupTextCoordsForDimensions )
{
if (!IsValidId(id))
{
Msg( "SetTextureRGBA: Invalid texture id %i\n", id );
return;
}
CMatSystemTexture &texture = m_Textures[id];
texture.SetTextureRGBA( rgba, wide, tall, format, bFixupTextCoordsForDimensions );
}
void CTextureDictionary::SetSubTextureRGBA( int id, int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall )
{
SetSubTextureRGBAEx( id, drawX, drawY, rgba, subTextureWide, subTextureTall, IMAGE_FORMAT_RGBA8888 );
}
void CTextureDictionary::SetSubTextureRGBAEx( int id, int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall, ImageFormat format )
{
if (!IsValidId(id))
{
Msg( "SetSubTextureRGBA: Invalid texture id %i\n", id );
return;
}
CMatSystemTexture &texture = m_Textures[id];
texture.SetSubTextureRGBAEx( drawX, drawY, rgba, subTextureWide, subTextureTall, format );
}
void CTextureDictionary::UpdateSubTextureRGBA( int id, int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall, ImageFormat imageFormat )
{
if (!IsValidId(id))
{
Msg( "UpdateSubTextureRGBA: Invalid texture id %i\n", id );
return;
}
CMatSystemTexture &texture = m_Textures[id];
texture.UpdateSubTextureRGBA( drawX, drawY, rgba, subTextureWide, subTextureTall, imageFormat );
}
//-----------------------------------------------------------------------------
// Returns true if the id is valid
//-----------------------------------------------------------------------------
bool CTextureDictionary::IsValidId( int id ) const
{
Assert( id != 0 );
if ( id == 0 )
return false;
return m_Textures.IsValidIndex( id );
}
//-----------------------------------------------------------------------------
// Binds a file to a particular texture
//-----------------------------------------------------------------------------
void CTextureDictionary::BindTextureToFile( int id, const char *pFileName )
{
if (!IsValidId(id))
{
Msg( "BindTextureToFile: Invalid texture id for file %s\n", pFileName );
return;
}
CMatSystemTexture &texture = m_Textures[id];
// Reload from file if the material was never loaded, or if the filename has changed at all
CRC32_t fileNameCRC = Texture_CRCName( pFileName );
if ( !texture.GetMaterial() || fileNameCRC != texture.GetCRC() )
{
// New texture name
texture.SetCRC( fileNameCRC );
texture.SetMaterial( pFileName );
}
}
//-----------------------------------------------------------------------------
// Binds a material to a texture
//-----------------------------------------------------------------------------
void CTextureDictionary::BindTextureToMaterial( int id, IMaterial *pMaterial )
{
if (!IsValidId(id))
{
Msg( "BindTextureToFile: Invalid texture id %d\n", id );
return;
}
CMatSystemTexture &texture = m_Textures[id];
texture.SetMaterial( pMaterial );
}
//-----------------------------------------------------------------------------
// Binds a material to a texture reference
//-----------------------------------------------------------------------------
void CTextureDictionary::BindTextureToMaterialReference( int id, int referenceId, IMaterial *pMaterial )
{
if (!IsValidId(id) || !IsValidId(referenceId))
{
Msg( "BindTextureToFile: Invalid texture ids %d %d\n", id, referenceId );
return;
}
CMatSystemTexture &texture = m_Textures[id];
CMatSystemTexture &textureSource = m_Textures[referenceId];
texture.ReferenceOtherProcedural( &textureSource, pMaterial );
}
//-----------------------------------------------------------------------------
// Returns the material associated with an id
//-----------------------------------------------------------------------------
IMaterial *CTextureDictionary::GetTextureMaterial( int id )
{
if (!IsValidId(id))
return NULL;
return m_Textures[id].GetMaterial();
}
//-----------------------------------------------------------------------------
// Returns the material size associated with an id
//-----------------------------------------------------------------------------
void CTextureDictionary::GetTextureSize(int id, int& iWide, int& iTall )
{
if (!IsValidId(id))
{
iWide = iTall = 0;
return;
}
iWide = m_Textures[id].Width();
iTall = m_Textures[id].Height();
}
void CTextureDictionary::GetTextureTexCoords( int id, float &s0, float &t0, float &s1, float &t1 )
{
if (!IsValidId(id))
{
s0 = t0 = 0.0f;
s1 = t1 = 1.0f;
return;
}
s0 = m_Textures[id].m_s0;
t0 = m_Textures[id].m_t0;
s1 = m_Textures[id].m_s1;
t1 = m_Textures[id].m_t1;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : id -
// Output : CMatSystemTexture
//-----------------------------------------------------------------------------
CMatSystemTexture *CTextureDictionary::GetTexture( int id )
{
if (!IsValidId(id))
return NULL;
return &m_Textures[ id ];
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pFileName -
//-----------------------------------------------------------------------------
int CTextureDictionary::FindTextureIdForTextureFile( char const *pFileName )
{
for ( int i = m_Textures.Head(); i != m_Textures.InvalidIndex(); i = m_Textures.Next( i ) )
{
CMatSystemTexture *tex = &m_Textures[i];
if ( !tex )
continue;
IMaterial *mat = tex->GetMaterial();
if ( !mat )
continue;
if ( !stricmp( mat->GetName(), pFileName ) )
return i;
}
return -1;
}

View File

@ -0,0 +1,63 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Contains all texture state for the material system surface to use
//
// $Revision: $
// $NoKeywords: $
//=============================================================================//
#ifndef TEXTUREDICTIONARY_H
#define TEXTUREDICTIONARY_H
class IMaterial;
class ITexture;
enum
{
INVALID_TEXTURE_ID = -1
};
//-----------------------------------------------------------------------------
// A class that manages textures used by the material system surface
//-----------------------------------------------------------------------------
class ITextureDictionary
{
public:
// Create, destroy textures
virtual int CreateTexture( bool procedural = false ) = 0;
virtual int CreateTextureByTexture( ITexture *pTexture, bool procedural = true ) = 0;
virtual void DestroyTexture( int id ) = 0;
virtual void DestroyAllTextures() = 0;
// Is this a valid id?
virtual bool IsValidId( int id ) const = 0;
// Binds a material to a texture
virtual void BindTextureToFile( int id, const char *pFileName ) = 0;
// Binds a material to a texture
virtual void BindTextureToMaterial( int id, IMaterial *pMaterial ) = 0;
// Binds a material to a texture
virtual void BindTextureToMaterialReference( int id, int referenceId, IMaterial *pMaterial ) = 0;
// Texture info
virtual IMaterial *GetTextureMaterial( int id ) = 0;
virtual void GetTextureSize(int id, int& iWide, int& iTall ) = 0;
virtual void GetTextureTexCoords( int id, float &s0, float &t0, float &s1, float &t1 ) = 0;
virtual void SetTextureRGBA( int id, const char* rgba, int wide, int tall ) = 0;
virtual int FindTextureIdForTextureFile( char const *pFileName ) = 0;
virtual void SetSubTextureRGBA( int id, int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall ) = 0;
virtual void SetSubTextureRGBAEx( int id, int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall, ImageFormat format ) = 0;
virtual void SetTextureRGBAEx( int id, const char* rgba, int wide, int tall, ImageFormat format, bool bFixupTextCoordsForDimensions ) = 0;
virtual void UpdateSubTextureRGBA( int id, int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall, ImageFormat imageFormat ) = 0;
};
ITextureDictionary *TextureDictionary();
#endif // TEXTUREDICTIONARY_H

View File

@ -0,0 +1,181 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include <vgui/ISurface.h>
#include "memorybitmap.h"
#include <string.h>
#include <stdlib.h>
#include "MatSystemSurface.h"
#include "materialsystem/imaterialvar.h"
#include "materialsystem/itexture.h"
#include "bitmap/imageformat.h"
#include "vtf/vtf.h"
#include "KeyValues.h"
#include "TextureDictionary.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern CMatSystemSurface g_MatSystemSurface;
using namespace vgui;
//-----------------------------------------------------------------------------
// Purpose: Constructor
// Input : *filename - image file to load
//-----------------------------------------------------------------------------
MemoryBitmap::MemoryBitmap(unsigned char *texture,int wide, int tall)
{
_texture=texture;
_uploaded = false;
_color = Color(255, 255, 255, 255);
_pos[0] = _pos[1] = 0;
_valid = true;
_w = wide;
_h = tall;
m_iTextureID = -1;
ForceUpload(texture,wide,tall);
}
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
MemoryBitmap::~MemoryBitmap()
{
// Free the old texture ID.
if ( m_iTextureID != -1 )
{
TextureDictionary()->DestroyTexture( m_iTextureID );
m_iTextureID = -1;
}
}
//-----------------------------------------------------------------------------
// Purpose: data accessor
//-----------------------------------------------------------------------------
void MemoryBitmap::GetSize(int &wide, int &tall)
{
wide = 0;
tall = 0;
if (!_valid)
return;
g_MatSystemSurface.DrawGetTextureSize(m_iTextureID, wide, tall);
}
//-----------------------------------------------------------------------------
// Purpose: size of the bitmap
//-----------------------------------------------------------------------------
void MemoryBitmap::GetContentSize(int &wide, int &tall)
{
GetSize(wide, tall);
}
//-----------------------------------------------------------------------------
// Purpose: ignored
//-----------------------------------------------------------------------------
void MemoryBitmap::SetSize(int x, int y)
{
}
//-----------------------------------------------------------------------------
// Purpose: data accessor
//-----------------------------------------------------------------------------
void MemoryBitmap::SetPos(int x, int y)
{
_pos[0] = x;
_pos[1] = y;
}
//-----------------------------------------------------------------------------
// Purpose: data accessor
//-----------------------------------------------------------------------------
void MemoryBitmap::SetColor(Color col)
{
_color = col;
}
//-----------------------------------------------------------------------------
// Purpose: returns the file name of the bitmap
//-----------------------------------------------------------------------------
const char *MemoryBitmap::GetName()
{
return "MemoryBitmap";
}
//-----------------------------------------------------------------------------
// Purpose: Renders the loaded image, uploading it if necessary
// Assumes a valid image is always returned from uploading
//-----------------------------------------------------------------------------
void MemoryBitmap::Paint()
{
if (!_valid)
return;
// if we have not uploaded yet, lets go ahead and do so
if (!_uploaded)
{
ForceUpload(_texture,_w,_h);
}
//set the texture current, set the color, and draw the biatch
g_MatSystemSurface.DrawSetTexture(m_iTextureID);
g_MatSystemSurface.DrawSetColor(_color[0], _color[1], _color[2], _color[3]);
int wide, tall;
GetSize(wide, tall);
g_MatSystemSurface.DrawTexturedRect( _pos[0], _pos[1], _pos[0] + wide, _pos[1] + tall);
}
//-----------------------------------------------------------------------------
// Purpose: ensures the bitmap has been uploaded
//-----------------------------------------------------------------------------
void MemoryBitmap::ForceUpload(unsigned char *texture,int wide, int tall)
{
_texture=texture;
bool sizechanged = ( _w != wide || _h != tall );
_w = wide;
_h = tall;
if (!_valid)
return;
if(_w==0 || _h==0)
return;
// Not our first time through and the size changed, destroy and recreate texture id...
if ( m_iTextureID != -1 && sizechanged )
{
TextureDictionary()->DestroyTexture( m_iTextureID );
m_iTextureID = -1;
}
if ( m_iTextureID == -1 )
{
m_iTextureID = g_MatSystemSurface.CreateNewTextureID( true );
}
g_MatSystemSurface.DrawSetTextureRGBA( m_iTextureID, texture, wide, tall, true, true );
_uploaded = true;
_valid = g_MatSystemSurface.IsTextureIDValid(m_iTextureID);
}
//-----------------------------------------------------------------------------
// Purpose: data accessor
//-----------------------------------------------------------------------------
HTexture MemoryBitmap::GetID()
{
return m_iTextureID;
}

View File

@ -0,0 +1,63 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef MEMORYBITMAP_H
#define MEMORYBITMAP_H
#ifdef _WIN32
#pragma once
#endif
#include <vgui/VGUI.h>
#include <vgui/IImage.h>
#include <Color.h>
namespace vgui
{
typedef unsigned long HTexture;
//-----------------------------------------------------------------------------
// Purpose: Holds a single image created from a chunk of memory, internal to vgui only
//-----------------------------------------------------------------------------
class MemoryBitmap: public IImage
{
public:
MemoryBitmap(unsigned char *texture,int wide, int tall);
~MemoryBitmap();
// IImage implementation
virtual void Paint();
virtual void GetSize(int &wide, int &tall);
virtual void GetContentSize(int &wide, int &tall);
virtual void SetPos(int x, int y);
virtual void SetSize(int x, int y);
virtual void SetColor(Color col);
// methods
void ForceUpload(unsigned char *texture,int wide, int tall); // ensures the bitmap has been uploaded
HTexture GetID(); // returns the texture id
const char *GetName();
bool IsValid()
{
return _valid;
}
private:
// HTexture _id;
bool _uploaded;
bool _valid;
unsigned char *_texture;
int _pos[2];
Color _color;
int _w,_h; // size of the texture
int m_iTextureID;
};
} // namespace vgui
#endif // MEMORYBITMAP_H

View File

@ -0,0 +1,30 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Implementation of the VGUI ISurface interface using the
// material system to implement it
//
// $Revision: $
// $NoKeywords: $
//===========================================================================//
#ifndef VGUIMATSURFACE_H
#define VGUIMATSURFACE_H
#include <vgui/VGUI.h>
#include "tier3/tier3.h"
namespace vgui
{
class IInputInternal;
}
//-----------------------------------------------------------------------------
// Globals...
//-----------------------------------------------------------------------------
extern vgui::IInputInternal *g_pIInput;
#endif // VGUIMATSURFACE_H

View File

@ -0,0 +1,104 @@
//-----------------------------------------------------------------------------
// VGUIMATSURFACE.VPC
//
// Project Script
//-----------------------------------------------------------------------------
$macro SRCDIR ".."
$Macro OUTBINDIR "$SRCDIR\..\game\bin"
$include "$SRCDIR\vpc_scripts\source_dll_base.vpc"
$Configuration
{
$Compiler
{
$PreprocessorDefinitions "$BASE;BENCHMARK;VGUIMATSURFACE_DLL_EXPORT;GAMEUI_EXPORTS;DONT_PROTECT_FILEIO_FUNCTIONS;PROTECTED_THINGS_ENABLE"
$PreprocessorDefinitions "$BASE;fopen=dont_use_fopen" [$WIN32]
$EnableC++Exceptions "Yes (/EHsc)"
// $TreatWchar_tAsBuiltinType "No"
}
$Linker
{
$SystemLibraries "iconv" [$OSXALL]
$SystemFrameworks "Carbon" [$OSXALL]
$GCC_ExtraLinkerFlags "-L/usr/lib32 -L/usr/lib -L/usr/lib/i386-linux-gnu" [$LINUXALL]
$SystemLibraries "fontconfig;freetype" [$LINUXALL]
$AdditionalDependencies "$BASE vgui_surfacelib_360.lib" [$X360]
$AdditionalDependencies "$BASE vgui_surfacelib.lib nvtc.lib" [$WIN32]
}
}
$Project "vguimatsurface"
{
$Folder "Source Files"
{
$File "Clip2D.cpp"
$File "Cursor.cpp"
$File "$SRCDIR\public\filesystem_helpers.cpp"
$File "FontTextureCache.cpp"
$File "Input.cpp"
$File "MatSystemSurface.cpp"
$File "memorybitmap.cpp" [$WIN32]
$File "TextureDictionary.cpp"
$File "$SRCDIR\vgui2\src\vgui_key_translation.cpp"
$File "$SRCDIR\public\vgui_controls\vgui_controls.cpp"
}
$Folder "Header Files"
{
$File "Clip2D.h"
$File "Cursor.h"
$File "Input.h"
$File "memorybitmap.h" [$WIN32]
$File "TextureDictionary.h"
$File "vguimatsurface.h"
$File "MatSystemSurface.h"
$File "FontTextureCache.h"
$File "$SRCDIR\vgui2\src\vgui_key_translation.h"
}
$Folder "Public Header Files"
{
$File "$SRCDIR\public\tier0\basetypes.h"
$File "$SRCDIR\public\tier1\characterset.h"
$File "$SRCDIR\public\tier1\checksum_crc.h"
$File "$SRCDIR\public\tier0\commonmacros.h"
$File "$SRCDIR\public\filesystem.h"
$File "$SRCDIR\public\filesystem_helpers.h"
$File "$SRCDIR\common\vgui_surfacelib\FontAmalgam.h"
$File "$SRCDIR\common\vgui_surfacelib\FontManager.h"
$File "$SRCDIR\public\appframework\IAppSystem.h"
$File "$SRCDIR\public\materialsystem\imaterial.h"
$File "$SRCDIR\public\materialsystem\imaterialsystem.h"
$File "$SRCDIR\public\materialsystem\imaterialvar.h"
$File "$SRCDIR\public\VGuiMatSurface\IMatSystemSurface.h"
$File "$SRCDIR\public\materialsystem\imesh.h"
$File "$SRCDIR\public\tier1\interface.h"
$File "$SRCDIR\public\materialsystem\itexture.h"
$File "$SRCDIR\public\pixelwriter.h"
$File "$SRCDIR\public\tier1\strtools.h"
$File "$SRCDIR\public\tier1\utllinkedlist.h"
$File "$SRCDIR\public\tier1\utlmemory.h"
$File "$SRCDIR\public\tier1\utlrbtree.h"
$File "$SRCDIR\public\tier1\utlvector.h"
$File "$SRCDIR\public\mathlib\vector.h"
$File "$SRCDIR\public\mathlib\vector2d.h"
$File "$SRCDIR\public\mathlib\vector4d.h"
$File "$SRCDIR\public\vstdlib\vstdlib.h"
$File "$SRCDIR\public\vtf\vtf.h"
$File "$SRCDIR\common\vgui_surfacelib\Win32Font.h"
}
$Folder "Link Libraries"
{
$Lib bitmap
$Lib mathlib
$Lib tier2
$Lib tier3
$Lib vgui_controls
$Lib vgui_surfacelib
$ImpLib SDL2 [$SDL]
}
}

View File

@ -0,0 +1,3 @@
LIBRARY vguimatsurface_360.dll
EXPORTS
CreateInterface @1