diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /vguimatsurface | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'vguimatsurface')
| -rw-r--r-- | vguimatsurface/Clip2D.cpp | 457 | ||||
| -rw-r--r-- | vguimatsurface/Clip2D.h | 46 | ||||
| -rw-r--r-- | vguimatsurface/Cursor.cpp | 565 | ||||
| -rw-r--r-- | vguimatsurface/Cursor.h | 75 | ||||
| -rw-r--r-- | vguimatsurface/FontTextureCache.cpp | 512 | ||||
| -rw-r--r-- | vguimatsurface/FontTextureCache.h | 102 | ||||
| -rw-r--r-- | vguimatsurface/Input.cpp | 524 | ||||
| -rw-r--r-- | vguimatsurface/Input.h | 47 | ||||
| -rw-r--r-- | vguimatsurface/MatSystemSurface.cpp | 4614 | ||||
| -rw-r--r-- | vguimatsurface/MatSystemSurface.h | 643 | ||||
| -rw-r--r-- | vguimatsurface/TextureDictionary.cpp | 991 | ||||
| -rw-r--r-- | vguimatsurface/TextureDictionary.h | 63 | ||||
| -rw-r--r-- | vguimatsurface/memorybitmap.cpp | 181 | ||||
| -rw-r--r-- | vguimatsurface/memorybitmap.h | 63 | ||||
| -rw-r--r-- | vguimatsurface/vguimatsurface.h | 30 | ||||
| -rw-r--r-- | vguimatsurface/vguimatsurface.vpc | 104 | ||||
| -rw-r--r-- | vguimatsurface/xbox/xbox.def | 3 |
17 files changed, 9020 insertions, 0 deletions
diff --git a/vguimatsurface/Clip2D.cpp b/vguimatsurface/Clip2D.cpp new file mode 100644 index 0000000..af4cef2 --- /dev/null +++ b/vguimatsurface/Clip2D.cpp @@ -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; +} + diff --git a/vguimatsurface/Clip2D.h b/vguimatsurface/Clip2D.h new file mode 100644 index 0000000..b196920 --- /dev/null +++ b/vguimatsurface/Clip2D.h @@ -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
\ No newline at end of file diff --git a/vguimatsurface/Cursor.cpp b/vguimatsurface/Cursor.cpp new file mode 100644 index 0000000..5451541 --- /dev/null +++ b/vguimatsurface/Cursor.cpp @@ -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; +} + + diff --git a/vguimatsurface/Cursor.h b/vguimatsurface/Cursor.h new file mode 100644 index 0000000..10166df --- /dev/null +++ b/vguimatsurface/Cursor.h @@ -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 + + + + + diff --git a/vguimatsurface/FontTextureCache.cpp b/vguimatsurface/FontTextureCache.cpp new file mode 100644 index 0000000..d94e9af --- /dev/null +++ b/vguimatsurface/FontTextureCache.cpp @@ -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; +} diff --git a/vguimatsurface/FontTextureCache.h b/vguimatsurface/FontTextureCache.h new file mode 100644 index 0000000..1f12e3c --- /dev/null +++ b/vguimatsurface/FontTextureCache.h @@ -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 diff --git a/vguimatsurface/Input.cpp b/vguimatsurface/Input.cpp new file mode 100644 index 0000000..cafacce --- /dev/null +++ b/vguimatsurface/Input.cpp @@ -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; +} + + + diff --git a/vguimatsurface/Input.h b/vguimatsurface/Input.h new file mode 100644 index 0000000..0f45cae --- /dev/null +++ b/vguimatsurface/Input.h @@ -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
\ No newline at end of file diff --git a/vguimatsurface/MatSystemSurface.cpp b/vguimatsurface/MatSystemSurface.cpp new file mode 100644 index 0000000..7426590 --- /dev/null +++ b/vguimatsurface/MatSystemSurface.cpp @@ -0,0 +1,4614 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Implementation of the VGUI ISurface interface using the +// material system to implement it +// +//=============================================================================// + +#if defined( WIN32) && !defined( _X360 ) +#include <windows.h> +#endif +#ifdef OSX +#include <Carbon/Carbon.h> +#endif + +#if defined( USE_SDL ) +#include <appframework/ilaunchermgr.h> +ILauncherMgr *g_pLauncherMgr = NULL; +#endif + + +#include "tier1/strtools.h" +#include "tier0/icommandline.h" +#include "tier0/dbg.h" +#include "filesystem.h" +#include <vgui/VGUI.h> +#include <Color.h> +#include "utlbuffer.h" +#include "utlvector.h" +#include "Clip2D.h" +#include <vgui_controls/Panel.h> +#include <vgui/IInput.h> +#include <vgui/Point.h> +#include "bitmap/imageformat.h" +#include "TextureDictionary.h" +#include "Cursor.h" +#include "Input.h" +#include <vgui/IHTML.h> +#include <vgui/IVGui.h> +#include "vgui_surfacelib/FontManager.h" +#include "FontTextureCache.h" +#include "MatSystemSurface.h" +#include "inputsystem/iinputsystem.h" +#include <vgui_controls/Controls.h> +#include <vgui/ISystem.h> +#include "icvar.h" +#include "mathlib/mathlib.h" +#include <vgui/ILocalize.h> +#include "mathlib/vmatrix.h" +#include <tier0/vprof.h> +#include "materialsystem/itexture.h" +#include <malloc.h> +#include "../vgui2/src/VPanel.h" +#include <vgui/IInputInternal.h> +#if defined( _X360 ) +#include "xbox/xbox_win32stubs.h" +#endif +#include "xbox/xboxstubs.h" +#include "../vgui2/src/Memorybitmap.h" + +#pragma warning( disable : 4706 ) + +#include <vgui/IVguiMatInfo.h> +#include <vgui/IVguiMatInfoVar.h> +#include "materialsystem/imaterialvar.h" + +#pragma warning( default : 4706 ) + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + + +#define VPANEL_NORMAL ((vgui::SurfacePlat *) NULL) +#define VPANEL_MINIMIZED ((vgui::SurfacePlat *) 0x00000001) + +using namespace vgui; + +static bool g_bSpewFocus = false; + +class CVguiMatInfoVar : public IVguiMatInfoVar +{ +public: + CVguiMatInfoVar( IMaterialVar *pMaterialVar ) + { + m_pMaterialVar = pMaterialVar; + } + + // from IVguiMatInfoVar + virtual int GetIntValue ( void ) const + { + return m_pMaterialVar->GetIntValue(); + } + + virtual void SetIntValue ( int val ) + { + m_pMaterialVar->SetIntValue( val ); + } + +private: + IMaterialVar *m_pMaterialVar; +}; + +class CVguiMatInfo : public IVguiMatInfo +{ +public: + CVguiMatInfo( IMaterial *pMaterial ) + { + m_pMaterial = pMaterial; + } + + // from IVguiMatInfo + virtual IVguiMatInfoVar* FindVarFactory( const char *varName, bool *found ) + { + IMaterialVar *pMaterialVar = m_pMaterial->FindVar( varName, found ); + + if ( pMaterialVar == NULL ) + return NULL; + return new CVguiMatInfoVar( pMaterialVar ); + } + + virtual int GetNumAnimationFrames( void ) + { + return m_pMaterial->GetNumAnimationFrames(); + } + +private: + IMaterial *m_pMaterial; +}; + + +//----------------------------------------------------------------------------- +// Globals... +//----------------------------------------------------------------------------- +vgui::IInputInternal *g_pIInput; +static bool g_bInDrawing; +static CFontTextureCache g_FontTextureCache; + +//----------------------------------------------------------------------------- +// Singleton instance +//----------------------------------------------------------------------------- +CMatSystemSurface g_MatSystemSurface; +EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CMatSystemSurface, ISurface, + VGUI_SURFACE_INTERFACE_VERSION, g_MatSystemSurface ); + +#ifdef LINUX +CUtlDict< CMatSystemSurface::font_entry, unsigned short > CMatSystemSurface::m_FontData; +#endif + +//----------------------------------------------------------------------------- +// Make sure the panel is the same size as the viewport +//----------------------------------------------------------------------------- +CMatEmbeddedPanel::CMatEmbeddedPanel() : BaseClass( NULL, "MatSystemTopPanel" ) +{ + SetPaintBackgroundEnabled( false ); + +#if defined( _X360 ) + SetPos( 0, 0 ); + SetSize( GetSystemMetrics( SM_CXSCREEN ), GetSystemMetrics( SM_CYSCREEN ) ); +#endif +} + +void CMatEmbeddedPanel::OnThink() +{ + int x, y, width, height; + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + pRenderContext->GetViewport( x, y, width, height ); + SetSize( width, height ); + SetPos( x, y ); + Repaint(); +} + +VPANEL CMatEmbeddedPanel::IsWithinTraverse(int x, int y, bool traversePopups) +{ + VPANEL retval = BaseClass::IsWithinTraverse( x, y, traversePopups ); + if ( retval == GetVPanel() ) + return 0; + return retval; +} + + +//----------------------------------------------------------------------------- +// Constructor, destructor +//----------------------------------------------------------------------------- +CMatSystemSurface::CMatSystemSurface() : m_pEmbeddedPanel(NULL), m_pWhite(NULL) +{ + m_iBoundTexture = -1; + m_HWnd = NULL; + m_bIn3DPaintMode = false; + m_b3DPaintRenderToTexture = false; + m_bDrawingIn3DWorld = false; + m_PlaySoundFunc = NULL; + m_bInThink = false; + m_bAllowJavaScript = false; + m_bAppDrivesInput = false; + m_nLastInputPollCount = 0; + + m_hCurrentFont = NULL; + m_pRestrictedPanel = NULL; + + m_bNeedsKeyboard = true; + m_bNeedsMouse = true; + m_bUsingTempFullScreenBufferMaterial = false; + m_nFullScreenBufferMaterialId = -1; + + memset( m_WorkSpaceInsets, 0, sizeof( m_WorkSpaceInsets ) ); + m_nBatchedCharVertCount = 0; + + m_nFullscreenViewportX = m_nFullscreenViewportY = 0; + m_nFullscreenViewportWidth = m_nFullscreenViewportHeight = 0; + m_pFullscreenRenderTarget = NULL; + + m_cursorAlwaysVisible = false; +} + +CMatSystemSurface::~CMatSystemSurface() +{ + if ( m_nFullScreenBufferMaterialId != -1 ) + { + DestroyTextureID( m_nFullScreenBufferMaterialId ); + m_nFullScreenBufferMaterialId = -1; + } +} + + +//----------------------------------------------------------------------------- +// Connect, disconnect... +//----------------------------------------------------------------------------- +bool CMatSystemSurface::Connect( CreateInterfaceFn factory ) +{ + if ( !BaseClass::Connect( factory ) ) + return false; + + if ( !g_pFullFileSystem ) + { + Warning( "MatSystemSurface requires the file system to run!\n" ); + return false; + } + + if ( !g_pMaterialSystem ) + { + Warning( "MatSystemSurface requires the material system to run!\n" ); + return false; + } + + if ( !g_pVGuiPanel ) + { + Warning( "MatSystemSurface requires the vgui::IPanel system to run!\n" ); + return false; + } + + g_pIInput = (IInputInternal *)factory( VGUI_INPUTINTERNAL_INTERFACE_VERSION, NULL ); + if ( !g_pIInput ) + { + Warning( "MatSystemSurface requires the vgui::IInput system to run!\n" ); + return false; + } + + if ( !g_pVGui ) + { + Warning( "MatSystemSurface requires the vgui::IVGUI system to run!\n" ); + return false; + } + + Assert( g_pVGuiSurface == this ); + + // initialize vgui_control interfaces + if ( !vgui::VGui_InitInterfacesList( "MATSURFACE", &factory, 1 ) ) + return false; + +#ifdef USE_SDL + g_pLauncherMgr = (ILauncherMgr *)factory( SDLMGR_INTERFACE_VERSION, NULL ); +#endif + + return true; +} + +void CMatSystemSurface::Disconnect() +{ + g_pIInput = NULL; + BaseClass::Disconnect(); +} + + +//----------------------------------------------------------------------------- +// Access to other interfaces... +//----------------------------------------------------------------------------- +void *CMatSystemSurface::QueryInterface( const char *pInterfaceName ) +{ + // We also implement the IMatSystemSurface interface + if (!Q_strncmp( pInterfaceName, MAT_SYSTEM_SURFACE_INTERFACE_VERSION, Q_strlen(MAT_SYSTEM_SURFACE_INTERFACE_VERSION) + 1)) + return (IMatSystemSurface*)this; + + // We also implement the IMatSystemSurface interface + if (!Q_strncmp( pInterfaceName, VGUI_SURFACE_INTERFACE_VERSION, Q_strlen(VGUI_SURFACE_INTERFACE_VERSION) + 1)) + return (vgui::ISurface*)this; + + return BaseClass::QueryInterface( pInterfaceName ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMatSystemSurface::InitFullScreenBuffer( const char *pszRenderTargetName ) +{ + if ( !IsPC() ) + return; + + char pTemp[512]; + Q_snprintf( pTemp, sizeof(pTemp), "VGUI_3DPaint_FullScreen_%s", pszRenderTargetName ); + m_FullScreenBufferMaterial.Shutdown(); + + // Set up a material with which to reference the final image for subsequent display using vgui + KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" ); + pVMTKeyValues->SetString( "$basetexture", pszRenderTargetName ); + pVMTKeyValues->SetInt( "$nocull", 1 ); + pVMTKeyValues->SetInt( "$nofog", 1 ); + pVMTKeyValues->SetInt( "$ignorez", 1 ); + pVMTKeyValues->SetInt( "$translucent", 1 ); + m_FullScreenBufferMaterial.Init( pTemp, TEXTURE_GROUP_OTHER, pVMTKeyValues ); + m_FullScreenBufferMaterial->Refresh(); + + if ( m_nFullScreenBufferMaterialId != -1 ) + { + DestroyTextureID( m_nFullScreenBufferMaterialId ); + } + m_nFullScreenBufferMaterialId = -1; + m_FullScreenBuffer.Shutdown(); + + m_FullScreenBufferName = pszRenderTargetName; +} + +//----------------------------------------------------------------------------- +// Initialization and shutdown... +//----------------------------------------------------------------------------- +InitReturnVal_t CMatSystemSurface::Init( void ) +{ + InitReturnVal_t nRetVal = BaseClass::Init(); + if ( nRetVal != INIT_OK ) + return nRetVal; + + // Allocate a white material + KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" ); + pVMTKeyValues->SetInt( "$vertexcolor", 1 ); + pVMTKeyValues->SetInt( "$vertexalpha", 1 ); + pVMTKeyValues->SetInt( "$ignorez", 1 ); + pVMTKeyValues->SetInt( "$no_fullbright", 1 ); + + if ( ! (CommandLine()->FindParm("-disable_matsurf_noculls")) ) + { + pVMTKeyValues->SetInt( "$nocull", 1 ); // skip this if user asks for the switch above + } + + m_pWhite.Init( "VGUI_White", TEXTURE_GROUP_OTHER, pVMTKeyValues ); + + InitFullScreenBuffer( "_rt_FullScreen" ); + + m_DrawColor[0] = m_DrawColor[1] = m_DrawColor[2] = m_DrawColor[3] = 255; + m_nTranslateX = m_nTranslateY = 0; + EnableScissor( false ); + SetScissorRect( 0, 0, 100000, 100000 ); + m_flAlphaMultiplier = 1.0f; + + // By default, use the default embedded panel + m_pDefaultEmbeddedPanel = new CMatEmbeddedPanel; + SetEmbeddedPanel( m_pDefaultEmbeddedPanel->GetVPanel() ); + + m_iBoundTexture = -1; + + // Initialize font info.. + m_pDrawTextPos[0] = m_pDrawTextPos[1] = 0; + m_DrawTextColor[0] = m_DrawTextColor[1] = m_DrawTextColor[2] = m_DrawTextColor[3] = 255; + + m_bIn3DPaintMode = false; + m_b3DPaintRenderToTexture = false; + m_bDrawingIn3DWorld = false; + m_PlaySoundFunc = NULL; + + // Input system + InitInput(); + + // Initialize cursors + InitCursors(); + + // fonts initialization + char language[64]; + bool bValid; + if ( IsPC() ) + { + bValid = system()->GetRegistryString( "HKEY_CURRENT_USER\\Software\\Valve\\Source\\Language", language, sizeof(language)-1 ); + } + else + { + Q_strncpy( language, XBX_GetLanguageString(), sizeof( language ) ); + bValid = true; + } + + if ( bValid ) + { + FontManager().SetLanguage( language ); + } + else + { + FontManager().SetLanguage( "english" ); + } + +#ifdef LINUX + FontManager().SetFontDataHelper( &CMatSystemSurface::FontDataHelper ); +#endif + + // font manager needs the file system and material system for bitmap fonts + FontManager().SetInterfaces( g_pFullFileSystem, g_pMaterialSystem ); + + g_bSpewFocus = CommandLine()->FindParm( "-vguifocus" ) ? true : false; + + return INIT_OK; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMatSystemSurface::Shutdown( void ) +{ + for ( int i = m_FileTypeImages.First(); i != m_FileTypeImages.InvalidIndex(); i = m_FileTypeImages.Next( i ) ) + { + delete m_FileTypeImages[ i ]; + } + m_FileTypeImages.RemoveAll(); + + // Release all textures + TextureDictionary()->DestroyAllTextures(); + m_iBoundTexture = -1; + + // Release the standard materials + m_pWhite.Shutdown(); + m_FullScreenBufferMaterial.Shutdown(); + m_FullScreenBuffer.Shutdown(); + + m_Titles.Purge(); + m_PaintStateStack.Purge(); + +#if defined( WIN32 ) && !defined( _X360 ) + // release any custom font files + // use newer function if possible + HMODULE gdiModule = ::LoadLibrary( "gdi32.dll" ); + typedef int (WINAPI *RemoveFontResourceExProc)(LPCTSTR, DWORD, PVOID); + RemoveFontResourceExProc pRemoveFontResourceEx = NULL; + if ( gdiModule ) + { + pRemoveFontResourceEx = (RemoveFontResourceExProc)::GetProcAddress(gdiModule, "RemoveFontResourceExA"); + } + + for (int i = 0; i < m_CustomFontFileNames.Count(); i++) + { + if (pRemoveFontResourceEx) + { + // dvs: Keep removing the font until we get an error back. After consulting with Microsoft, it appears + // that RemoveFontResourceEx must sometimes be called multiple times to work. Doing this insures that + // when we load the font next time we get the real font instead of Ariel. + int nRetries = 0; + while ( (*pRemoveFontResourceEx)(m_CustomFontFileNames[i].String(), 0x10, NULL) && ( nRetries < 10 ) ) + { + nRetries++; + Msg( "Removed font resource %s on attempt %d.\n", m_CustomFontFileNames[i].String(), nRetries ); + } + } + else + { + // dvs: Keep removing the font until we get an error back. After consulting with Microsoft, it appears + // that RemoveFontResourceEx must sometimes be called multiple times to work. Doing this insures that + // when we load the font next time we get the real font instead of Ariel. + int nRetries = 0; + while ( ::RemoveFontResource(m_CustomFontFileNames[i].String()) && ( nRetries < 10 ) ) + { + nRetries++; + Msg( "Removed font resource %s on attempt %d.\n", m_CustomFontFileNames[i].String(), nRetries ); + } + } + } +#endif + + m_CustomFontFileNames.RemoveAll(); + m_BitmapFontFileNames.RemoveAll(); + m_BitmapFontFileMapping.RemoveAll(); + + Cursor_ClearUserCursors(); + +#if defined( WIN32 ) && !defined( _X360 ) + if ( gdiModule ) + { + ::FreeLibrary(gdiModule); + } +#endif + + BaseClass::Shutdown(); +} + +void CMatSystemSurface::SetEmbeddedPanel(VPANEL pEmbeddedPanel) +{ + m_pEmbeddedPanel = pEmbeddedPanel; + ((VPanel *)pEmbeddedPanel)->Client()->RequestFocus(0); +} + +//----------------------------------------------------------------------------- +// hierarchy root +//----------------------------------------------------------------------------- +VPANEL CMatSystemSurface::GetEmbeddedPanel() +{ + return m_pEmbeddedPanel; +} + +//----------------------------------------------------------------------------- +// Purpose: cap bits +// Warning: if you change this, make sure the SurfaceV28 wrapper above reports +// the correct capabilities. +//----------------------------------------------------------------------------- +bool CMatSystemSurface::SupportsFeature(SurfaceFeature_e feature) +{ + switch (feature) + { + case ISurface::ANTIALIASED_FONTS: + case ISurface::DROPSHADOW_FONTS: + return true; + + case ISurface::OUTLINE_FONTS: + if ( IsX360() ) + return false; + return true; + + case ISurface::ESCAPE_KEY: + return true; + + case ISurface::OPENING_NEW_HTML_WINDOWS: + case ISurface::FRAME_MINIMIZE_MAXIMIZE: + default: + return false; + }; +} + +//----------------------------------------------------------------------------- +// Hook needed to Get input to work +//----------------------------------------------------------------------------- +void CMatSystemSurface::AttachToWindow( void *hWnd, bool bLetAppDriveInput ) +{ + InputDetachFromWindow( m_HWnd ); + m_HWnd = hWnd; + if ( hWnd ) + { + InputAttachToWindow( hWnd ); + m_bAppDrivesInput = bLetAppDriveInput; + } + else + { + // Never call RunFrame stuff + m_bAppDrivesInput = true; + } +} + +bool CMatSystemSurface::HandleInputEvent( const InputEvent_t &event ) +{ + if ( !m_bAppDrivesInput ) + { + g_pIInput->UpdateButtonState( event ); + } + + return InputHandleInputEvent( event ); +} + + +//----------------------------------------------------------------------------- +// Draws a panel in 3D space. Assumes view + projection are already set up +// Also assumes the (x,y) coordinates of the panels are defined in 640xN coords +// (N isn't necessary 480 because the panel may not be 4x3) +// The width + height specified are the size of the panel in world coordinates +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawPanelIn3DSpace( vgui::VPANEL pRootPanel, const VMatrix &panelCenterToWorld, int pw, int ph, float sw, float sh ) +{ + Assert( pRootPanel ); + + // FIXME: When should such panels be solved?!? + SolveTraverse( pRootPanel, false ); + + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + + // Force Z buffering to be on for all panels drawn... + pRenderContext->OverrideDepthEnable( true, false ); + + Assert(!m_bDrawingIn3DWorld); + m_bDrawingIn3DWorld = true; + + StartDrawingIn3DSpace( panelCenterToWorld, pw, ph, sw, sh ); + + ((VPanel *)pRootPanel)->Client()->Repaint(); + ((VPanel *)pRootPanel)->Client()->PaintTraverse(true, false); + + FinishDrawing(); + + // Reset z buffering to normal state + pRenderContext->OverrideDepthEnable( false, true ); + + m_bDrawingIn3DWorld = false; +} + + +//----------------------------------------------------------------------------- +// Purpose: Setup rendering for vgui on a panel existing in 3D space +//----------------------------------------------------------------------------- +void CMatSystemSurface::StartDrawingIn3DSpace( const VMatrix &screenToWorld, int pw, int ph, float sw, float sh ) +{ + g_bInDrawing = true; + m_iBoundTexture = -1; + + int px = 0; + int py = 0; + + m_pSurfaceExtents[0] = px; + m_pSurfaceExtents[1] = py; + m_pSurfaceExtents[2] = px + pw; + m_pSurfaceExtents[3] = py + ph; + + // In order for this to work, the model matrix must have its origin + // at the upper left corner of the screen. We must also scale down the + // rendering from pixel space to screen space. Let's construct a matrix + // transforming from pixel coordinates (640xN) to screen coordinates + // (wxh, with the origin at the upper left of the screen). Then we'll + // concatenate it with the panelCenterToWorld to produce pixelToWorld transform + VMatrix pixelToScreen; + + // First, scale it so that 0->pw transforms to 0->sw + MatrixBuildScale( pixelToScreen, sw / pw, -sh / ph, 1.0f ); + + // Construct pixelToWorld + VMatrix pixelToWorld; + MatrixMultiply( screenToWorld, pixelToScreen, pixelToWorld ); + + // make sure there is no translation and rotation laying around + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + + pRenderContext->MatrixMode( MATERIAL_MODEL ); + pRenderContext->PushMatrix(); + pRenderContext->LoadMatrix( pixelToWorld ); + + // These are only here so that FinishDrawing works... + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->PushMatrix(); + + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->PushMatrix(); + + // Always enable scissoring (translate to origin because of the glTranslatef call above..) + EnableScissor( true ); + + m_nTranslateX = 0; + m_nTranslateY = 0; + m_flAlphaMultiplier = 1.0f; +} + + +//----------------------------------------------------------------------------- +// Purpose: Setup ortho for vgui +//----------------------------------------------------------------------------- + +// we may need to offset by 0.5 texels to account for the different in pixel vs. texel centers in dx7-9 +// however, we do this fixup already when we set up the texture coordinates for all materials/fonts +// so in theory we shouldn't need to do any adjustments for setting up the screen +// HOWEVER, we must do the offset, else the driver will think the text is something that should +// be antialiased, so the text will look broken if antialiasing is turned on (usually forced on in the driver) +float g_flPixelOffsetX = 0.5f; +float g_flPixelOffsetY = 0.5f; + +bool g_bCheckedCommandLine = false; + +extern void ___stop___( void ); +void CMatSystemSurface::StartDrawing( void ) +{ + MAT_FUNC; + + if ( !g_bCheckedCommandLine ) + { + g_bCheckedCommandLine = true; + + const char *pX = CommandLine()->ParmValue( "-pixel_offset_x", (const char*)NULL ); + if ( pX ) + g_flPixelOffsetX = atof( pX ); + + const char *pY = CommandLine()->ParmValue( "-pixel_offset_y", (const char*)NULL ); + if ( pY ) + g_flPixelOffsetY = atof( pY ); + } + + g_bInDrawing = true; + m_iBoundTexture = -1; + + int x, y, width, height; + + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + pRenderContext->GetViewport( x, y, width, height); + + // we don't want to include x and y from the viewport here. DX will + // automatically translate any drawing we do into that viewport. + m_pSurfaceExtents[0] = 0; + m_pSurfaceExtents[1] = 0; + m_pSurfaceExtents[2] = width; + m_pSurfaceExtents[3] = height; + + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->PushMatrix(); + pRenderContext->LoadIdentity(); + pRenderContext->Scale( 1, -1, 1 ); + + //___stop___(); + pRenderContext->Ortho( g_flPixelOffsetX, g_flPixelOffsetY, width + g_flPixelOffsetX, height + g_flPixelOffsetY, -1.0f, 1.0f ); + + // make sure there is no translation and rotation laying around + pRenderContext->MatrixMode( MATERIAL_MODEL ); + pRenderContext->PushMatrix(); + pRenderContext->LoadIdentity(); + + // Always enable scissoring (translate to origin because of the glTranslatef call above..) + EnableScissor( true ); + + m_nTranslateX = 0; + m_nTranslateY = 0; + + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->PushMatrix(); + pRenderContext->LoadIdentity(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMatSystemSurface::FinishDrawing( void ) +{ + MAT_FUNC; + + // We're done with scissoring + EnableScissor( false ); + + // Restore the matrices + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->PopMatrix(); + + pRenderContext->MatrixMode( MATERIAL_MODEL ); + pRenderContext->PopMatrix(); + + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->PopMatrix(); + + Assert( g_bInDrawing ); + g_bInDrawing = false; +} + + +//----------------------------------------------------------------------------- +// frame +//----------------------------------------------------------------------------- +void CMatSystemSurface::RunFrame() +{ + int nPollCount = g_pInputSystem->GetPollCount(); + if ( m_nLastInputPollCount == nPollCount ) + return; + + // If this isn't true, we've lost input! + if ( !m_bAppDrivesInput && m_nLastInputPollCount != nPollCount - 1 ) + { + Assert( 0 ); + Warning( "Vgui is losing input messages! Call brian!\n" ); + } + + m_nLastInputPollCount = nPollCount; + + if ( m_bAppDrivesInput ) + return; + + // Generate all input messages + int nEventCount = g_pInputSystem->GetEventCount(); + const InputEvent_t* pEvents = g_pInputSystem->GetEventData( ); + for ( int i = 0; i < nEventCount; ++i ) + { + HandleInputEvent( pEvents[i] ); + } +} + + +//----------------------------------------------------------------------------- +// Sets up a particular painting state... +//----------------------------------------------------------------------------- +void CMatSystemSurface::SetupPaintState( const PaintState_t &paintState ) +{ + m_nTranslateX = paintState.m_iTranslateX; + m_nTranslateY = paintState.m_iTranslateY; + SetScissorRect( paintState.m_iScissorLeft, paintState.m_iScissorTop, + paintState.m_iScissorRight, paintState.m_iScissorBottom ); +} + +//----------------------------------------------------------------------------- +// Indicates a particular panel is about to be rendered +//----------------------------------------------------------------------------- +void CMatSystemSurface::PushMakeCurrent(VPANEL pPanel, bool useInSets) +{ + int inSets[4] = {0, 0, 0, 0}; + int absExtents[4]; + int clipRect[4]; + + if (useInSets) + { + g_pVGuiPanel->GetInset(pPanel, inSets[0], inSets[1], inSets[2], inSets[3]); + } + + g_pVGuiPanel->GetAbsPos(pPanel, absExtents[0], absExtents[1]); + int wide, tall; + g_pVGuiPanel->GetSize(pPanel, wide, tall); + absExtents[2] = absExtents[0] + wide; + absExtents[3] = absExtents[1] + tall; + + g_pVGuiPanel->GetClipRect(pPanel, clipRect[0], clipRect[1], clipRect[2], clipRect[3]); + + int i = m_PaintStateStack.AddToTail(); + PaintState_t &paintState = m_PaintStateStack[i]; + paintState.m_pPanel = pPanel; + + // Determine corrected top left origin + paintState.m_iTranslateX = inSets[0] + absExtents[0] - m_pSurfaceExtents[0]; + paintState.m_iTranslateY = inSets[1] + absExtents[1] - m_pSurfaceExtents[1]; + + // Setup clipping rectangle for scissoring + paintState.m_iScissorLeft = clipRect[0] - m_pSurfaceExtents[0]; + paintState.m_iScissorTop = clipRect[1] - m_pSurfaceExtents[1]; + paintState.m_iScissorRight = clipRect[2] - m_pSurfaceExtents[0]; + paintState.m_iScissorBottom = clipRect[3] - m_pSurfaceExtents[1]; + + SetupPaintState( paintState ); +} + +void CMatSystemSurface::PopMakeCurrent(VPANEL pPanel) +{ + //hushed MAT_FUNC; + + // draw any remaining text + if ( m_nBatchedCharVertCount > 0 ) + { + DrawFlushText(); + } + + int top = m_PaintStateStack.Count() - 1; + + // More pops that pushes? + Assert( top >= 0 ); + + // Didn't pop in reverse order of push? + Assert( m_PaintStateStack[top].m_pPanel == pPanel ); + + m_PaintStateStack.Remove(top); + + if (top > 0) + SetupPaintState( m_PaintStateStack[top-1] ); + +// m_iBoundTexture = -1; +} + + +//----------------------------------------------------------------------------- +// Color Setting methods +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawSetColor(int r, int g, int b, int a) +{ + Assert( g_bInDrawing ); + m_DrawColor[0]=(unsigned char)r; + m_DrawColor[1]=(unsigned char)g; + m_DrawColor[2]=(unsigned char)b; + m_DrawColor[3]=(unsigned char)(a * m_flAlphaMultiplier); +} + +void CMatSystemSurface::DrawSetColor(Color col) +{ + Assert( g_bInDrawing ); + DrawSetColor(col[0], col[1], col[2], col[3]); +} + + +//----------------------------------------------------------------------------- +// material Setting methods +//----------------------------------------------------------------------------- +void CMatSystemSurface::InternalSetMaterial( IMaterial *pMaterial ) +{ + if (!pMaterial) + { + pMaterial = m_pWhite; + } + + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + m_pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMaterial ); +} + + +//----------------------------------------------------------------------------- +// Helper method to initialize vertices (transforms them into screen space too) +//----------------------------------------------------------------------------- +void CMatSystemSurface::InitVertex( vgui::Vertex_t &vertex, int x, int y, float u, float v ) +{ + vertex.m_Position.Init( x + m_nTranslateX, y + m_nTranslateY ); + vertex.m_TexCoord.Init( u, v ); +} + + +//----------------------------------------------------------------------------- +// Draws a line! +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawTexturedLineInternal( const Vertex_t &a, const Vertex_t &b ) +{ + MAT_FUNC; + + Assert( !m_bIn3DPaintMode ); + + // Don't bother drawing fully transparent lines + if( m_DrawColor[3] == 0 ) + return; + + vgui::Vertex_t verts[2] = { a, b }; + + verts[0].m_Position.x += m_nTranslateX + g_flPixelOffsetX; + verts[0].m_Position.y += m_nTranslateY + g_flPixelOffsetY; + + verts[1].m_Position.x += m_nTranslateX + g_flPixelOffsetX; + verts[1].m_Position.y += m_nTranslateY + g_flPixelOffsetY; + + vgui::Vertex_t clippedVerts[2]; + + if (!ClipLine( verts, clippedVerts )) + return; + + meshBuilder.Begin( m_pMesh, MATERIAL_LINES, 1 ); + + meshBuilder.Position3f( clippedVerts[0].m_Position.x, clippedVerts[0].m_Position.y, m_flZPos ); + meshBuilder.Color4ubv( m_DrawColor ); + meshBuilder.TexCoord2fv( 0, clippedVerts[0].m_TexCoord.Base() ); + meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>(); + + meshBuilder.Position3f( clippedVerts[1].m_Position.x, clippedVerts[1].m_Position.y, m_flZPos ); + meshBuilder.Color4ubv( m_DrawColor ); + meshBuilder.TexCoord2fv( 0, clippedVerts[1].m_TexCoord.Base() ); + meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>(); + + meshBuilder.End(); + m_pMesh->Draw(); +} + +void CMatSystemSurface::DrawLine( int x0, int y0, int x1, int y1 ) +{ + MAT_FUNC; + + Assert( g_bInDrawing ); + + // Don't bother drawing fully transparent lines + if( m_DrawColor[3] == 0 ) + return; + + vgui::Vertex_t verts[2]; + verts[0].Init( Vector2D( x0, y0 ), Vector2D( 0, 0 ) ); + verts[1].Init( Vector2D( x1, y1 ), Vector2D( 1, 1 ) ); + + InternalSetMaterial( ); + DrawTexturedLineInternal( verts[0], verts[1] ); +} + + +void CMatSystemSurface::DrawTexturedLine( const Vertex_t &a, const Vertex_t &b ) +{ + IMaterial *pMaterial = TextureDictionary()->GetTextureMaterial(m_iBoundTexture); + InternalSetMaterial( pMaterial ); + DrawTexturedLineInternal( a, b ); +} + + +//----------------------------------------------------------------------------- +// Draws a line! +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawPolyLine( int *px, int *py ,int n ) +{ + MAT_FUNC; + + Assert( g_bInDrawing ); + + Assert( !m_bIn3DPaintMode ); + + // Don't bother drawing fully transparent lines + if( m_DrawColor[3] == 0 ) + return; + + InternalSetMaterial( ); + meshBuilder.Begin( m_pMesh, MATERIAL_LINES, n ); + + for ( int i = 0; i < n ; i++ ) + { + int inext = ( i + 1 ) % n; + + vgui::Vertex_t verts[2]; + vgui::Vertex_t clippedVerts[2]; + + int x0, y0, x1, y1; + + x0 = px[ i ]; + x1 = px[ inext ]; + y0 = py[ i ]; + y1 = py[ inext ]; + + InitVertex( verts[0], x0, y0, 0, 0 ); + InitVertex( verts[1], x1, y1, 1, 1 ); + + if (!ClipLine( verts, clippedVerts )) + continue; + + meshBuilder.Position3f( clippedVerts[0].m_Position.x+ g_flPixelOffsetX, clippedVerts[0].m_Position.y + g_flPixelOffsetY, m_flZPos ); + meshBuilder.Color4ubv( m_DrawColor ); + meshBuilder.TexCoord2fv( 0, clippedVerts[0].m_TexCoord.Base() ); + meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>(); + + meshBuilder.Position3f( clippedVerts[1].m_Position.x+ g_flPixelOffsetX, clippedVerts[1].m_Position.y + g_flPixelOffsetY, m_flZPos ); + meshBuilder.Color4ubv( m_DrawColor ); + meshBuilder.TexCoord2fv( 0, clippedVerts[1].m_TexCoord.Base() ); + meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>(); + } + + meshBuilder.End(); + m_pMesh->Draw(); +} + + +void CMatSystemSurface::DrawTexturedPolyLine( const vgui::Vertex_t *p,int n ) +{ + MAT_FUNC; + + int iPrev = n - 1; + for ( int i=0; i < n; i++ ) + { + DrawTexturedLine( p[iPrev], p[i] ); + iPrev = i; + } +} + + +//----------------------------------------------------------------------------- +// Draws a quad: +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawQuad( const vgui::Vertex_t &ul, const vgui::Vertex_t &lr, unsigned char *pColor ) +{ + MAT_FUNC; + + Assert( !m_bIn3DPaintMode ); + + if ( !m_pMesh ) + return; + + meshBuilder.Begin( m_pMesh, MATERIAL_QUADS, 1 ); + + meshBuilder.Position3f( ul.m_Position.x, ul.m_Position.y, m_flZPos ); + meshBuilder.Color4ubv( pColor ); + meshBuilder.TexCoord2f( 0, ul.m_TexCoord.x, ul.m_TexCoord.y ); + meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>(); + + meshBuilder.Position3f( lr.m_Position.x, ul.m_Position.y, m_flZPos ); + meshBuilder.Color4ubv( pColor ); + meshBuilder.TexCoord2f( 0, lr.m_TexCoord.x, ul.m_TexCoord.y ); + meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>(); + + meshBuilder.Position3f( lr.m_Position.x, lr.m_Position.y, m_flZPos ); + meshBuilder.Color4ubv( pColor ); + meshBuilder.TexCoord2f( 0, lr.m_TexCoord.x, lr.m_TexCoord.y ); + meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>(); + + meshBuilder.Position3f( ul.m_Position.x, lr.m_Position.y, m_flZPos ); + meshBuilder.Color4ubv( pColor ); + meshBuilder.TexCoord2f( 0, ul.m_TexCoord.x, lr.m_TexCoord.y ); + meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>(); + + meshBuilder.End(); + m_pMesh->Draw(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Draws an array of quads +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawQuadArray( int quadCount, vgui::Vertex_t *pVerts, unsigned char *pColor, bool bShouldClip ) +{ + MAT_FUNC; + + Assert( !m_bIn3DPaintMode ); + + if ( !m_pMesh ) + return; + + meshBuilder.Begin( m_pMesh, MATERIAL_QUADS, quadCount ); + + vgui::Vertex_t ulc; + vgui::Vertex_t lrc; + vgui::Vertex_t *pulc; + vgui::Vertex_t *plrc; + + if ( bShouldClip ) + { + for ( int i = 0; i < quadCount; ++i ) + { + PREFETCH360( &pVerts[ 2 * ( i + 1 ) ], 0 ); + + if ( !ClipRect( pVerts[2*i], pVerts[2*i + 1], &ulc, &lrc ) ) + { + continue; + } + pulc = &ulc; + plrc = &lrc; + + meshBuilder.Position3f( pulc->m_Position.x, pulc->m_Position.y, m_flZPos ); + meshBuilder.Color4ubv( pColor ); + meshBuilder.TexCoord2f( 0, pulc->m_TexCoord.x, pulc->m_TexCoord.y ); + meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>(); + + meshBuilder.Position3f( plrc->m_Position.x, pulc->m_Position.y, m_flZPos ); + meshBuilder.Color4ubv( pColor ); + meshBuilder.TexCoord2f( 0, plrc->m_TexCoord.x, pulc->m_TexCoord.y ); + meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>(); + + meshBuilder.Position3f( plrc->m_Position.x, plrc->m_Position.y, m_flZPos ); + meshBuilder.Color4ubv( pColor ); + meshBuilder.TexCoord2f( 0, plrc->m_TexCoord.x, plrc->m_TexCoord.y ); + meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>(); + + meshBuilder.Position3f( pulc->m_Position.x, plrc->m_Position.y, m_flZPos ); + meshBuilder.Color4ubv( pColor ); + meshBuilder.TexCoord2f( 0, pulc->m_TexCoord.x, plrc->m_TexCoord.y ); + meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>(); + } + } + else + { + for ( int i = 0; i < quadCount; ++i ) + { + PREFETCH360( &pVerts[ 2 * ( i + 1 ) ], 0 ); + + pulc = &pVerts[2*i]; + plrc = &pVerts[2*i + 1]; + + meshBuilder.Position3f( pulc->m_Position.x, pulc->m_Position.y, m_flZPos ); + meshBuilder.Color4ubv( pColor ); + meshBuilder.TexCoord2f( 0, pulc->m_TexCoord.x, pulc->m_TexCoord.y ); + meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>(); + + meshBuilder.Position3f( plrc->m_Position.x, pulc->m_Position.y, m_flZPos ); + meshBuilder.Color4ubv( pColor ); + meshBuilder.TexCoord2f( 0, plrc->m_TexCoord.x, pulc->m_TexCoord.y ); + meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>(); + + meshBuilder.Position3f( plrc->m_Position.x, plrc->m_Position.y, m_flZPos ); + meshBuilder.Color4ubv( pColor ); + meshBuilder.TexCoord2f( 0, plrc->m_TexCoord.x, plrc->m_TexCoord.y ); + meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>(); + + meshBuilder.Position3f( pulc->m_Position.x, plrc->m_Position.y, m_flZPos ); + meshBuilder.Color4ubv( pColor ); + meshBuilder.TexCoord2f( 0, pulc->m_TexCoord.x, plrc->m_TexCoord.y ); + meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>(); + } + } + + meshBuilder.End(); + m_pMesh->Draw(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Draws a rectangle colored with the current drawcolor +// using the white material +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawFilledRect( int x0, int y0, int x1, int y1 ) +{ + MAT_FUNC; + + Assert( g_bInDrawing ); + + // Don't even bother drawing fully transparent junk + if( m_DrawColor[3]!=0 ) + { + vgui::Vertex_t rect[2]; + vgui::Vertex_t clippedRect[2]; + InitVertex( rect[0], x0, y0, 0, 0 ); + InitVertex( rect[1], x1, y1, 0, 0 ); + + // Fully clipped? + if ( !ClipRect(rect[0], rect[1], &clippedRect[0], &clippedRect[1]) ) + return; + + InternalSetMaterial(); + DrawQuad( clippedRect[0], clippedRect[1], m_DrawColor ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Draws an array of rectangles colored with the current drawcolor +// using the white material +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawFilledRectArray( IntRect *pRects, int numRects ) +{ + MAT_FUNC; + + Assert( g_bInDrawing ); + + // Don't even bother drawing fully transparent junk + if( m_DrawColor[3]==0 ) + return; + + if ( !m_pMesh ) + return; + + InternalSetMaterial( ); + + meshBuilder.Begin( m_pMesh, MATERIAL_QUADS, numRects ); + + for (int i = 0; i < numRects; ++i ) + { + vgui::Vertex_t rect[2]; + vgui::Vertex_t clippedRect[2]; + InitVertex( rect[0], pRects[i].x0, pRects[i].y0, 0, 0 ); + InitVertex( rect[1], pRects[i].x1, pRects[i].y1, 0, 0 ); + + ClipRect( rect[0], rect[1], &clippedRect[0], &clippedRect[1] ); + + vgui::Vertex_t &ul = clippedRect[0]; + vgui::Vertex_t &lr = clippedRect[1]; + + meshBuilder.Position3f( ul.m_Position.x, ul.m_Position.y, m_flZPos ); + meshBuilder.Color4ubv( m_DrawColor ); + meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 0>(); + + meshBuilder.Position3f( lr.m_Position.x, ul.m_Position.y, m_flZPos ); + meshBuilder.Color4ubv( m_DrawColor ); + meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 0>(); + + meshBuilder.Position3f( lr.m_Position.x, lr.m_Position.y, m_flZPos ); + meshBuilder.Color4ubv( m_DrawColor ); + meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 0>(); + + meshBuilder.Position3f( ul.m_Position.x, lr.m_Position.y, m_flZPos ); + meshBuilder.Color4ubv( m_DrawColor ); + meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 0>(); + } + + meshBuilder.End(); + m_pMesh->Draw(); +} + +//----------------------------------------------------------------------------- +// Draws a fade between the fadeStartPt and fadeEndPT with the current draw color oriented according to argument +// Example: DrawFilledRectFastFade( 10, 10, 100, 20, 50, 60, 255, 128, true ); +// -this will draw +// a solid rect (10,10,50,20) //alpha 255 +// a solid rect (50,10,60,20) //alpha faded from 255 to 128 +// a solid rect (60,10,100,20) //alpha 128 +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawFilledRectFastFade( int x0, int y0, int x1, int y1, int fadeStartPt, int fadeEndPt, unsigned int alpha0, unsigned int alpha1, bool bHorizontal ) +{ + if( bHorizontal ) + { + if( alpha0 ) + { + DrawSetColor( m_DrawColor[0], m_DrawColor[1], m_DrawColor[2], alpha0 ); + DrawFilledRect( x0, y0, fadeStartPt, y1 ); + } + DrawFilledRectFade( fadeStartPt, y0, fadeEndPt, y1, alpha0, alpha1, true ); + if( alpha1 ) + { + DrawSetColor( m_DrawColor[0], m_DrawColor[1], m_DrawColor[2], alpha1 ); + DrawFilledRect( fadeEndPt, y0, x1, y1 ); + } + } + else + { + if( alpha0 ) + { + DrawSetColor( m_DrawColor[0], m_DrawColor[1], m_DrawColor[2], alpha0 ); + DrawFilledRect( x0, y0, x1, fadeStartPt ); + } + DrawFilledRectFade( x0, fadeStartPt, x1, fadeEndPt, alpha0, alpha1, false ); + if( alpha1 ) + { + DrawSetColor( m_DrawColor[0], m_DrawColor[1], m_DrawColor[2], alpha1 ); + DrawFilledRect( x0, fadeEndPt, x1, y1 ); + } + } +} + +//----------------------------------------------------------------------------- +// Draws a fade with the current draw color oriented according to argument +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawFilledRectFade( int x0, int y0, int x1, int y1, unsigned int alpha0, unsigned int alpha1, bool bHorizontal ) +{ + MAT_FUNC; + + Assert( g_bInDrawing ); + + // Scale the desired alphas by the surface alpha + float alphaScale = m_DrawColor[3] / 255.f; + alpha0 *= alphaScale; + alpha1 *= alphaScale; + + // Don't even bother drawing fully transparent junk + if ( alpha0 == 0 && alpha1 == 0 ) + return; + + vgui::Vertex_t rect[2]; + vgui::Vertex_t clippedRect[2]; + InitVertex( rect[0], x0, y0, 0, 0 ); + InitVertex( rect[1], x1, y1, 0, 0 ); + + // Fully clipped? + if ( !ClipRect(rect[0], rect[1], &clippedRect[0], &clippedRect[1]) ) + return; + + InternalSetMaterial(); + + unsigned char colors[4][4] = {{0}}; + for ( int i=0; i<4; i++ ) + { + // copy the rgb and leave the alpha at zero + Q_memcpy( colors[i], m_DrawColor, 3 ); + } + + unsigned char nAlpha0 = (alpha0 & 0xFF); + unsigned char nAlpha1 = (alpha1 & 0xFF); + + if ( bHorizontal ) + { + // horizontal fade + colors[0][3] = nAlpha0; + colors[1][3] = nAlpha1; + colors[2][3] = nAlpha1; + colors[3][3] = nAlpha0; + } + else + { + // vertical fade + colors[0][3] = nAlpha0; + colors[1][3] = nAlpha0; + colors[2][3] = nAlpha1; + colors[3][3] = nAlpha1; + } + + meshBuilder.Begin( m_pMesh, MATERIAL_QUADS, 1 ); + + meshBuilder.Position3f( clippedRect[0].m_Position.x, clippedRect[0].m_Position.y, m_flZPos ); + meshBuilder.Color4ubv( colors[0] ); + meshBuilder.TexCoord2f( 0, clippedRect[0].m_TexCoord.x, clippedRect[0].m_TexCoord.y ); + meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>(); + + meshBuilder.Position3f( clippedRect[1].m_Position.x, clippedRect[0].m_Position.y, m_flZPos ); + meshBuilder.Color4ubv( colors[1] ); + meshBuilder.TexCoord2f( 0, clippedRect[1].m_TexCoord.x, clippedRect[0].m_TexCoord.y ); + meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>(); + + meshBuilder.Position3f( clippedRect[1].m_Position.x, clippedRect[1].m_Position.y, m_flZPos ); + meshBuilder.Color4ubv( colors[2] ); + meshBuilder.TexCoord2f( 0, clippedRect[1].m_TexCoord.x, clippedRect[1].m_TexCoord.y ); + meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>(); + + meshBuilder.Position3f( clippedRect[0].m_Position.x, clippedRect[1].m_Position.y, m_flZPos ); + meshBuilder.Color4ubv( colors[3] ); + meshBuilder.TexCoord2f( 0, clippedRect[0].m_TexCoord.x, clippedRect[1].m_TexCoord.y ); + meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>(); + + meshBuilder.End(); + m_pMesh->Draw(); +} + +//----------------------------------------------------------------------------- +// Purpose: Draws an unfilled rectangle in the current drawcolor +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawOutlinedRect(int x0,int y0,int x1,int y1) +{ + MAT_FUNC; + + // Don't even bother drawing fully transparent junk + if ( m_DrawColor[3] == 0 ) + return; + + DrawFilledRect(x0,y0,x1,y0+1); //top + DrawFilledRect(x0,y1-1,x1,y1); //bottom + DrawFilledRect(x0,y0+1,x0+1,y1-1); //left + DrawFilledRect(x1-1,y0+1,x1,y1-1); //right +} + + +//----------------------------------------------------------------------------- +// Purpose: Draws an outlined circle in the current drawcolor +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawOutlinedCircle(int x, int y, int radius, int segments) +{ + MAT_FUNC; + + Assert( g_bInDrawing ); + + Assert( !m_bIn3DPaintMode ); + + // Don't even bother drawing fully transparent junk + if( m_DrawColor[3]==0 ) + return; + + // NOTE: Gotta use lines instead of linelist or lineloop due to clipping + InternalSetMaterial( ); + meshBuilder.Begin( m_pMesh, MATERIAL_LINES, segments ); + + vgui::Vertex_t renderVertex[2]; + vgui::Vertex_t vertex[2]; + vertex[0].m_Position.Init( m_nTranslateX + x + radius, m_nTranslateY + y ); + vertex[0].m_TexCoord.Init( 1.0f, 0.5f ); + + float invDelta = 2.0f * M_PI / segments; + for ( int i = 1; i <= segments; ++i ) + { + float flRadians = i * invDelta; + float ca = cos( flRadians ); + float sa = sin( flRadians ); + + // Rotate it around the circle + vertex[1].m_Position.x = m_nTranslateX + x + (radius * ca); + vertex[1].m_Position.y = m_nTranslateY + y + (radius * sa); + vertex[1].m_TexCoord.x = 0.5f * (ca + 1.0f); + vertex[1].m_TexCoord.y = 0.5f * (sa + 1.0f); + + if (ClipLine( vertex, renderVertex )) + { + meshBuilder.Position3f( renderVertex[0].m_Position.x, renderVertex[0].m_Position.y, m_flZPos ); + meshBuilder.Color4ubv( m_DrawColor ); + meshBuilder.TexCoord2fv( 0, renderVertex[0].m_TexCoord.Base() ); + meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>(); + + meshBuilder.Position3f( renderVertex[1].m_Position.x, renderVertex[1].m_Position.y, m_flZPos ); + meshBuilder.Color4ubv( m_DrawColor ); + meshBuilder.TexCoord2fv( 0, renderVertex[1].m_TexCoord.Base() ); + meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>(); + } + + vertex[0].m_Position = vertex[1].m_Position; + vertex[0].m_TexCoord = vertex[1].m_TexCoord; + } + + meshBuilder.End(); + m_pMesh->Draw(); +} + + +//----------------------------------------------------------------------------- +// Loads a particular texture (material) +//----------------------------------------------------------------------------- +int CMatSystemSurface::CreateNewTextureID( bool procedural /*=false*/ ) +{ + return TextureDictionary()->CreateTexture( procedural ); +} + +void CMatSystemSurface::DestroyTextureID( int id ) +{ + TextureDictionary()->DestroyTexture( id ); +} + +bool CMatSystemSurface::DeleteTextureByID(int id) +{ + TextureDictionary()->DestroyTexture( id ); + return false; +} + +#ifdef _X360 +void CMatSystemSurface::UncacheUnusedMaterials() +{ + // unbind any currently set texture (which may be uncached) + DrawSetTexture( -1 ); + + // X360TBD: Need to only destroy "marked" textures +} +#endif + +//----------------------------------------------------------------------------- +// Purpose: +// Input : id - +// *filename - +// maxlen - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CMatSystemSurface::DrawGetTextureFile(int id, char *filename, int maxlen ) +{ + if ( !TextureDictionary()->IsValidId( id ) ) + return false; + + IMaterial *texture = TextureDictionary()->GetTextureMaterial(id); + if ( !texture ) + return false; + + Q_strncpy( filename, texture->GetName(), maxlen ); + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : id - texture id +// Output : returns IMaterial for the referenced texture +//----------------------------------------------------------------------------- +IVguiMatInfo *CMatSystemSurface::DrawGetTextureMatInfoFactory(int id) +{ + if ( !TextureDictionary()->IsValidId( id ) ) + return NULL; + + IMaterial *texture = TextureDictionary()->GetTextureMaterial(id); + + if ( texture == NULL ) + return NULL; + + return new CVguiMatInfo(texture); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *filename - +// Output : int +//----------------------------------------------------------------------------- +int CMatSystemSurface::DrawGetTextureId( char const *filename ) +{ + return TextureDictionary()->FindTextureIdForTextureFile( filename ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pTexture +// Output : int +//----------------------------------------------------------------------------- +int CMatSystemSurface::DrawGetTextureId( ITexture *pTexture ) +{ + return TextureDictionary()->CreateTextureByTexture( pTexture ); +} + + +//----------------------------------------------------------------------------- +// Associates a texture with a material file (also binds it) +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawSetTextureFile(int id, const char *pFileName, int hardwareFilter, bool forceReload /*= false*/) +{ + TextureDictionary()->BindTextureToFile( id, pFileName ); + DrawSetTexture( id ); +} + + +//----------------------------------------------------------------------------- +// Associates a texture with a material file (also binds it) +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawSetTextureMaterial(int id, IMaterial *pMaterial) +{ + TextureDictionary()->BindTextureToMaterial( id, pMaterial ); + DrawSetTexture( id ); +} + +IMaterial *CMatSystemSurface::DrawGetTextureMaterial( int id ) +{ + return TextureDictionary()->GetTextureMaterial( id ); +} + + +void CMatSystemSurface::ReferenceProceduralMaterial( int id, int referenceId, IMaterial *pMaterial ) +{ + TextureDictionary()->BindTextureToMaterialReference( id, referenceId, pMaterial ); +} + + +//----------------------------------------------------------------------------- +// Binds a texture +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawSetTexture( int id ) +{ + // if we're switching textures, flush any batched text + if ( id != m_iBoundTexture ) + { + DrawFlushText(); + m_iBoundTexture = id; + + if ( IsX360() && id == -1 ) + { + // ensure we unbind current material that may go away + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + pRenderContext->Bind( m_pWhite ); + } + } +} + + +//----------------------------------------------------------------------------- +// Returns texture size +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawGetTextureSize(int id, int &iWide, int &iTall) +{ + TextureDictionary()->GetTextureSize( id, iWide, iTall ); +} + + +//----------------------------------------------------------------------------- +// Draws a textured rectangle +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawTexturedRect( int x0, int y0, int x1, int y1 ) +{ + MAT_FUNC; + + Assert( g_bInDrawing ); + + // Don't even bother drawing fully transparent junk + if( m_DrawColor[3] == 0 ) + return; + + float s0, t0, s1, t1; + TextureDictionary()->GetTextureTexCoords( m_iBoundTexture, s0, t0, s1, t1 ); + + vgui::Vertex_t rect[2]; + vgui::Vertex_t clippedRect[2]; + InitVertex( rect[0], x0, y0, s0, t0 ); + InitVertex( rect[1], x1, y1, s1, t1 ); + + // Fully clipped? + if ( !ClipRect(rect[0], rect[1], &clippedRect[0], &clippedRect[1]) ) + return; + + IMaterial *pMaterial = TextureDictionary()->GetTextureMaterial(m_iBoundTexture); + InternalSetMaterial( pMaterial ); + DrawQuad( clippedRect[0], clippedRect[1], m_DrawColor ); +} + +//----------------------------------------------------------------------------- +// Draws a textured rectangle +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawTexturedSubRect( int x0, int y0, int x1, int y1, float texs0, float text0, float texs1, float text1 ) +{ + MAT_FUNC; + + Assert( g_bInDrawing ); + + // Don't even bother drawing fully transparent junk + if( m_DrawColor[3] == 0 ) + return; + + float s0, t0, s1, t1; + TextureDictionary()->GetTextureTexCoords( m_iBoundTexture, s0, t0, s1, t1 ); + + float ssize = s1 - s0; + float tsize = t1 - t0; + + // Rescale tex values into range of s0 to s1 ,etc. + texs0 = s0 + texs0 * ( ssize ); + texs1 = s0 + texs1 * ( ssize ); + text0 = t0 + text0 * ( tsize ); + text1 = t0 + text1 * ( tsize ); + + vgui::Vertex_t rect[2]; + vgui::Vertex_t clippedRect[2]; + InitVertex( rect[0], x0, y0, texs0, text0 ); + InitVertex( rect[1], x1, y1, texs1, text1 ); + + // Fully clipped? + if ( !ClipRect(rect[0], rect[1], &clippedRect[0], &clippedRect[1]) ) + return; + + IMaterial *pMaterial = TextureDictionary()->GetTextureMaterial(m_iBoundTexture); + InternalSetMaterial( pMaterial ); + DrawQuad( clippedRect[0], clippedRect[1], m_DrawColor ); +} + +//----------------------------------------------------------------------------- +// Draws a textured polygon +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawTexturedPolygon(int n, Vertex_t *pVertices, bool bClipVertices /*= true*/ ) +{ + MAT_FUNC; + + Assert( !m_bIn3DPaintMode ); + + Assert( g_bInDrawing ); + + // Don't even bother drawing fully transparent junk + if( (n == 0) || (m_DrawColor[3]==0) ) + return; + + if ( bClipVertices ) + { + int iCount; + Vertex_t **ppClippedVerts = NULL; + iCount = ClipPolygon( n, pVertices, m_nTranslateX, m_nTranslateY, &ppClippedVerts ); + if (iCount <= 0) + return; + + IMaterial *pMaterial = TextureDictionary()->GetTextureMaterial(m_iBoundTexture); + InternalSetMaterial( pMaterial ); + + meshBuilder.Begin( m_pMesh, MATERIAL_POLYGON, iCount ); + + for (int i = 0; i < iCount; ++i) + { + meshBuilder.Position3f( ppClippedVerts[i]->m_Position.x, ppClippedVerts[i]->m_Position.y, m_flZPos ); + meshBuilder.Color4ubv( m_DrawColor ); + meshBuilder.TexCoord2fv( 0, ppClippedVerts[i]->m_TexCoord.Base() ); + meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>(); + } + + meshBuilder.End(); + m_pMesh->Draw(); + } + else + { + IMaterial *pMaterial = TextureDictionary()->GetTextureMaterial(m_iBoundTexture); + InternalSetMaterial( pMaterial ); + + meshBuilder.Begin( m_pMesh, MATERIAL_POLYGON, n ); + + for (int i = 0; i < n; ++i) + { + meshBuilder.Position3f( pVertices[i].m_Position.x + m_nTranslateX, pVertices[i].m_Position.y + m_nTranslateY, m_flZPos ); + meshBuilder.Color4ubv( m_DrawColor ); + meshBuilder.TexCoord2fv( 0, pVertices[i].m_TexCoord.Base() ); + meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>(); + } + + meshBuilder.End(); + m_pMesh->Draw(); + } +} + + + +//----------------------------------------------------------------------------- +// +// Font-related methods begin here +// +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// Purpose: creates a new empty font +//----------------------------------------------------------------------------- +HFont CMatSystemSurface::CreateFont() +{ + MAT_FUNC; + + return FontManager().CreateFont(); +} + +//----------------------------------------------------------------------------- +// Purpose: adds glyphs to a font created by CreateFont() +//----------------------------------------------------------------------------- +bool CMatSystemSurface::SetFontGlyphSet(HFont font, const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags, int nRangeMin, int nRangeMax) +{ + return FontManager().SetFontGlyphSet(font, windowsFontName, tall, weight, blur, scanlines, flags, nRangeMin, nRangeMax); +} + +//----------------------------------------------------------------------------- +// Purpose: adds glyphs to a font created by CreateFont() +//----------------------------------------------------------------------------- +bool CMatSystemSurface::SetBitmapFontGlyphSet(HFont font, const char *windowsFontName, float scalex, float scaley, int flags) +{ + return FontManager().SetBitmapFontGlyphSet(font, windowsFontName, scalex, scaley, flags); +} + +//----------------------------------------------------------------------------- +// Purpose: returns the max height of a font +//----------------------------------------------------------------------------- +int CMatSystemSurface::GetFontTall(HFont font) +{ + return FontManager().GetFontTall(font); +} + +//----------------------------------------------------------------------------- +// Purpose: returns the requested height of a font +//----------------------------------------------------------------------------- +int CMatSystemSurface::GetFontTallRequested(HFont font) +{ + return FontManager().GetFontTallRequested(font); +} + +//----------------------------------------------------------------------------- +// Purpose: returns the max height of a font +//----------------------------------------------------------------------------- +int CMatSystemSurface::GetFontAscent(HFont font, wchar_t wch) +{ + return FontManager().GetFontAscent(font,wch); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : font - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CMatSystemSurface::IsFontAdditive(HFont font) +{ + return FontManager().IsFontAdditive(font); +} + +//----------------------------------------------------------------------------- +// Purpose: returns the abc widths of a single character +//----------------------------------------------------------------------------- +void CMatSystemSurface::GetCharABCwide(HFont font, int ch, int &a, int &b, int &c) +{ + FontManager().GetCharABCwide(font, ch, a, b, c); +} + +//----------------------------------------------------------------------------- +// Purpose: returns the pixel width of a single character +//----------------------------------------------------------------------------- +int CMatSystemSurface::GetCharacterWidth(HFont font, int ch) +{ + return FontManager().GetCharacterWidth(font, ch); +} + +//----------------------------------------------------------------------------- +// Purpose: returns the kerned width of this char +//----------------------------------------------------------------------------- +void CMatSystemSurface::GetKernedCharWidth( HFont font, wchar_t ch, wchar_t chBefore, wchar_t chAfter, float &wide, float &abcA ) //, float &abcC ) +{ + float abcC = 0.0f; + FontManager().GetKernedCharWidth(font, ch, chBefore, chAfter, wide, abcA, abcC ); +} + + +//----------------------------------------------------------------------------- +// Purpose: returns the area of a text string, including newlines +//----------------------------------------------------------------------------- +void CMatSystemSurface::GetTextSize(HFont font, const wchar_t *text, int &wide, int &tall) +{ + FontManager().GetTextSize(font, text, wide, tall); +} + +//----------------------------------------------------------------------------- +// Purpose: adds a custom font file (only supports true type font files (.ttf) for now) +//----------------------------------------------------------------------------- +bool CMatSystemSurface::AddCustomFontFile( const char *fontName, const char *fontFileName ) +{ + if ( IsX360() ) + { + // custom fonts are not supported (not needed) on xbox, all .vfonts are offline converted to ttfs + // ttfs are mounted/handled elsewhere + return true; + } + MAT_FUNC; + + char fullPath[MAX_PATH]; + bool bFound = false; + // windows needs an absolute path for ttf + bFound = g_pFullFileSystem->GetLocalPath( fontFileName, fullPath, sizeof( fullPath ) ); + if ( !bFound ) + { + Warning( "Couldn't find custom font file '%s'\n", fontFileName ); + return false; + } + + // only add if it's not already in the list + Q_strlower( fullPath ); + CUtlSymbol sym(fullPath); + int i; + for ( i = 0; i < m_CustomFontFileNames.Count(); i++ ) + { + if ( m_CustomFontFileNames[i] == sym ) + break; + } + if ( !m_CustomFontFileNames.IsValidIndex( i ) ) + { + m_CustomFontFileNames.AddToTail( fullPath ); + + if ( IsPC() ) + { + // make sure it's on disk + // only do this once for each font since in steam it will overwrite the + // registered font file, causing windows to invalidate the font + g_pFullFileSystem->GetLocalCopy( fullPath ); + } + } + + // try and use the optimal custom font loader, will makes sure fonts are unloaded properly + // this function is in a newer version of the gdi library (win2k+), so need to try get it directly +#if defined( WIN32 ) && !defined( _X360 ) + bool successfullyAdded = false; + HMODULE gdiModule = ::LoadLibrary("gdi32.dll"); + if (gdiModule) + { + typedef int (WINAPI *AddFontResourceExProc)(LPCTSTR, DWORD, PVOID); + AddFontResourceExProc pAddFontResourceEx = (AddFontResourceExProc)::GetProcAddress(gdiModule, "AddFontResourceExA"); + if (pAddFontResourceEx) + { + int result = (*pAddFontResourceEx)(fullPath, 0x10, NULL); + if (result > 0) + { + successfullyAdded = true; + } + } + ::FreeLibrary(gdiModule); + } + + // add to windows + bool success = successfullyAdded || (::AddFontResource(fullPath) > 0); + if ( !success ) + { + Msg( "Failed to load custom font file '%s'\n", fullPath ); + } + Assert( success ); + return success; +#elif OSX + + FSRef ref; + OSStatus err = FSPathMakeRef( (const UInt8*)fullPath, &ref, NULL ); + if ( err == noErr ) + err = ATSFontActivateFromFileReference( &ref, kATSFontContextLocal, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault, NULL ); + + return err == noErr; + +#elif LINUX + + int size; + if ( CMatSystemSurface::FontDataHelper( fontName, size, fontFileName ) ) + return true; + return false; + +#elif defined( _X360 ) +#include "xbox/xbox_win32stubs.h" +#else +#error +#endif +} + +#ifdef LINUX + +static void RemoveSpaces( CUtlString &str ) +{ + char *dst = str.GetForModify(); + + for( int i = 0; i < str.Length(); i++ ) + { + if( ( str[ i ] != ' ' ) && ( str[ i ] != '-' ) ) + { + *dst++ = str[ i ]; + } + } + + *dst = 0; +} + +void *CMatSystemSurface::FontDataHelper( const char *pchFontName, int &size, const char *fontFileName ) +{ + size = 0; + + if( fontFileName ) + { + // If we were given a fontFileName, then load that bugger and shove it in the cache. + + // Just load the font data, decrypt in memory and register for this process + CUtlBuffer buf; + if ( !g_pFullFileSystem->ReadFile( fontFileName, NULL, buf ) ) + { + Msg( "Failed to load custom font file '%s'\n", fontFileName ); + return NULL; + } + + FT_Face face; + const FT_Error error = FT_New_Memory_Face( FontManager().GetFontLibraryHandle(), (FT_Byte *)buf.Base(), buf.TellPut(), 0, &face ); + + if ( error ) + { + // FT_Err_Unknown_File_Format, etc. + Msg( "ERROR %d: UNABLE TO LOAD FONT FILE %s\n", error, fontFileName ); + return NULL; + } + + if( !pchFontName ) + { + // If we weren't passed a font name for this thing, then use the one from the face. + pchFontName = face->family_name; + if ( !pchFontName || !pchFontName[ 0 ] ) + { + pchFontName = FT_Get_Postscript_Name( face ); + } + } + + // Replace spaces and dashes with underscores. + CUtlString strFontName( pchFontName ); + RemoveSpaces( strFontName ); + + font_entry entry; + entry.size = buf.TellPut(); + entry.data = malloc( entry.size ); + memcpy( entry.data, buf.Base(), entry.size ); + m_FontData.Insert( strFontName.Get(), entry ); + + FT_Done_Face( face ); + + size = entry.size; + return entry.data; + } + else + { + // Replace spaces and dashes with underscores. + CUtlString strFontName( pchFontName ); + RemoveSpaces( strFontName ); + + int iIndex = m_FontData.Find( strFontName.Get() ); + if ( iIndex != m_FontData.InvalidIndex() ) + { + size = m_FontData[ iIndex ].size; + return m_FontData[ iIndex ].data; + } + } + + return NULL; +} + +#endif // LINUX + +//----------------------------------------------------------------------------- +// Purpose: adds a bitmap font file +//----------------------------------------------------------------------------- +bool CMatSystemSurface::AddBitmapFontFile( const char *fontFileName ) +{ + MAT_FUNC; + + bool bFound = false; + bFound = ( ( g_pFullFileSystem->GetDVDMode() == DVDMODE_STRICT ) || g_pFullFileSystem->FileExists( fontFileName, IsX360() ? "GAME" : NULL ) ); + if ( !bFound ) + { + Msg( "Couldn't find bitmap font file '%s'\n", fontFileName ); + return false; + } + char path[MAX_PATH]; + Q_strncpy( path, fontFileName, MAX_PATH ); + + // only add if it's not already in the list + Q_strlower( path ); + CUtlSymbol sym( path ); + int i; + for ( i = 0; i < m_BitmapFontFileNames.Count(); i++ ) + { + if ( m_BitmapFontFileNames[i] == sym ) + break; + } + if ( !m_BitmapFontFileNames.IsValidIndex( i ) ) + { + m_BitmapFontFileNames.AddToTail( path ); + + if ( IsPC() ) + { + // make sure it's on disk + // only do this once for each font since in steam it will overwrite the + // registered font file, causing windows to invalidate the font + g_pFullFileSystem->GetLocalCopy( path ); + } + } + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMatSystemSurface::SetBitmapFontName( const char *pName, const char *pFontFilename ) +{ + char fontPath[MAX_PATH]; + Q_strncpy( fontPath, pFontFilename, MAX_PATH ); + Q_strlower( fontPath ); + + CUtlSymbol sym( fontPath ); + int i; + for (i = 0; i < m_BitmapFontFileNames.Count(); i++) + { + if ( m_BitmapFontFileNames[i] == sym ) + { + // found it, update the mapping + int index = m_BitmapFontFileMapping.Find( pName ); + if ( !m_BitmapFontFileMapping.IsValidIndex( index ) ) + { + index = m_BitmapFontFileMapping.Insert( pName ); + } + m_BitmapFontFileMapping.Element( index ) = i; + break; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +const char *CMatSystemSurface::GetBitmapFontName( const char *pName ) +{ + // find it in the mapping symbol table + int index = m_BitmapFontFileMapping.Find( pName ); + if ( index == m_BitmapFontFileMapping.InvalidIndex() ) + { + return ""; + } + + return m_BitmapFontFileNames[m_BitmapFontFileMapping.Element( index )].String(); +} + +void CMatSystemSurface::ClearTemporaryFontCache( void ) +{ + FontManager().ClearTemporaryFontCache(); +} + +//----------------------------------------------------------------------------- +// Purpose: Force a set of characters to be rendered into the font page. +//----------------------------------------------------------------------------- +void CMatSystemSurface::PrecacheFontCharacters( HFont font, const wchar_t *pCharacterString ) +{ + wchar_t *pCommonChars = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,.!:-/%"; + MAT_FUNC; + + if ( !pCharacterString || !pCharacterString[0] ) + { + // use the common chars, alternate languages are not handled + pCharacterString = pCommonChars; + } + + StartDrawing(); + DrawSetTextFont( font ); + + int numChars = 0; + while( pCharacterString[ numChars ] ) + { + numChars++; + } + int *pTextureIDs_ignored = (int *)_alloca( numChars*sizeof( int ) ); + float **pTexCoords_ignored = (float **)_alloca( numChars*sizeof( float * ) ); + g_FontTextureCache.GetTextureForChars( m_hCurrentFont, FONT_DRAW_DEFAULT, pCharacterString, pTextureIDs_ignored, pTexCoords_ignored, numChars ); + + FinishDrawing(); +} + +const char *CMatSystemSurface::GetFontName( HFont font ) +{ + return FontManager().GetFontName( font ); +} + +const char *CMatSystemSurface::GetFontFamilyName( HFont font ) +{ + return FontManager().GetFontFamilyName( font ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawSetTextFont(HFont font) +{ + Assert( g_bInDrawing ); + + m_hCurrentFont = font; +} + +//----------------------------------------------------------------------------- +// Purpose: Renders any batched up text +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawFlushText() +{ + if ( !m_nBatchedCharVertCount ) + return; + + { + // don't log entry unless actual work happens.. + MAT_FUNC; + + IMaterial *pMaterial = TextureDictionary()->GetTextureMaterial(m_iBoundTexture); + InternalSetMaterial( pMaterial ); + DrawQuadArray( m_nBatchedCharVertCount / 2, m_BatchedCharVerts, m_DrawTextColor ); + m_nBatchedCharVertCount = 0; + } +} + +//----------------------------------------------------------------------------- +// Sets the text color +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawSetTextColor(int r, int g, int b, int a) +{ + int adjustedAlpha = (a * m_flAlphaMultiplier); + + if ( r != m_DrawTextColor[0] || g != m_DrawTextColor[1] || b != m_DrawTextColor[2] || adjustedAlpha != m_DrawTextColor[3] ) + { + // text color changed, flush any existing text + DrawFlushText(); + + m_DrawTextColor[0] = (unsigned char)r; + m_DrawTextColor[1] = (unsigned char)g; + m_DrawTextColor[2] = (unsigned char)b; + m_DrawTextColor[3] = (unsigned char)adjustedAlpha; + } +} + +//----------------------------------------------------------------------------- +// Purpose: alternate color set +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawSetTextColor(Color col) +{ + DrawSetTextColor(col[0], col[1], col[2], col[3]); +} + +//----------------------------------------------------------------------------- +// Purpose: change the scale of a bitmap font +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawSetTextScale(float sx, float sy) +{ + FontManager().SetFontScale( m_hCurrentFont, sx, sy ); +} + +//----------------------------------------------------------------------------- +// Text rendering location +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawSetTextPos(int x, int y) +{ + Assert( g_bInDrawing ); + + m_pDrawTextPos[0] = x; + m_pDrawTextPos[1] = y; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawGetTextPos(int& x,int& y) +{ + Assert( g_bInDrawing ); + + x = m_pDrawTextPos[0]; + y = m_pDrawTextPos[1]; +} + +#pragma warning( disable : 4706 ) +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawUnicodeString( const wchar_t *pString, FontDrawType_t drawType /*= FONT_DRAW_DEFAULT */ ) +{ + // skip fully transparent characters + if ( m_DrawTextColor[3] == 0 ) + return; + + //hushed MAT_FUNC; +#ifdef POSIX + DrawPrintText( pString, V_wcslen( pString ) , drawType ); +#else + wchar_t ch; + + while ( ( ch = *pString++ ) ) + { + DrawUnicodeChar( ch ); + } +#endif +} +#pragma warning( default : 4706 ) + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawUnicodeChar(wchar_t ch, FontDrawType_t drawType /*= FONT_DRAW_DEFAULT */ ) +{ + // skip fully transparent characters + if ( m_DrawTextColor[3] == 0 ) + return; + //hushed MAT_FUNC; + + CharRenderInfo info; + info.drawType = drawType; + if ( DrawGetUnicodeCharRenderInfo( ch, info ) ) + { + DrawRenderCharFromInfo( info ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CMatSystemSurface::DrawGetUnicodeCharRenderInfo( wchar_t ch, CharRenderInfo& info ) +{ + //hushed MAT_FUNC; + + Assert( g_bInDrawing ); + info.valid = false; + + if ( !m_hCurrentFont ) + { + return info.valid; + } + + PREFETCH360( &m_BatchedCharVerts[ m_nBatchedCharVertCount ], 0 ); + + info.valid = true; + info.ch = ch; + DrawGetTextPos(info.x, info.y); + + info.currentFont = m_hCurrentFont; + info.fontTall = GetFontTall(m_hCurrentFont); + + GetCharABCwide(m_hCurrentFont, ch, info.abcA, info.abcB, info.abcC); + bool bUnderlined = FontManager().GetFontUnderlined( m_hCurrentFont ); + + // Do prestep before generating texture coordinates, etc. + if ( !bUnderlined ) + { + info.x += info.abcA; + } + + // get the character texture from the cache + info.textureId = 0; + float *texCoords = NULL; + if (!g_FontTextureCache.GetTextureForChar(m_hCurrentFont, info.drawType, ch, &info.textureId, &texCoords)) + { + info.valid = false; + return info.valid; + } + + int fontWide = info.abcB; + if ( bUnderlined ) + { + fontWide += ( info.abcA + info.abcC ); + info.x-= info.abcA; + } + + // Because CharRenderInfo has a pointer to the verts, we need to keep m_BatchedCharVerts in sync, so if we + // will be flushing the text when we get to this char, flush it now instead. + if ( info.textureId != m_iBoundTexture ) + { + DrawFlushText(); + } + + // This avoid copying the data in the nonclipped case!!! (X360) + info.verts = &m_BatchedCharVerts[ m_nBatchedCharVertCount ]; + InitVertex( info.verts[0], info.x, info.y, texCoords[0], texCoords[1] ); + InitVertex( info.verts[1], info.x + fontWide, info.y + info.fontTall, texCoords[2], texCoords[3] ); + + info.shouldclip = true; + + return info.valid; +} + +//----------------------------------------------------------------------------- +// Purpose: batches up characters for rendering +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawRenderCharInternal( const CharRenderInfo& info ) +{ + //hushed MAT_FUNC; + + Assert( g_bInDrawing ); + + // xbox opts out of pricey/pointless text clipping + if ( IsPC() && info.shouldclip ) + { + Vertex_t clip[ 2 ]; + clip[ 0 ] = info.verts[ 0 ]; + clip[ 1 ] = info.verts[ 1 ]; + if ( !ClipRect( clip[0], clip[1], &info.verts[0], &info.verts[1] ) ) + { + // Fully clipped + return; + } + } + + m_nBatchedCharVertCount += 2; + + if ( m_nBatchedCharVertCount >= MAX_BATCHED_CHAR_VERTS - 2 ) + { + DrawFlushText(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawRenderCharFromInfo( const CharRenderInfo& info ) +{ + //hushed MAT_FUNC; + + if ( !info.valid ) + return; + + int x = info.x; + + // get the character texture from the cache + DrawSetTexture( info.textureId ); + + DrawRenderCharInternal( info ); + + // Only do post step + x += ( info.abcB + info.abcC ); + + // Update cursor pos + DrawSetTextPos(x, info.y); +} + +//----------------------------------------------------------------------------- +// Renders a text buffer +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawPrintText(const wchar_t *text, int iTextLen, FontDrawType_t drawType /*= FONT_DRAW_DEFAULT */ ) +{ + MAT_FUNC; + + Assert( g_bInDrawing ); + if (!text) + return; + + if (!m_hCurrentFont) + return; + + int x = m_pDrawTextPos[0] + m_nTranslateX; + int y = m_pDrawTextPos[1] + m_nTranslateY; + + int iTall = GetFontTall(m_hCurrentFont); + int iLastTexId = -1; + + int iCount = 0; + vgui::Vertex_t *pQuads = (vgui::Vertex_t*)stackalloc((2 * iTextLen) * sizeof(vgui::Vertex_t) ); + bool bUnderlined = FontManager().GetFontUnderlined( m_hCurrentFont ); + + int iTotalWidth = 0; + for (int i=0; i<iTextLen; ++i) + { + wchar_t ch = text[i]; + +#if USE_GETKERNEDCHARWIDTH + //iTotalWidth += abcA; + float flWide; + float flabcA; + float flabcC; + wchar_t chBefore = 0; + wchar_t chAfter = 0; + if ( i > 0 ) + chBefore = text[i-1]; + if ( i < (iTextLen-1) ) + chAfter = text[i+1]; + FontManager().GetKernedCharWidth( m_hCurrentFont, ch, chBefore, chAfter, flWide, flabcA, flabcC ); + + int abcA,abcB,abcC; + // also grab the single char dimensions so we match the texture size to the one in the font page, + // different to the amount we step ahead once rendered + GetCharABCwide(m_hCurrentFont, ch, abcA, abcB, abcC); + + int textureWide = abcB; + if ( bUnderlined ) + { + textureWide += ( abcA + abcC ); + x-= flabcA; + } +#else + int abcA,abcB,abcC; + GetCharABCwide(m_hCurrentFont, ch, abcA, abcB, abcC); + int textureWide = abcB; + if ( bUnderlined ) + { + textureWide += ( abcA + abcC ); + x-= abcA; + } + float flabcA = abcA; + float flWide = abcA + abcB + abcC; +#endif + + if ( !iswspace( ch ) || bUnderlined ) + { + // get the character texture from the cache + int iTexId = 0; + float *texCoords = NULL; + if (!g_FontTextureCache.GetTextureForChar(m_hCurrentFont, drawType, ch, &iTexId, &texCoords)) + continue; + + Assert( texCoords ); + + if (iTexId != iLastTexId) + { + // FIXME: At the moment, we just draw all the batched up + // text when the font changes. We Should batch up per material + // and *then* draw + if (iCount) + { + IMaterial *pMaterial = TextureDictionary()->GetTextureMaterial(iLastTexId); + InternalSetMaterial( pMaterial ); + DrawQuadArray( iCount, pQuads, m_DrawTextColor, IsPC() ); + iCount = 0; + } + + iLastTexId = iTexId; + } + + vgui::Vertex_t &ul = pQuads[2*iCount]; + vgui::Vertex_t &lr = pQuads[2*iCount + 1]; + ++iCount; + + ul.m_Position.x = x + iTotalWidth + floor(flabcA + 0.6); + ul.m_Position.y = y; + lr.m_Position.x = ul.m_Position.x + textureWide; + lr.m_Position.y = ul.m_Position.y + iTall; + + // Gets at the texture coords for this character in its texture page + /* + float tex_U0_bias = prc->Knob("tex-U0-bias"); + float tex_V0_bias = prc->Knob("tex-V0-bias"); + float tex_U1_bias = prc->Knob("tex-U1-bias"); + float tex_V1_bias = prc->Knob("tex-V1-bias"); + + ul.m_TexCoord[0] = texCoords[0] + tex_U0_bias; + ul.m_TexCoord[1] = texCoords[1] + tex_V0_bias; + lr.m_TexCoord[0] = texCoords[2] + tex_U1_bias; + lr.m_TexCoord[1] = texCoords[3] + tex_V1_bias; + */ + + ul.m_TexCoord[0] = texCoords[0]; + ul.m_TexCoord[1] = texCoords[1]; + lr.m_TexCoord[0] = texCoords[2]; + lr.m_TexCoord[1] = texCoords[3]; + } + + iTotalWidth += floor(flWide+0.6); + } + + // Draw any left-over characters + if (iCount) + { + IMaterial *pMaterial = TextureDictionary()->GetTextureMaterial(iLastTexId); + InternalSetMaterial( pMaterial ); + DrawQuadArray( iCount, pQuads, m_DrawTextColor, IsPC() ); + } + + m_pDrawTextPos[0] += iTotalWidth; + + stackfree(pQuads); +} + + +//----------------------------------------------------------------------------- +// Returns the screen size +//----------------------------------------------------------------------------- +void CMatSystemSurface::GetScreenSize(int &iWide, int &iTall) +{ + if ( m_ScreenSizeOverride.m_bActive ) + { + iWide = m_ScreenSizeOverride.m_nValue[ 0 ]; + iTall = m_ScreenSizeOverride.m_nValue[ 1 ]; + return; + } + + int x, y; + + // mikesart: This is just sticking in unnecessary BeginRender/EndRender calls to the queue. + // CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + IMatRenderContext *pRenderContext = g_pMaterialSystem->GetRenderContext(); + pRenderContext->GetViewport( x, y, iWide, iTall ); +} + +bool CMatSystemSurface::ForceScreenSizeOverride( bool bState, int wide, int tall ) +{ + bool bWasSet = m_ScreenSizeOverride.m_bActive; + m_ScreenSizeOverride.m_bActive = bState; + m_ScreenSizeOverride.m_nValue[ 0 ] = wide; + m_ScreenSizeOverride.m_nValue[ 1 ] = tall; + return bWasSet; +} + +// LocalToScreen, ParentLocalToScreen fixups for explicit PaintTraverse calls on Panels not at 0, 0 position +bool CMatSystemSurface::ForceScreenPosOffset( bool bState, int x, int y ) +{ + bool bWasSet = m_ScreenPosOverride.m_bActive; + m_ScreenPosOverride.m_bActive = bState; + m_ScreenPosOverride.m_nValue[ 0 ] = x; + m_ScreenPosOverride.m_nValue[ 1 ] = y; + return bWasSet; +} + +void CMatSystemSurface::OffsetAbsPos( int &x, int &y ) +{ + if ( !m_ScreenPosOverride.m_bActive ) + return; + + x += m_ScreenPosOverride.m_nValue[ 0 ]; + y += m_ScreenPosOverride.m_nValue[ 1 ]; +} + + +bool CMatSystemSurface::IsScreenSizeOverrideActive( void ) +{ + return ( m_ScreenSizeOverride.m_bActive ); +} + +bool CMatSystemSurface::IsScreenPosOverrideActive( void ) +{ + return ( m_ScreenPosOverride.m_bActive ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Notification of a new screen size +//----------------------------------------------------------------------------- +void CMatSystemSurface::OnScreenSizeChanged( int nOldWidth, int nOldHeight ) +{ + int iNewWidth, iNewHeight; + GetScreenSize( iNewWidth, iNewHeight ); + + Msg( "Changing resolutions from (%d, %d) -> (%d, %d)\n", nOldWidth, nOldHeight, iNewWidth, iNewHeight ); + + // update the root panel size + ipanel()->SetSize(m_pEmbeddedPanel, iNewWidth, iNewHeight); + + // notify every panel + VPANEL panel = GetEmbeddedPanel(); + ivgui()->PostMessage(panel, new KeyValues("OnScreenSizeChanged", "oldwide", nOldWidth, "oldtall", nOldHeight), NULL); + + // Run a frame of the GUI to notify all subwindows of the message size change + ivgui()->RunFrame(); + + // clear font texture cache + ResetFontCaches(); +} + +// Causes fonts to get reloaded, etc. +void CMatSystemSurface::ResetFontCaches() +{ + // Don't do this on x360!!! + if ( IsX360() ) + return; + + // clear font texture cache + g_FontTextureCache.Clear(); + m_iBoundTexture = -1; + + // reload fonts + FontManager().ClearAllFonts(); + scheme()->ReloadFonts(); + + // Run a frame of the GUI to notify all subwindows of the message size change + ivgui()->RunFrame(); +} + +//----------------------------------------------------------------------------- +// Returns the size of the embedded panel +//----------------------------------------------------------------------------- +void CMatSystemSurface::GetWorkspaceBounds(int &x, int &y, int &iWide, int &iTall) +{ + if ( m_ScreenSizeOverride.m_bActive ) + { + x = y = 0; + iWide = m_ScreenSizeOverride.m_nValue[ 0 ]; + iTall = m_ScreenSizeOverride.m_nValue[ 1 ]; + return; + } + // NOTE: This is equal to the viewport size by default, + // but other embedded panels can be used + x = m_WorkSpaceInsets[0]; + y = m_WorkSpaceInsets[1]; + g_pVGuiPanel->GetSize(m_pEmbeddedPanel, iWide, iTall); + + iWide -= m_WorkSpaceInsets[2]; + iTall -= m_WorkSpaceInsets[3]; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMatSystemSurface::SetWorkspaceInsets( int left, int top, int right, int bottom ) +{ + m_WorkSpaceInsets[0] = left; + m_WorkSpaceInsets[1] = top; + m_WorkSpaceInsets[2] = right; + m_WorkSpaceInsets[3] = bottom; +} + +//----------------------------------------------------------------------------- +// A bunch of methods needed for the windows version only +//----------------------------------------------------------------------------- +void CMatSystemSurface::SetAsTopMost(VPANEL panel, bool state) +{ +} + +void CMatSystemSurface::SetAsToolBar(VPANEL panel, bool state) // removes the window's task bar entry (for context menu's, etc.) +{ +} + +void CMatSystemSurface::SetForegroundWindow (VPANEL panel) +{ + BringToFront(panel); +} + +void CMatSystemSurface::SetPanelVisible(VPANEL panel, bool state) +{ +} + +void CMatSystemSurface::SetMinimized(VPANEL panel, bool state) +{ + if (state) + { + g_pVGuiPanel->SetPlat(panel, VPANEL_MINIMIZED); + g_pVGuiPanel->SetVisible(panel, false); + } + else + { + g_pVGuiPanel->SetPlat(panel, VPANEL_NORMAL); + } +} + +bool CMatSystemSurface::IsMinimized(vgui::VPANEL panel) +{ + return (g_pVGuiPanel->Plat(panel) == VPANEL_MINIMIZED); + +} + +void CMatSystemSurface::FlashWindow(VPANEL panel, bool state) +{ +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMatSystemSurface::SetTitle(VPANEL panel, const wchar_t *title) +{ + int entry = GetTitleEntry( panel ); + if ( entry == -1 ) + { + entry = m_Titles.AddToTail(); + } + + TitleEntry *e = &m_Titles[ entry ]; + Assert( e ); + wcsncpy( e->title, title, sizeof( e->title )/ sizeof( wchar_t ) ); + e->panel = panel; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +wchar_t const *CMatSystemSurface::GetTitle( VPANEL panel ) +{ + int entry = GetTitleEntry( panel ); + if ( entry != -1 ) + { + TitleEntry *e = &m_Titles[ entry ]; + return e->title; + } + + return NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: Private lookup method +// Input : *panel - +// Output : TitleEntry +//----------------------------------------------------------------------------- +int CMatSystemSurface::GetTitleEntry( vgui::VPANEL panel ) +{ + for ( int i = 0; i < m_Titles.Count(); i++ ) + { + TitleEntry* entry = &m_Titles[ i ]; + if ( entry->panel == panel ) + return i; + } + return -1; +} + +void CMatSystemSurface::SwapBuffers(VPANEL panel) +{ +} + +void CMatSystemSurface::Invalidate(VPANEL panel) +{ +} + +void CMatSystemSurface::ApplyChanges() +{ +} + +// notify icons?!? +VPANEL CMatSystemSurface::GetNotifyPanel() +{ + return NULL; +} + +void CMatSystemSurface::SetNotifyIcon(VPANEL context, HTexture icon, VPANEL panelToReceiveMessages, const char *text) +{ +} + +bool CMatSystemSurface::IsWithin(int x, int y) +{ + return true; +} + +bool CMatSystemSurface::ShouldPaintChildPanel(VPANEL childPanel) +{ + if ( m_pRestrictedPanel && ( m_pRestrictedPanel != childPanel ) && + !g_pVGuiPanel->HasParent( childPanel, m_pRestrictedPanel ) ) + { + return false; + } + + bool isPopup = ipanel()->IsPopup(childPanel); + return !isPopup; +} + +bool CMatSystemSurface::RecreateContext(VPANEL panel) +{ + return false; +} + +//----------------------------------------------------------------------------- +// Focus-related methods +//----------------------------------------------------------------------------- +bool CMatSystemSurface::HasFocus() +{ + return true; +} + +void CMatSystemSurface::BringToFront(VPANEL panel) +{ + // move panel to top of list + g_pVGuiPanel->MoveToFront(panel); + + // move panel to top of popup list + if ( g_pVGuiPanel->IsPopup( panel ) ) + { + MovePopupToFront( panel ); + } +} + + +// engine-only focus handling (replacing WM_FOCUS windows handling) +void CMatSystemSurface::SetTopLevelFocus(VPANEL pSubFocus) +{ + // walk up the hierarchy until we find what popup panel belongs to + while (pSubFocus) + { + if (ipanel()->IsPopup(pSubFocus) && ipanel()->IsMouseInputEnabled(pSubFocus)) + { + BringToFront(pSubFocus); + break; + } + + pSubFocus = ipanel()->GetParent(pSubFocus); + } +} + + +//----------------------------------------------------------------------------- +// Installs a function to play sounds +//----------------------------------------------------------------------------- +void CMatSystemSurface::InstallPlaySoundFunc( PlaySoundFunc_t soundFunc ) +{ + m_PlaySoundFunc = soundFunc; +} + + +//----------------------------------------------------------------------------- +// plays a sound +//----------------------------------------------------------------------------- +void CMatSystemSurface::PlaySound(const char *pFileName) +{ + if (m_PlaySoundFunc) + m_PlaySoundFunc( pFileName ); +} + + +//----------------------------------------------------------------------------- +// handles mouse movement +//----------------------------------------------------------------------------- +void CMatSystemSurface::SetCursorPos(int x, int y) +{ + CursorSetPos( m_HWnd, x, y ); +} + +void CMatSystemSurface::GetCursorPos(int &x, int &y) +{ + CursorGetPos( m_HWnd, x, y ); +} + +void CMatSystemSurface::SetCursor(HCursor hCursor) +{ + if ( IsCursorLocked() ) + return; + + if ( _currentCursor != hCursor ) + { + _currentCursor = hCursor; + CursorSelect( hCursor ); + } +} + +void CMatSystemSurface::EnableMouseCapture( VPANEL panel, bool state ) +{ +#ifdef WIN32 + if ( state ) + { + ::SetCapture( reinterpret_cast< HWND >( m_HWnd ) ); + } + else + { + ::ReleaseCapture(); + } +#elif defined( POSIX ) + // SetCapture on Win32 makes all the mouse messages (move and button up/down) head to + // the captured window. From what I can tell, this routine is called for modal dialogs + // when you click down on a button. However the current behavior is to highlight the + // buttons when you're over them, and trigger when you mouse up over the top - so I + // don't believe that SetCapture is needed on Windows, and Linux is behaving exactly + // the same as Win32 in all the tests I've run so far. (I've clicked on a lot of dialogs). + // I talked with Alfred about this and we haven't done any SetCapture stuff on OSX ever + // and he says nobody has ever reported any regressions. + // So I've removed the Assert. 8/32/2012 - mikesart. +#else +#error +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: Turns the panel into a standalone window +//----------------------------------------------------------------------------- +void CMatSystemSurface::CreatePopup(VPANEL panel, bool minimized, bool showTaskbarIcon, bool disabled , bool mouseInput , bool kbInput) +{ + if (!g_pVGuiPanel->GetParent(panel)) + { + g_pVGuiPanel->SetParent(panel, GetEmbeddedPanel()); + } + ((VPanel *)panel)->SetPopup(true); + ((VPanel *)panel)->SetKeyBoardInputEnabled(kbInput); + ((VPanel *)panel)->SetMouseInputEnabled(mouseInput); + + HPanel p = ivgui()->PanelToHandle( panel ); + + if ( m_PopupList.Find( p ) == m_PopupList.InvalidIndex() ) + { + m_PopupList.AddToTail( p ); + } + else + { + MovePopupToFront( panel ); + } +} + + +//----------------------------------------------------------------------------- +// Create/destroy panels.. +//----------------------------------------------------------------------------- +void CMatSystemSurface::AddPanel(VPANEL panel) +{ + if (g_pVGuiPanel->IsPopup(panel)) + { + // turn it into a popup menu + CreatePopup(panel, false); + } +} + +void CMatSystemSurface::ReleasePanel(VPANEL panel) +{ + // Remove from popup list if needed and remove any dead popups while we're at it + RemovePopup( panel ); + + int entry = GetTitleEntry( panel ); + if ( entry != -1 ) + { + m_Titles.Remove( entry ); + } +} + + +//----------------------------------------------------------------------------- +// Popup accessors used by VGUI +//----------------------------------------------------------------------------- +int CMatSystemSurface::GetPopupCount( ) +{ + return m_PopupList.Count(); +} + +VPANEL CMatSystemSurface::GetPopup( int index ) +{ + HPanel p = m_PopupList[ index ]; + VPANEL panel = ivgui()->HandleToPanel( p ); + return panel; +} + +void CMatSystemSurface::ResetPopupList( ) +{ + m_PopupList.RemoveAll(); +} + +void CMatSystemSurface::AddPopup( VPANEL panel ) +{ + HPanel p = ivgui()->PanelToHandle( panel ); + + if ( m_PopupList.Find( p ) == m_PopupList.InvalidIndex() ) + { + m_PopupList.AddToTail( p ); + } +} + + +void CMatSystemSurface::RemovePopup( vgui::VPANEL panel ) +{ + // Remove from popup list if needed and remove any dead popups while we're at it + int c = GetPopupCount(); + + for ( int i = c - 1; i >= 0 ; i-- ) + { + VPANEL popup = GetPopup(i ); + if ( popup && ( popup != panel ) ) + continue; + + m_PopupList.Remove( i ); + break; + } +} + +//----------------------------------------------------------------------------- +// Methods associated with iterating + drawing the panel tree +//----------------------------------------------------------------------------- +void CMatSystemSurface::AddPopupsToList( VPANEL panel ) +{ + if (!g_pVGuiPanel->IsVisible(panel)) + return; + + // Add to popup list as we visit popups + // Note: popup list is cleared in RunFrame which occurs before this call!!! + if ( g_pVGuiPanel->IsPopup( panel ) ) + { + AddPopup( panel ); + } + + int count = g_pVGuiPanel->GetChildCount(panel); + for (int i = 0; i < count; ++i) + { + VPANEL child = g_pVGuiPanel->GetChild(panel, i); + AddPopupsToList( child ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: recurses the panels calculating absolute positions +// parents must be solved before children +//----------------------------------------------------------------------------- +void CMatSystemSurface::InternalSolveTraverse(VPANEL panel) +{ + VPanel * RESTRICT vp = (VPanel *)panel; + + vp->TraverseLevel( 1 ); + tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "%s - %s", __FUNCTION__, vp->GetName() ); + + // solve the parent + vp->Solve(); + + CUtlVector< VPanel * > &children = vp->GetChildren(); + + // WARNING: Some of the think functions add/remove children, so make sure we + // explicitly check for children.Count(). + for ( int i = 0; i < children.Count(); ++i ) + { + VPanel *child = children[ i ]; + if (child->IsVisible()) + { + InternalSolveTraverse( (VPANEL)child ); + } + } + + vp->TraverseLevel( -1 ); +} + +//----------------------------------------------------------------------------- +// Purpose: recurses the panels giving them a chance to do a user-defined think, +// PerformLayout and ApplySchemeSettings +// must be done child before parent +//----------------------------------------------------------------------------- +void CMatSystemSurface::InternalThinkTraverse(VPANEL panel) +{ + VPanel * RESTRICT vp = (VPanel *)panel; + + vp->TraverseLevel( 1 ); + tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "%s - %s", __FUNCTION__, vp->GetName() ); + + // think the parent + vp->Client()->Think(); + + CUtlVector< VPanel * > &children = vp->GetChildren(); + + // WARNING: Some of the think functions add/remove children, so make sure we + // explicitly check for children.Count(). + for ( int i = 0; i < children.Count(); ++i ) + { + VPanel *child = children[ i ]; + if ( child->IsVisible() ) + { + InternalThinkTraverse( (VPANEL)child ); + } + } + + vp->TraverseLevel( -1 ); +} + +//----------------------------------------------------------------------------- +// Purpose: recurses the panels giving them a chance to do apply settings, +//----------------------------------------------------------------------------- +void CMatSystemSurface::InternalSchemeSettingsTraverse(VPANEL panel, bool forceApplySchemeSettings) +{ + VPanel * RESTRICT vp = (VPanel *)panel; + + vp->TraverseLevel( 1 ); + tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "%s - %s", __FUNCTION__, vp->GetName() ); + + CUtlVector< VPanel * > &children = vp->GetChildren(); + + // apply to the children... + for ( int i = 0; i < children.Count(); ++i ) + { + VPanel *child = children[ i ]; + if ( forceApplySchemeSettings || child->IsVisible() ) + { + InternalSchemeSettingsTraverse((VPANEL)child, forceApplySchemeSettings); + } + } + // and then the parent + vp->Client()->PerformApplySchemeSettings(); + + vp->TraverseLevel( -1 ); +} + +//----------------------------------------------------------------------------- +// Purpose: Walks through the panel tree calling Solve() on them all, in order +//----------------------------------------------------------------------------- +void CMatSystemSurface::SolveTraverse(VPANEL panel, bool forceApplySchemeSettings) +{ + { + VPROF( "InternalSchemeSettingsTraverse" ); + tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "%s - InternalSchemeSettingsTraverse", __FUNCTION__ ); + InternalSchemeSettingsTraverse(panel, forceApplySchemeSettings); + } + + { + VPROF( "InternalThinkTraverse" ); + tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "%s - InternalThinkTraverse", __FUNCTION__ ); + InternalThinkTraverse(panel); + } + + { + VPROF( "InternalSolveTraverse" ); + tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "%s - InternalSolveTraverse", __FUNCTION__ ); + InternalSolveTraverse(panel); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Restricts rendering to a single panel +//----------------------------------------------------------------------------- +void CMatSystemSurface::RestrictPaintToSinglePanel(VPANEL panel) +{ + if ( panel && m_pRestrictedPanel && m_pRestrictedPanel == input()->GetAppModalSurface() ) + { + return; // don't restrict drawing to a panel other than the modal one - that's a good way to hang the game. + } + + m_pRestrictedPanel = panel; + + if ( !input()->GetAppModalSurface() ) + { + input()->SetAppModalSurface( panel ); // if painting is restricted to this panel, it had better be modal, or else you can get in some bad state... + } +} + + +//----------------------------------------------------------------------------- +// Is a panel under the restricted panel? +//----------------------------------------------------------------------------- +bool CMatSystemSurface::IsPanelUnderRestrictedPanel( VPANEL panel ) +{ + if ( !m_pRestrictedPanel ) + return true; + + while ( panel ) + { + if ( panel == m_pRestrictedPanel ) + return true; + + panel = ipanel()->GetParent( panel ); + } + return false; +} + + +//----------------------------------------------------------------------------- +// Main entry point for painting +//----------------------------------------------------------------------------- +void CMatSystemSurface::PaintTraverseEx(VPANEL panel, bool paintPopups /*= false*/ ) +{ + MAT_FUNC; + + if ( !ipanel()->IsVisible( panel ) ) + return; + + VPROF( "CMatSystemSurface::PaintTraverse" ); + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + bool bTopLevelDraw = false; + + if ( g_bInDrawing == false ) + { + // only set the 2d ortho mode once + bTopLevelDraw = true; + StartDrawing(); + + // clear z + stencil buffer + // NOTE: Stencil is used to get 3D painting in vgui panels working correctly + pRenderContext->ClearBuffers( false, true, true ); + pRenderContext->SetStencilEnable( true ); + pRenderContext->SetStencilFailOperation( STENCILOPERATION_KEEP ); + pRenderContext->SetStencilZFailOperation( STENCILOPERATION_KEEP ); + pRenderContext->SetStencilPassOperation( STENCILOPERATION_REPLACE ); + pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_GREATEREQUAL ); + pRenderContext->SetStencilReferenceValue( 0 ); + pRenderContext->SetStencilTestMask( 0xFFFFFFFF ); + pRenderContext->SetStencilWriteMask( 0xFFFFFFFF ); + } + + float flOldZPos = m_flZPos; + + // NOTE You might expect we'd have to draw these under the popups so they would occlude + // them, but there are a few things we do have to draw on top of, esp. the black + // panel that draws over the top of the engine to darken everything. + m_flZPos = 0.0f; + if ( panel == GetEmbeddedPanel() ) + { + if ( m_pRestrictedPanel ) + { + // Paint the restricted panel, and its parent. + // NOTE: This call has guards to not draw popups. If the restricted panel + // is a popup, it won't draw here. + ipanel()->PaintTraverse( ipanel()->GetParent( m_pRestrictedPanel ), true ); + } + else + { + // paint traverse the root panel, painting all children + VPROF( "ipanel()->PaintTraverse" ); + ipanel()->PaintTraverse( panel, true ); + } + } + else + { + // If it's a popup, it should already have been painted above + VPROF( "ipanel()->PaintTraverse" ); + if ( !paintPopups || !ipanel()->IsPopup( panel ) ) + { + ipanel()->PaintTraverse( panel, true ); + } + } + + // draw the popups + if ( paintPopups ) + { + // now draw the popups front to back + // since depth-test and depth-write are on, the front panels will occlude the underlying ones + { + VPROF( "CMatSystemSurface::PaintTraverse popups loop" ); + int popups = GetPopupCount(); + if ( popups > 254 ) + { + Warning( "Too many popups! Rendering will be bad!\n" ); + } + + // HACK! Using stencil ref 254 so drag/drop helper can use 255. + int nStencilRef = 254; + for ( int i = popups - 1; i >= 0; --i ) + { + VPANEL popupPanel = GetPopup( i ); + + if ( !popupPanel ) + continue; + + if ( !ipanel()->IsFullyVisible( popupPanel ) ) + continue; + + if ( !IsPanelUnderRestrictedPanel( popupPanel ) ) + continue; + + // This makes sure the drag/drop helper is always the first thing drawn + bool bIsTopmostPopup = ( (VPanel *)popupPanel )->IsTopmostPopup(); + + // set our z position + pRenderContext->SetStencilReferenceValue( bIsTopmostPopup ? 255 : nStencilRef ); + --nStencilRef; + + m_flZPos = ((float)(i) / (float)popups); + ipanel()->PaintTraverse( popupPanel, true ); + } + } + } + + // Restore the old Z Pos + m_flZPos = flOldZPos; + + if ( bTopLevelDraw ) + { + // only undo the 2d ortho mode once + VPROF( "FinishDrawing" ); + + // Reset stencil to normal state + pRenderContext->SetStencilEnable( false ); + + FinishDrawing(); + } +} + +//----------------------------------------------------------------------------- +// Draw a panel +//----------------------------------------------------------------------------- +void CMatSystemSurface::PaintTraverse(VPANEL panel) +{ + PaintTraverseEx( panel, false ); +} + + +//----------------------------------------------------------------------------- +// Begins, ends 3D painting from within a panel paint() method +//----------------------------------------------------------------------------- +void CMatSystemSurface::Begin3DPaint( int iLeft, int iTop, int iRight, int iBottom, bool bRenderToTexture ) +{ + MAT_FUNC; + + if ( IsX360() ) + { + Assert( 0 ); + return; + } + + Assert( iRight > iLeft ); + Assert( iBottom > iTop ); + + // Can't use this while drawing in the 3D world since it relies on + // whacking the shared depth buffer + Assert( !m_bDrawingIn3DWorld ); + if ( m_bDrawingIn3DWorld ) + return; + + m_n3DLeft = iLeft; + m_n3DRight = iRight; + m_n3DTop = iTop; + m_n3DBottom = iBottom; + + // Can't use this feature when drawing into the 3D world + Assert( !m_bDrawingIn3DWorld ); + Assert( !m_bIn3DPaintMode ); + m_bIn3DPaintMode = true; + m_b3DPaintRenderToTexture = bRenderToTexture; + + // Save off the matrices in case the painting method changes them. + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + + pRenderContext->MatrixMode( MATERIAL_MODEL ); + pRenderContext->PushMatrix(); + + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->PushMatrix(); + + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->PushMatrix(); + + if ( bRenderToTexture ) + { + + // For 3d painting, use the off-screen render target the material system allocates + // NOTE: We have to grab it here, as opposed to during init, + // because the mode hasn't been set by now. + if ( !m_FullScreenBuffer ) + { + m_FullScreenBuffer.Init( materials->FindTexture( m_FullScreenBufferName, "render targets" ) ); + } + + // FIXME: Set the viewport to match the clip rectangle? + // Set the viewport to match the scissor rectangle + pRenderContext->PushRenderTargetAndViewport( m_FullScreenBuffer, + 0, 0, iRight - iLeft, iBottom - iTop ); + + // NOTE: Stencil is used to get 3D painting in vgui panels working correctly + pRenderContext->SetStencilFailOperation( STENCILOPERATION_KEEP ); + pRenderContext->SetStencilZFailOperation( STENCILOPERATION_KEEP ); + pRenderContext->SetStencilPassOperation( STENCILOPERATION_REPLACE ); + pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_EQUAL ); + + // Don't draw the 3D scene w/ stencil + pRenderContext->SetStencilEnable( false ); + } + else + { + int clipLeft, clipTop, clipRight, clipBottom; + bool clipEnabled; + GetScissorRect( clipLeft, clipTop, clipRight, clipBottom, clipEnabled ); + pRenderContext->PushRenderTargetAndViewport(); + pRenderContext->Viewport( clipLeft + iLeft, clipTop + iTop, iRight - iLeft, iBottom - iTop ); + } + + pRenderContext->CullMode( MATERIAL_CULLMODE_CW ); + + pRenderContext->Flush(); +} + +void CMatSystemSurface::End3DPaint() +{ + MAT_FUNC; + + if ( IsX360() ) + { + Assert( 0 ); + return; + } + + // Can't use this feature when drawing into the 3D world + Assert( !m_bDrawingIn3DWorld ); + Assert( m_bIn3DPaintMode ); + m_bIn3DPaintMode = false; + + // Reset stencil to set stencil everywhere we draw + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + + pRenderContext->SetStencilEnable( true ); + pRenderContext->SetStencilFailOperation( STENCILOPERATION_KEEP ); + pRenderContext->SetStencilZFailOperation( STENCILOPERATION_KEEP ); + pRenderContext->SetStencilPassOperation( STENCILOPERATION_REPLACE ); + pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_GREATEREQUAL ); + + // Restore the matrices + pRenderContext->MatrixMode( MATERIAL_MODEL ); + pRenderContext->PopMatrix(); + + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->PopMatrix(); + + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->PopMatrix(); + + // Restore the viewport (it was stored off in StartDrawing) + pRenderContext->PopRenderTargetAndViewport(); + pRenderContext->CullMode(MATERIAL_CULLMODE_CCW); + + // Draw the full-screen buffer into the panel, if we rendering + // to a texture + if ( m_b3DPaintRenderToTexture ) + DrawFullScreenBuffer( m_n3DLeft, m_n3DTop, m_n3DRight, m_n3DBottom ); + + // ReSet the material state + InternalSetMaterial( NULL ); +} + + +//----------------------------------------------------------------------------- +// skin composition, force drawing +//----------------------------------------------------------------------------- +void CMatSystemSurface::BeginSkinCompositionPainting() +{ + g_bInDrawing = true; +} + + +//----------------------------------------------------------------------------- +// end drawing when finish skin composition +//----------------------------------------------------------------------------- +void CMatSystemSurface::EndSkinCompositionPainting() +{ + g_bInDrawing = false; +} + + +//----------------------------------------------------------------------------- +// Gets texture coordinates for drawing the full screen buffer +//----------------------------------------------------------------------------- +void CMatSystemSurface::GetFullScreenTexCoords( int x, int y, int w, int h, float *pMinU, float *pMinV, float *pMaxU, float *pMaxV ) +{ + int nTexWidth = m_FullScreenBuffer->GetActualWidth(); + int nTexHeight = m_FullScreenBuffer->GetActualHeight(); + float flOOWidth = 1.0f / nTexWidth; + float flOOHeight = 1.0f / nTexHeight; + + *pMinU = ( (float)x + 0.5f ) * flOOWidth; + *pMinV = ( (float)y + 0.5f ) * flOOHeight; + *pMaxU = ( (float)(x+w) - 0.5f ) * flOOWidth; + *pMaxV = ( (float)(y+h) - 0.5f ) * flOOHeight; +} + + +//----------------------------------------------------------------------------- +// Draws the fullscreen buffer into the panel +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawFullScreenBuffer( int nLeft, int nTop, int nRight, int nBottom ) +{ + MAT_FUNC; + + // Draw a textured rectangle over the area + if ( m_nFullScreenBufferMaterialId == -1 ) + { + m_nFullScreenBufferMaterialId = CreateNewTextureID(); + DrawSetTextureMaterial( m_nFullScreenBufferMaterialId, m_FullScreenBufferMaterial ); + } + + float flGetAlphaMultiplier = DrawGetAlphaMultiplier(); + unsigned char oldColor[4]; + oldColor[0] = m_DrawColor[0]; + oldColor[1] = m_DrawColor[1]; + oldColor[2] = m_DrawColor[2]; + oldColor[3] = m_DrawColor[3]; + + DrawSetAlphaMultiplier( 1.0f ); + DrawSetColor( 255, 255, 255, 255 ); + + DrawSetTexture( m_nFullScreenBufferMaterialId ); + + float u0, u1, v0, v1; + GetFullScreenTexCoords( 0, 0, nRight - nLeft, nBottom - nTop, &u0, &v0, &u1, &v1 ); + DrawTexturedSubRect( nLeft, nTop, nRight, nBottom, u0, v0, u1, v1 ); + + m_DrawColor[0] = oldColor[0]; + m_DrawColor[1] = oldColor[1]; + m_DrawColor[2] = oldColor[2]; + m_DrawColor[3] = oldColor[3]; + DrawSetAlphaMultiplier( flGetAlphaMultiplier ); +} + + +//----------------------------------------------------------------------------- +// Draws a rectangle, setting z to the current value +//----------------------------------------------------------------------------- +float CMatSystemSurface::GetZPos() const +{ + return m_flZPos; +} + + +//----------------------------------------------------------------------------- +// Some drawing methods that cannot be accomplished under Win32 +//----------------------------------------------------------------------------- +#define CIRCLE_POINTS 360 + +void CMatSystemSurface::DrawColoredCircle( int centerx, int centery, float radius, int r, int g, int b, int a ) +{ + MAT_FUNC; + + Assert( g_bInDrawing ); + // Draw a circle + int iDegrees = 0; + Vector vecPoint, vecLastPoint(0,0,0); + vecPoint.z = 0.0f; + Color clr; + clr.SetColor( r, g, b, a ); + DrawSetColor( clr ); + + for ( int i = 0; i < CIRCLE_POINTS; i++ ) + { + float flRadians = DEG2RAD( iDegrees ); + iDegrees += (360 / CIRCLE_POINTS); + + float ca = cos( flRadians ); + float sa = sin( flRadians ); + + // Rotate it around the circle + vecPoint.x = centerx + (radius * sa); + vecPoint.y = centery - (radius * ca); + + // Draw the point, if it's not on the previous point, to avoid smaller circles being brighter + if ( vecLastPoint != vecPoint ) + { + DrawFilledRect( vecPoint.x, vecPoint.y, vecPoint.x + 1, vecPoint.y + 1 ); + } + + vecLastPoint = vecPoint; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Draws colored text to a vgui panel +// Input : *font - font to use +// x - position of text +// y - +// r - color of text +// g - +// b - +// a - alpha ( 255 = opaque, 0 = transparent ) +// *fmt - va_* text string +// ... - +// Output : int - horizontal # of pixels drawn +//----------------------------------------------------------------------------- +int CMatSystemSurface::DrawColoredText( vgui::HFont font, int x, int y, int r, int g, int b, int a, const char *fmt, va_list argptr ) +{ + MAT_FUNC; + Assert( g_bInDrawing ); + int len; + char data[1024]; + + DrawSetTextPos( x, y ); + DrawSetTextColor( r, g, b, a ); + + len = Q_vsnprintf(data, sizeof( data ), fmt, argptr); + + DrawSetTextFont( font ); + + wchar_t szconverted[ 1024 ]; + g_pVGuiLocalize->ConvertANSIToUnicode( data, szconverted, 1024 ); + DrawPrintText( szconverted, wcslen(szconverted ) ); + + int totalLength = DrawTextLen( font, data ); + + return x + totalLength; +} + +int CMatSystemSurface::DrawColoredText( vgui::HFont font, int x, int y, int r, int g, int b, int a, const char *fmt, ... ) +{ + MAT_FUNC; + + va_list argptr; + va_start( argptr, fmt ); + int ret = DrawColoredText( font, x, y, r, g, b, a, fmt, argptr ); + va_end(argptr); + return ret; +} + + +//----------------------------------------------------------------------------- +// Draws text with current font at position and wordwrapped to the rect using color values specified +//----------------------------------------------------------------------------- +void CMatSystemSurface::SearchForWordBreak( vgui::HFont font, char *text, int& chars, int& pixels ) +{ + chars = pixels = 0; + while ( 1 ) + { + char ch = text[ chars ]; + int a, b, c; + GetCharABCwide( font, ch, a, b, c ); + + if ( ch == 0 || ch <= 32 ) + { + if ( ch == 32 && chars == 0 ) + { + pixels += ( b + c ); + chars++; + } + break; + } + + pixels += ( b + c ); + chars++; + } +} + +//----------------------------------------------------------------------------- +// Purpose: If text width is specified, reterns height of text at that width +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawTextHeight( vgui::HFont font, int w, int& h, const char *fmt, ... ) +{ + if ( !font ) + return; + + int len; + char data[8192]; + + va_list argptr; + va_start( argptr, fmt ); + len = Q_vsnprintf( data, sizeof( data ), fmt, argptr ); + va_end( argptr ); + + int x = 0; + int y = 0; + + int ystep = GetFontTall( font ); + int startx = x; + int endx = x + w; + //int endy = y + h; + int endy = 0; + + int chars = 0; + int pixels = 0; + for ( int i = 0 ; i < len; i += chars ) + { + SearchForWordBreak( font, &data[ i ], chars, pixels ); + + if ( data[ i ] == '\n' ) + { + x = startx; + y += ystep; + chars = 1; + continue; + } + + if ( x + ( pixels ) >= endx ) + { + x = startx; + // No room even on new line!!! + if ( x + pixels >= endx ) + break; + + y += ystep; + } + + for ( int j = 0 ; j < chars; j++ ) + { + int a, b, c; + char ch = data[ i + j ]; + + GetCharABCwide( font, ch, a, b, c ); + + x += a + b + c; + } + } + + endy = y+ystep; + + h = endy; +} + + +//----------------------------------------------------------------------------- +// Draws text with current font at position and wordwrapped to the rect using color values specified +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawColoredTextRect( vgui::HFont font, int x, int y, int w, int h, int r, int g, int b, int a, const char *fmt, ... ) +{ + MAT_FUNC; + + Assert( g_bInDrawing ); + if ( !font ) + return; + + int len; + char data[8192]; + + va_list argptr; + va_start( argptr, fmt ); + len = Q_vsnprintf( data, sizeof( data ), fmt, argptr ); + va_end( argptr ); + + DrawSetTextPos( x, y ); + DrawSetTextColor( r, g, b, a ); + DrawSetTextFont( font ); + + int ystep = GetFontTall( font ); + int startx = x; + int endx = x + w; + int endy = y + h; + + int chars = 0; + int pixels = 0; + + char word[ 512 ]; + char space[ 2 ]; + space[1] = 0; + space[0] = ' '; + + for ( int i = 0 ; i < len; i += chars ) + { + SearchForWordBreak( font, &data[ i ], chars, pixels ); + + if ( data[ i ] == '\n' ) + { + x = startx; + y += ystep; + chars = 1; + continue; + } + + if ( x + ( pixels ) >= endx ) + { + x = startx; + // No room even on new line!!! + if ( x + pixels >= endx ) + break; + + y += ystep; + } + + if ( y + ystep >= endy ) + break; + + + if ( chars <= 0 ) + continue; + + Q_strncpy( word, &data[ i ], chars + 1 ); + + DrawSetTextPos( x, y ); + + wchar_t szconverted[ 1024 ]; + g_pVGuiLocalize->ConvertANSIToUnicode( word, szconverted, 1024 ); + DrawPrintText( szconverted, wcslen(szconverted ) ); + + // Leave room for space, too + x += DrawTextLen( font, word ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Determine length of text string +//----------------------------------------------------------------------------- +int CMatSystemSurface::DrawTextLen( vgui::HFont font, const char *fmt, ... ) +{ + va_list argptr; + char data[1024]; + int len; + + va_start(argptr, fmt); + len = Q_vsnprintf(data, sizeof( data ), fmt, argptr); + va_end(argptr); + + int i; + int x = 0; + + for ( i = 0 ; i < len; i++ ) + { + int a, b, c; + GetCharABCwide( font, data[i], a, b, c ); + + // Ignore a + // x += a; + x += b; + x += c; + } + + return x; +} + +//----------------------------------------------------------------------------- +// Disable clipping during rendering +//----------------------------------------------------------------------------- +void CMatSystemSurface::DisableClipping( bool bDisable ) +{ + // when the clipping rules change. flush any text we've + // queued up to draw so it gets clipped appropriatesly + DrawFlushText(); + + EnableScissor( !bDisable ); +} + + +//----------------------------------------------------------------------------- +// Fetch current clipping rectangle +//----------------------------------------------------------------------------- +void CMatSystemSurface::GetClippingRect( int &left, int &top, int &right, int &bottom, bool &bClippingDisabled ) +{ + bool bEnabled = true; + GetScissorRect( left, top, right, bottom, bEnabled ); + bClippingDisabled = !bEnabled; +} + +//----------------------------------------------------------------------------- +// Set clipping rectangle +//----------------------------------------------------------------------------- +void CMatSystemSurface::SetClippingRect( int left, int top, int right, int bottom ) +{ + SetScissorRect( left, top, right, bottom ); +} + +//----------------------------------------------------------------------------- +// Purpose: unlocks the cursor state +//----------------------------------------------------------------------------- +bool CMatSystemSurface::IsCursorLocked() const +{ + return ::IsCursorLocked(); +} + + +//----------------------------------------------------------------------------- +// Sets the mouse Get + Set callbacks +//----------------------------------------------------------------------------- +void CMatSystemSurface::SetMouseCallbacks( GetMouseCallback_t GetFunc, SetMouseCallback_t SetFunc ) +{ + // FIXME: Remove! This is obsolete + Assert(0); +} + + +//----------------------------------------------------------------------------- +// Tells the surface to ignore windows messages +//----------------------------------------------------------------------------- +void CMatSystemSurface::EnableWindowsMessages( bool bEnable ) +{ + EnableInput( bEnable ); +} + +void CMatSystemSurface::MovePopupToFront(VPANEL panel) +{ + HPanel p = ivgui()->PanelToHandle( panel ); + + int index = m_PopupList.Find( p ); + if ( index == m_PopupList.InvalidIndex() ) + return; + + m_PopupList.Remove( index ); + m_PopupList.AddToTail( p ); + + if ( g_bSpewFocus ) + { + char const *pName = ipanel()->GetName( panel ); + Msg( "%s moved to front\n", pName ? pName : "(no name)" ); + } + + // If the modal panel isn't a parent, restore it to the top, to prevent a hard lock + if ( input()->GetAppModalSurface() ) + { + if ( !g_pVGuiPanel->HasParent(panel, input()->GetAppModalSurface()) ) + { + HPanel p = ivgui()->PanelToHandle( input()->GetAppModalSurface() ); + index = m_PopupList.Find( p ); + if ( index != m_PopupList.InvalidIndex() ) + { + m_PopupList.Remove( index ); + m_PopupList.AddToTail( p ); + } + } + } + + ivgui()->PostMessage(panel, new KeyValues("OnMovedPopupToFront"), NULL); +} + +void CMatSystemSurface::MovePopupToBack(VPANEL panel) +{ + HPanel p = ivgui()->PanelToHandle( panel ); + + int index = m_PopupList.Find( p ); + if ( index == m_PopupList.InvalidIndex() ) + { + return; + } + + m_PopupList.Remove( index ); + m_PopupList.AddToHead( p ); +} + + +bool CMatSystemSurface::IsInThink( VPANEL panel) +{ + if ( m_bInThink ) + { + if ( panel == m_CurrentThinkPanel ) // HasParent() returns true if you pass yourself in + { + return false; + } + + return ipanel()->HasParent( panel, m_CurrentThinkPanel); + } + return false; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CMatSystemSurface::IsCursorVisible() +{ + return m_cursorAlwaysVisible || (_currentCursor != dc_none); +} + +void CMatSystemSurface::SetCursorAlwaysVisible( bool visible ) +{ + m_cursorAlwaysVisible = visible; + CursorSelect( visible ? dc_alwaysvisible_push : dc_alwaysvisible_pop ); +} + +bool CMatSystemSurface::IsTextureIDValid(int id) +{ + // FIXME: + return true; +} + +void CMatSystemSurface::SetAllowHTMLJavaScript( bool state ) +{ + m_bAllowJavaScript = state; +} + +IHTML *CMatSystemSurface::CreateHTMLWindow(vgui::IHTMLEvents *events,VPANEL context) +{ + Assert( !"CMatSystemSurface::CreateHTMLWindow" ); + return NULL; +} + + +void CMatSystemSurface::DeleteHTMLWindow(IHTML *htmlwin) +{ +} + + + +void CMatSystemSurface::PaintHTMLWindow(IHTML *htmlwin) +{ +} + +bool CMatSystemSurface::BHTMLWindowNeedsPaint(IHTML *htmlwin) +{ + return false; +} + +//----------------------------------------------------------------------------- +/*void CMatSystemSurface::DrawSetTextureRGBA( int id, const unsigned char* rgba, int wide, int tall ) +{ + TextureDictionary()->SetTextureRGBAEx( id, (const char *)rgba, wide, tall, IMAGE_FORMAT_RGBA8888 ); +}*/ + +void CMatSystemSurface::DrawSetTextureRGBA(int id, const unsigned char* rgba, int wide, int tall, int hardwareFilter, bool forceUpload) +{ + TextureDictionary()->SetTextureRGBAEx( id, (const char *)rgba, wide, tall, IMAGE_FORMAT_RGBA8888, false ); +} + +void CMatSystemSurface::DrawSetTextureRGBAEx( int id, const unsigned char* rgba, int wide, int tall, ImageFormat format ) +{ + TextureDictionary()->SetTextureRGBAEx( id, (const char *)rgba, wide, tall, format, true ); +} + +void CMatSystemSurface::DrawSetSubTextureRGBA(int textureID, int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall) +{ + TextureDictionary()->SetSubTextureRGBA( textureID, drawX, drawY, rgba, subTextureWide, subTextureTall ); +} + +void CMatSystemSurface::DrawUpdateRegionTextureRGBA( int nTextureID, int x, int y, const unsigned char *pchData, int wide, int tall, ImageFormat imageFormat ) +{ + TextureDictionary()->UpdateSubTextureRGBA( nTextureID, x, y, pchData, wide, tall, imageFormat ); +} + +void CMatSystemSurface::SetModalPanel(VPANEL ) +{ +} + +VPANEL CMatSystemSurface::GetModalPanel() +{ + return 0; +} + +void CMatSystemSurface::UnlockCursor() +{ + ::LockCursor( false ); +} + +void CMatSystemSurface::LockCursor() +{ + ::LockCursor( true ); +} + +void CMatSystemSurface::SetTranslateExtendedKeys(bool state) +{ +} + +VPANEL CMatSystemSurface::GetTopmostPopup() +{ + return 0; +} + +//----------------------------------------------------------------------------- +// Purpose: gets the absolute coordinates of the screen (in screen space) +//----------------------------------------------------------------------------- +void CMatSystemSurface::GetAbsoluteWindowBounds(int &x, int &y, int &wide, int &tall) +{ + // always work in full window screen space + x = 0; + y = 0; + GetScreenSize(wide, tall); +} + +// returns true if the specified panel is a child of the current modal panel +// if no modal panel is set, then this always returns TRUE +static bool IsChildOfModalSubTree(VPANEL panel) +{ + if ( !panel ) + return true; + + VPANEL modalSubTree = input()->GetModalSubTree(); + + if ( modalSubTree ) + { + bool restrictMessages = input()->ShouldModalSubTreeReceiveMessages(); + + // If panel is child of modal subtree, the allow messages to route to it if restrict messages is set + bool isChildOfModal = ipanel()->HasParent( panel, modalSubTree ); + if ( isChildOfModal ) + { + return restrictMessages; + } + // If panel is not a child of modal subtree, then only allow messages if we're not restricting them to the modal subtree + else + { + return !restrictMessages; + } + } + + return true; +} + +void CMatSystemSurface::CalculateMouseVisible() +{ + int i; + m_bNeedsMouse = false; + m_bNeedsKeyboard = false; + + if ( input()->GetMouseCapture() != 0 ) + return; + + int c = surface()->GetPopupCount(); + + VPANEL modalSubTree = input()->GetModalSubTree(); + if ( modalSubTree ) + { + for (i = 0 ; i < c ; i++ ) + { + VPanel *pop = (VPanel *)surface()->GetPopup(i) ; + bool isChildOfModalSubPanel = IsChildOfModalSubTree( (VPANEL)pop ); + if ( !isChildOfModalSubPanel ) + continue; + + bool isVisible=pop->IsVisible(); + VPanel *p= pop->GetParent(); + + while (p && isVisible) + { + if( p->IsVisible()==false) + { + isVisible=false; + break; + } + p=p->GetParent(); + } + + if ( isVisible ) + { + m_bNeedsMouse = m_bNeedsMouse || pop->IsMouseInputEnabled(); + m_bNeedsKeyboard = m_bNeedsKeyboard || pop->IsKeyBoardInputEnabled(); + + // Seen enough!!! + if ( m_bNeedsMouse && m_bNeedsKeyboard ) + break; + } + } + } + else + { + for (i = 0 ; i < c ; i++ ) + { + VPanel *pop = (VPanel *)surface()->GetPopup(i) ; + + bool isVisible=pop->IsVisible(); + VPanel *p= pop->GetParent(); + + while (p && isVisible) + { + if( p->IsVisible()==false) + { + isVisible=false; + break; + } + p=p->GetParent(); + } + + if ( isVisible ) + { + m_bNeedsMouse = m_bNeedsMouse || pop->IsMouseInputEnabled(); + m_bNeedsKeyboard = m_bNeedsKeyboard || pop->IsKeyBoardInputEnabled(); + + // Seen enough!!! + if ( m_bNeedsMouse && m_bNeedsKeyboard ) + break; + } + } + } + + if (m_bNeedsMouse) + { + // NOTE: We must unlock the cursor *before* the set call here. + // Failing to do this causes s_bCursorVisible to not be set correctly + // (UnlockCursor fails to set it correctly) + UnlockCursor(); + if ( _currentCursor == vgui::dc_none ) + { + SetCursor(vgui::dc_arrow); + } + } + else + { + SetCursor(vgui::dc_none); + LockCursor(); + } +} + +bool CMatSystemSurface::NeedKBInput() +{ + return m_bNeedsKeyboard; +} + +void CMatSystemSurface::SurfaceGetCursorPos(int &x, int &y) +{ + GetCursorPos( x, y ); +} +void CMatSystemSurface::SurfaceSetCursorPos(int x, int y) +{ + SetCursorPos( x, y ); +} + +//----------------------------------------------------------------------------- +// Purpose: global alpha setting functions +//----------------------------------------------------------------------------- +void CMatSystemSurface::DrawSetAlphaMultiplier( float alpha /* [0..1] */ ) +{ + m_flAlphaMultiplier = clamp(alpha, 0.0f, 1.0f); +} + +//----------------------------------------------------------------------------- +// Purpose: data accessor +//----------------------------------------------------------------------------- +float CMatSystemSurface::DrawGetAlphaMultiplier() +{ + return m_flAlphaMultiplier; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *curOrAniFile - +// Output : vgui::HCursor +//----------------------------------------------------------------------------- +vgui::HCursor CMatSystemSurface::CreateCursorFromFile( char const *curOrAniFile, char const *pPathID ) +{ + return Cursor_CreateCursorFromFile( curOrAniFile, pPathID ); +} + +void CMatSystemSurface::SetPanelForInput( VPANEL vpanel ) +{ + g_pIInput->AssociatePanelWithInputContext( DEFAULT_INPUT_CONTEXT, vpanel ); + if ( vpanel ) + { + m_bNeedsKeyboard = true; + } + else + { + m_bNeedsKeyboard = false; + } +} + +#if defined( WIN32 ) && !defined( _X360 ) +static bool GetIconSize( ICONINFO& iconInfo, int& w, int& h ) +{ + w = h = 0; + + HBITMAP bitmap = iconInfo.hbmColor; + BITMAP bm; + if ( 0 == GetObject((HGDIOBJ)bitmap, sizeof(BITMAP), (LPVOID)&bm) ) + { + return false; + } + + w = bm.bmWidth; + h = bm.bmHeight; + + return true; +} + +// If rgba is NULL, bufsize gets filled in w/ # of bytes required +static bool GetIconBits( HDC hdc, ICONINFO& iconInfo, int& w, int& h, unsigned char *rgba, size_t& bufsize ) +{ + if ( !iconInfo.hbmColor || !iconInfo.hbmMask ) + return false; + + if ( !rgba ) + { + if ( !GetIconSize( iconInfo, w, h ) ) + return false; + + bufsize = (size_t)( ( w * h ) << 2 ); + return true; + } + + bool bret = false; + + Assert( w > 0 ); + Assert( h > 0 ); + Assert( bufsize == (size_t)( ( w * h ) << 2 ) ); + + DWORD *maskData = new DWORD[ w * h ]; + DWORD *colorData = new DWORD[ w * h ]; + DWORD *output = (DWORD *)rgba; + + BITMAPINFO bmInfo; + + memset( &bmInfo, 0, sizeof( bmInfo ) ); + bmInfo.bmiHeader.biSize = sizeof( bmInfo.bmiHeader ); + bmInfo.bmiHeader.biWidth = w; + bmInfo.bmiHeader.biHeight = h; + bmInfo.bmiHeader.biPlanes = 1; + bmInfo.bmiHeader.biBitCount = 32; + bmInfo.bmiHeader.biCompression = BI_RGB; + + // Get the info about the bits + if ( GetDIBits( hdc, iconInfo.hbmMask, 0, h, maskData, &bmInfo, DIB_RGB_COLORS ) == h && + GetDIBits( hdc, iconInfo.hbmColor, 0, h, colorData, &bmInfo, DIB_RGB_COLORS ) == h ) + { + bret = true; + + for ( int row = 0; row < h; ++row ) + { + // Invert + int r = ( h - row - 1 ); + int rowstart = r * w; + + DWORD *color = &colorData[ rowstart ]; + DWORD *mask = &maskData[ rowstart ]; + DWORD *outdata = &output[ row * w ]; + + for ( int col = 0; col < w; ++col ) + { + unsigned char *cr = ( unsigned char * )&color[ col ]; + + // Set alpha + cr[ 3 ] = mask[ col ] == 0 ? 0xff : 0x00; + + // Swap blue and red + unsigned char t = cr[ 2 ]; + cr[ 2 ] = cr[ 0 ]; + cr[ 0 ] = t; + + *( unsigned int *)&outdata[ col ] = *( unsigned int * )cr; + } + } + } + + delete[] colorData; + delete[] maskData; + + return bret; +} + +static bool ShouldMakeUnique( char const *extension ) +{ + if ( !Q_stricmp( extension, "cur" ) ) + return true; + if ( !Q_stricmp( extension, "ani" ) ) + return true; + return false; +} +#endif // !_X360 + +vgui::IImage *CMatSystemSurface::GetIconImageForFullPath( char const *pFullPath ) +{ + vgui::IImage *newIcon = NULL; + +#if defined( WIN32 ) && !defined( _X360 ) + SHFILEINFO info = { 0 }; + DWORD_PTR dwResult = SHGetFileInfo( + pFullPath, + 0, + &info, + sizeof( info ), + SHGFI_TYPENAME | SHGFI_ICON | SHGFI_SMALLICON | SHGFI_SHELLICONSIZE + ); + if ( dwResult ) + { + if ( info.szTypeName[ 0 ] != 0 ) + { + char ext[ 32 ]; + Q_ExtractFileExtension( pFullPath, ext, sizeof( ext ) ); + + char lookup[ 512 ]; + Q_snprintf( lookup, sizeof( lookup ), "%s", ShouldMakeUnique( ext ) ? pFullPath : info.szTypeName ); + + // Now check the dictionary + unsigned short idx = m_FileTypeImages.Find( lookup ); + if ( idx == m_FileTypeImages.InvalidIndex() ) + { + ICONINFO iconInfo; + if ( 0 != GetIconInfo( info.hIcon, &iconInfo ) ) + { + int w, h; + size_t bufsize = 0; + + HDC hdc = ::GetDC(reinterpret_cast<HWND>(m_HWnd)); + + if ( GetIconBits( hdc, iconInfo, w, h, NULL, bufsize ) ) + { + byte *bits = new byte[ bufsize ]; + if ( bits && GetIconBits( hdc, iconInfo, w, h, bits, bufsize ) ) + { + newIcon = new MemoryBitmap( bits, w, h ); + } + delete[] bits; + } + + ::ReleaseDC( reinterpret_cast<HWND>(m_HWnd), hdc ); + } + + idx = m_FileTypeImages.Insert( lookup, newIcon ); + } + + newIcon = m_FileTypeImages[ idx ]; + } + + DestroyIcon( info.hIcon ); + } +#endif + return newIcon; +} + +const char *CMatSystemSurface::GetResolutionKey( void ) const +{ + Assert( !IsPC() ); + int x, y, width, height; + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + pRenderContext->GetViewport( x, y, width, height ); + if( height <= 480 ) + { + return "_lodef"; + } + else + { + return "_hidef"; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMatSystemSurface::Set3DPaintTempRenderTarget( const char *pRenderTargetName ) +{ + MAT_FUNC; + + Assert( !m_bUsingTempFullScreenBufferMaterial ); + m_bUsingTempFullScreenBufferMaterial = true; + + InitFullScreenBuffer( pRenderTargetName ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMatSystemSurface::Reset3DPaintTempRenderTarget( void ) +{ + MAT_FUNC; + + Assert( m_bUsingTempFullScreenBufferMaterial ); + m_bUsingTempFullScreenBufferMaterial = false; + + InitFullScreenBuffer( "_rt_FullScreen" ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Sets the origin of the viewport to render into if we were +// rendering into the frame buffer. This version of the function is +// mostly here for backward compatibility and always uses a NULL +// render target (i.e. the frame buffer.) +//----------------------------------------------------------------------------- +void CMatSystemSurface::SetFullscreenViewport( int x, int y, int w, int h ) +{ + SetFullscreenViewportAndRenderTarget( x, y, w, h, NULL ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Sets the origin of the viewport to render into if we were +// rendering into the frame buffer. We might actually be generally +// using a render target but need to switch back to the frame buffer +// for some panels. +//----------------------------------------------------------------------------- +void CMatSystemSurface::SetFullscreenViewportAndRenderTarget( int x, int y, int w, int h, ITexture *pRenderTarget ) +{ + m_nFullscreenViewportX = x; + m_nFullscreenViewportY = y; + m_nFullscreenViewportWidth = w; + m_nFullscreenViewportHeight = h; + m_pFullscreenRenderTarget = pRenderTarget; +} + + +//----------------------------------------------------------------------------- +// Purpose: Gets the origin of the viewport to render into if we were +// rendering into the frame buffer. We might actually be generally +// using a render target but need to switch back to the frame buffer +// for some panels. +//----------------------------------------------------------------------------- +void CMatSystemSurface::GetFullscreenViewportAndRenderTarget( int & x, int & y, int & w, int & h, ITexture **ppRenderTarget ) +{ + if( m_nFullscreenViewportHeight == 0 ) + { + // this can't actually be zero. If it is, use the height of the screen instead + x = y = 0; + GetScreenSize( w, h ); + if( ppRenderTarget) + *ppRenderTarget = NULL; + } + else + { + x = m_nFullscreenViewportX; + y = m_nFullscreenViewportY; + w = m_nFullscreenViewportWidth; + h = m_nFullscreenViewportHeight; + if( ppRenderTarget) + *ppRenderTarget = m_pFullscreenRenderTarget; + } +} +void CMatSystemSurface::GetFullscreenViewport( int & x, int & y, int & w, int & h ) +{ + GetFullscreenViewportAndRenderTarget( x, y, w, h, NULL ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Handle switching in and out of "render to fullscreen" mode. We don't +// actually support this mode in tools. +//----------------------------------------------------------------------------- +void CMatSystemSurface::PushFullscreenViewport() +{ + CMatRenderContextPtr pRenderContext( materials ); + + // the viewport x/y will be wrong because the render target is only for one eye. + // Ask the surface for that information instead. + int vx, vy, vw, vh; + ITexture *pRenderTarget; + GetFullscreenViewportAndRenderTarget( vx, vy, vw, vh, &pRenderTarget ); + pRenderContext->PushRenderTargetAndViewport( pRenderTarget, NULL, vx, vy, vw, vh ); + + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->PushMatrix(); + pRenderContext->LoadIdentity(); + pRenderContext->Scale( 1, -1, 1 ); + + //___stop___(); + pRenderContext->Ortho( g_flPixelOffsetX, g_flPixelOffsetY, vw + g_flPixelOffsetX, vh + g_flPixelOffsetY, -1.0f, 1.0f ); + + DisableClipping( true ); +} + +void CMatSystemSurface::PopFullscreenViewport() +{ + CMatRenderContextPtr pRenderContext( materials ); + + pRenderContext->PopRenderTargetAndViewport(); + + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->PopMatrix(); + + DisableClipping( false ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Handle switching in and out of "render to fullscreen" mode. We don't +// actually support this mode in tools. +//----------------------------------------------------------------------------- +void CMatSystemSurface::SetSoftwareCursor( bool bUseSoftwareCursor ) +{ + EnableSoftwareCursor( bUseSoftwareCursor ); +} + +void CMatSystemSurface::PaintSoftwareCursor() +{ + if( !ShouldDrawSoftwareCursor() ) + return; + + // this asks Windows for the position RIGHT NOW, which should be the least + // latent notion we have of where to draw the cursor + int x, y; + GetCursorPos( x, y ); + + Color clr( 255, 255, 255, 255 ); + + float uOffset, vOffset; + int nTextureID = GetSoftwareCursorTexture( &uOffset, &vOffset ); + if( nTextureID <= 0 ) + return; + + int w, h; + DrawGetTextureSize( nTextureID, w, h ); + + // the cursors are actually pretty big. Make them smaller. + w /= 2; + h /= 2; + + int xOffset = (int)(uOffset * (float)w); + int yOffset = (int)(vOffset * (float)h); + + Assert( !g_bInDrawing ); + StartDrawing(); + + PaintState_t paintState; + paintState.m_iTranslateX = paintState.m_iTranslateY = 0; + paintState.m_iScissorLeft = paintState.m_iScissorTop = 0; + GetScreenSize( paintState.m_iScissorRight, paintState.m_iScissorBottom ); + + SetupPaintState( paintState ); + + DrawSetColor( clr ); + DrawSetTexture( nTextureID ); + DrawTexturedRect( x + xOffset, y + yOffset, x + xOffset + w, y + yOffset + h ); + DrawSetTexture(0); + + FinishDrawing(); +} + +int CMatSystemSurface::GetTextureNumFrames( int id ) +{ + IMaterial *pMaterial = TextureDictionary()->GetTextureMaterial( id ); + if ( !pMaterial ) + { + return 0; + } + return pMaterial->GetNumAnimationFrames(); +} + +void CMatSystemSurface::DrawSetTextureFrame( int id, int nFrame, unsigned int *pFrameCache ) +{ + IMaterial *pMaterial = TextureDictionary()->GetTextureMaterial( id ); + if ( !pMaterial ) + { + return; + } + + int nTotalFrames = pMaterial->GetNumAnimationFrames(); + if ( !nTotalFrames ) + { + return; + } + + IMaterialVar *pFrameVar = pMaterial->FindVarFast( "$frame", pFrameCache ); + if ( pFrameVar ) + { + pFrameVar->SetIntValue( nFrame % nTotalFrames ); + } +} diff --git a/vguimatsurface/MatSystemSurface.h b/vguimatsurface/MatSystemSurface.h new file mode 100644 index 0000000..5be5bf3 --- /dev/null +++ b/vguimatsurface/MatSystemSurface.h @@ -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 diff --git a/vguimatsurface/TextureDictionary.cpp b/vguimatsurface/TextureDictionary.cpp new file mode 100644 index 0000000..d8fe072 --- /dev/null +++ b/vguimatsurface/TextureDictionary.cpp @@ -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; +} diff --git a/vguimatsurface/TextureDictionary.h b/vguimatsurface/TextureDictionary.h new file mode 100644 index 0000000..3fcb759 --- /dev/null +++ b/vguimatsurface/TextureDictionary.h @@ -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
\ No newline at end of file diff --git a/vguimatsurface/memorybitmap.cpp b/vguimatsurface/memorybitmap.cpp new file mode 100644 index 0000000..4cf6d36 --- /dev/null +++ b/vguimatsurface/memorybitmap.cpp @@ -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; +} + + diff --git a/vguimatsurface/memorybitmap.h b/vguimatsurface/memorybitmap.h new file mode 100644 index 0000000..408daad --- /dev/null +++ b/vguimatsurface/memorybitmap.h @@ -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 diff --git a/vguimatsurface/vguimatsurface.h b/vguimatsurface/vguimatsurface.h new file mode 100644 index 0000000..2c73875 --- /dev/null +++ b/vguimatsurface/vguimatsurface.h @@ -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 + + diff --git a/vguimatsurface/vguimatsurface.vpc b/vguimatsurface/vguimatsurface.vpc new file mode 100644 index 0000000..1f41c62 --- /dev/null +++ b/vguimatsurface/vguimatsurface.vpc @@ -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] + } +} diff --git a/vguimatsurface/xbox/xbox.def b/vguimatsurface/xbox/xbox.def new file mode 100644 index 0000000..f907212 --- /dev/null +++ b/vguimatsurface/xbox/xbox.def @@ -0,0 +1,3 @@ +LIBRARY vguimatsurface_360.dll +EXPORTS + CreateInterface @1 |