diff --git a/sp/src/game/client/client_mapbase.vpc b/sp/src/game/client/client_mapbase.vpc index 97a2217d3c..f8860e24ea 100644 --- a/sp/src/game/client/client_mapbase.vpc +++ b/sp/src/game/client/client_mapbase.vpc @@ -59,7 +59,11 @@ $Project $File "$SRCDIR\game\shared\mapbase\weapon_custom_scripted.cpp" [$MAPBASE_VSCRIPT] $File "$SRCDIR\game\shared\mapbase\weapon_custom_scripted.h" [$MAPBASE_VSCRIPT] $File "$SRCDIR\game\shared\mapbase\logic_script_client.cpp" [$MAPBASE_VSCRIPT] - + + $File "mapbase\vscript_vgui.cpp" [$MAPBASE_VSCRIPT] + $File "mapbase\vscript_vgui.h" [$MAPBASE_VSCRIPT] + $File "mapbase\vscript_vgui.nut" [$MAPBASE_VSCRIPT] + $File "mapbase\c_func_clientclip.cpp" $File "mapbase\c_func_fake_worldportal.cpp" $File "mapbase\c_func_fake_worldportal.h" diff --git a/sp/src/game/client/mapbase/vscript_vgui.cpp b/sp/src/game/client/mapbase/vscript_vgui.cpp new file mode 100644 index 0000000000..f2d66958a1 --- /dev/null +++ b/sp/src/game/client/mapbase/vscript_vgui.cpp @@ -0,0 +1,3208 @@ +//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + + +#include "cbase.h" +#include "tier1/utlcommon.h" + +#include "inputsystem/iinputsystem.h" +#include "iinput.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "matsys_controls/matsyscontrols.h" +#include "VGuiMatSurface/IMatSystemSurface.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "view.h" + +#include "vscript_vgui.h" +#include "vscript_vgui.nut" + + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +// +// +// Exposing a new panel class (e.g. vgui::FileOpenDialog): +// +// Create C++ bindings using 'CLASS_HELPER_INTERFACE( FileOpenDialog, Frame ){};' +// Define script bindings using 'DEFINE_VGUI_SCRIPTFUNC_FileOpenDialog()' +// Create 'class CScript_FileOpenDialog : FileOpenDialog' with vgui message callbacks and overrides (if needed) +// Create script helper using 'BEGIN_VGUI_HELPER( FileOpenDialog )', 'END_VGUI_HELPER()' +// Register script bindings with 'BEGIN_SCRIPTDESC_VGUI( FileOpenDialog )', 'END_SCRIPTDESC()' +// Add new condition in CScriptVGUI::Create +// +// +// +// CScript_FileOpenDialog_Helper +// ^^ +// IScript_FileOpenDialog << CScript_FileOpenDialog +// ^^ ^^ +// IScript_Frame FileOpenDialog +// ^^ ^^ +// IScript_Panel Frame +// ^^ ^^ +// CScriptVGUIObject Panel +// + + + +#ifdef _DEBUG +#define DebugMsg(...) ConColorMsg( Color(196, 196, 156, 255), __VA_ARGS__ ) +#define DebugWarning(...) Warning( __VA_ARGS__ ) +#define DebugDevMsg(...) DevMsg( __VA_ARGS__ ) + +#define DBG_PARAM(...) __VA_ARGS__ +#else +#define DebugMsg(...) (void)(0) +#define DebugWarning(...) (void)(0) +#define DebugDevMsg(...) (void)(0) + +#define DBG_PARAM(...) +#endif + + +#define surface() surface() + + +using namespace vgui; +class IScriptVGUIObject; +struct FontData_t; +template< typename T > class CCopyableUtlVectorConservative; + +// Aliases contain only one font definition unless 'yres' was defined +typedef CCopyableUtlVectorConservative< FontData_t > fontalias_t; +typedef CUtlDict< fontalias_t > CFontDict; + +template< typename T > +class CCopyableUtlVectorConservative : public CUtlVectorConservative< T > +{ + typedef CUtlVectorConservative< T > BaseClass; +public: + explicit CCopyableUtlVectorConservative( int growSize = 0, int initSize = 0 ) : BaseClass( growSize, initSize ) {} + explicit CCopyableUtlVectorConservative( T* pMemory, int numElements ) : BaseClass( pMemory, numElements ) {} + CCopyableUtlVectorConservative( CCopyableUtlVectorConservative const& vec ) { this->CopyArray( vec.Base(), vec.Count() ); } +}; + + + +CFontDict g_ScriptFonts( k_eDictCompareTypeCaseSensitive ); +CUtlVector< int > g_ScriptTextureIDs; +CUtlVector< IScriptVGUIObject* > g_ScriptPanels; + + +// Boundary is not checked in Surface, keep count manually to sanitise user input. +static int g_nFontCount = 0; + +static inline HFont IntToFontHandle( int i ) +{ + if ( i < 0 || i > g_nFontCount ) + return INVALID_FONT; + return static_cast< unsigned int >(i); +} + +static inline int HandleToInt( unsigned int i ) +{ + Assert( i <= INT_MAX ); + return static_cast< int >(i); +} + + +struct FontData_t +{ + HFont font; + char *name; + int tall; + int weight; + int blur; + int scanlines; + int flags; + //int range_min; + //int range_max; + int yres_min; + int yres_max; + bool proportional; +}; + +static const char *GetFixedFontName( const char *name, bool proportional ) +{ + static char fontName[64]; + V_snprintf( fontName, sizeof(fontName), "%s-%s", name, proportional ? "p" : "no" ); + return fontName; +} + +CON_COMMAND( vgui_spew_fonts_script, "" ) +{ + char fontName[64]; + + FOR_EACH_DICT_FAST( g_ScriptFonts, i ) + { + const FontData_t &data = g_ScriptFonts[i].Head(); + const char *name = surface()->GetFontName( data.font ); + const char *alias = g_ScriptFonts.GetElementName(i); + + // Strip off the appendix "-p" / "-no" + V_StrLeft( alias, V_strlen(alias) - (data.proportional ? 2 : 3), fontName, sizeof(fontName) ); + + Msg( " %2d: HFont:0x%8.8x, %s, %s, font:%s, tall:%d(%d) {%d}\n", + i, + data.font, + fontName, + alias, + name ? name : "??", + surface()->GetFontTall( data.font ), + surface()->GetFontTallRequested( data.font ), + g_ScriptFonts[i].Count() ); + } +} + +bool LoadFont( const FontData_t &font DBG_PARAM(, const char *fontAlias) ) +{ + if ( font.yres_min ) + { + int nScreenWide, nScreenTall; + surface()->GetScreenSize( nScreenWide, nScreenTall ); + + if ( nScreenTall < font.yres_min ) + return false; + + if ( font.yres_max && nScreenTall > font.yres_max ) + return false; + } + + int tall = font.tall; + int blur = font.blur; + int scanlines = font.scanlines; + + if ( font.proportional && !font.yres_min ) + { + tall = scheme()->GetProportionalScaledValue( tall ); + blur = scheme()->GetProportionalScaledValue( blur ); + scanlines = scheme()->GetProportionalScaledValue( scanlines ); + } + + bool bSuccess = surface()->SetFontGlyphSet( + font.font, + font.name, + tall, + font.weight, + blur, + scanlines, + font.flags ); + + NOTE_UNUSED( bSuccess ); + if ( bSuccess ) + { + if ( font.yres_min ) + DebugMsg( "Load font [%i]%s [%d %d]\n", font.font, fontAlias, font.yres_min, font.yres_max ); + else + DebugMsg( "Load font [%i]%s\n", font.font, fontAlias ); + } + else + { + DebugWarning( "Failed to load font [%i]%s\n", font.font, fontAlias ); + } + + return true; +} + +void ReloadFontGlyphs() +{ + FOR_EACH_DICT_FAST( g_ScriptFonts, i ) + { + const fontalias_t &alias = g_ScriptFonts[i]; + for ( int j = 0; j < alias.Count(); ++j ) + { + if ( LoadFont( alias.Element(j) DBG_PARAM(, g_ScriptFonts.GetElementName(i)) ) ) + break; + } + } +} + + +static inline void InitRootPanel( Panel *p, VGuiPanel_t parent, const char *name ) +{ + int w, h; + surface()->GetScreenSize( w, h ); + p->Init( 0, 0, w, h ); + p->SetName( name ); + p->SetVisible( true ); + p->SetPaintEnabled( false ); + p->SetPaintBackgroundEnabled( false ); + p->SetPaintBorderEnabled( false ); + p->SetParent( enginevgui->GetPanel( parent ) ); +} + +class CScriptRootPanel : public Panel +{ +public: + CScriptRootPanel() + { + InitRootPanel( this, PANEL_ROOT, "VScriptRoot" ); + } + + void OnTick() + { + if ( m_nLastFrame >= gpGlobals->framecount ) + return; + + ReloadFontGlyphs(); + ivgui()->RemoveTickSignal( GetVPanel() ); + } + + void OnScreenSizeChanged( int, int ) + { + // Reload fonts in the next vgui frame + ivgui()->AddTickSignal( GetVPanel() ); + m_nLastFrame = gpGlobals->framecount; + + // Invalidate cached values + if ( g_pScriptVM ) + g_pScriptVM->Run( "ISurface.__OnScreenSizeChanged()" ); + } + +private: + int m_nLastFrame; +}; + +CScriptRootPanel *g_pScriptRootPanel = NULL; + +#if SCRIPT_ENGINE_ROOT_PANELS +class CScriptRootDLLPanel : public Panel +{ +public: + CScriptRootDLLPanel( VGuiPanel_t parent, const char *name ) + { + InitRootPanel( this, parent, name ); + } +}; + +CScriptRootDLLPanel *g_pScriptClientDLLPanel = NULL; +CScriptRootDLLPanel *g_pScriptGameUIDLLPanel = NULL; +#endif + +void VGUI_DestroyScriptRootPanels() +{ + if ( g_pScriptRootPanel ) + { + delete g_pScriptRootPanel; + g_pScriptRootPanel = NULL; + } +#if SCRIPT_ENGINE_ROOT_PANELS + if ( g_pScriptClientDLLPanel ) + { + delete g_pScriptClientDLLPanel; + g_pScriptClientDLLPanel = NULL; + } + + if ( g_pScriptGameUIDLLPanel ) + { + delete g_pScriptGameUIDLLPanel; + g_pScriptGameUIDLLPanel = NULL; + } +#endif +} + +VPANEL VGUI_GetScriptRootPanel( VGuiPanel_t type ) +{ +#if !SCRIPT_ENGINE_ROOT_PANELS + if ( !g_pScriptRootPanel ) + g_pScriptRootPanel = new CScriptRootPanel(); + + return enginevgui->GetPanel( type ); +#else + switch ( type ) + { + case PANEL_ROOT: + { + if ( !g_pScriptRootPanel ) + g_pScriptRootPanel = new CScriptRootPanel(); + + return g_pScriptRootPanel->GetVPanel(); + } + case PANEL_CLIENTDLL: + { + if ( !g_pScriptClientDLLPanel ) + g_pScriptClientDLLPanel = new CScriptRootDLLPanel( PANEL_CLIENTDLL, "VScriptClient" ); + + return g_pScriptClientDLLPanel->GetVPanel(); + } + case PANEL_GAMEUIDLL: + { + if ( !g_pScriptGameUIDLLPanel ) + g_pScriptGameUIDLLPanel = new CScriptRootDLLPanel( PANEL_GAMEUIDLL, "VScriptGameUI" ); + + return g_pScriptGameUIDLLPanel->GetVPanel(); + } + } + return NULL; +#endif +} + + +//-------------------------------------------------------------- +// +//-------------------------------------------------------------- +class CScriptSurface +{ +public: + void PlaySound( const char* sound ); + void SetColor( int r, int g, int b, int a ); + void DrawFilledRect( int x0, int y0, int width, int height ); + void DrawFilledRectFade( int x0, int y0, int width, int height, int a0, int a1, bool bHorz ); + void DrawOutlinedRect( int x0, int y0, int width, int height, int thickness ); + void DrawLine( int x0, int y0, int x1, int y1 ); + void DrawPolyLine( HSCRIPT ax, HSCRIPT ay, int count ); + //void DrawTexturedPolygon(); + void DrawOutlinedCircle( int x, int y, int radius, int segments ); + //void DrawColoredCircle( int x, int y, int radius, int r, int g, int b, int a ); + + void SetTextColor( int r, int g, int b, int a ); + void SetTextPos( int x, int y ); + void DrawText( const char *text, int drawType = FONT_DRAW_DEFAULT ); + //void DrawUnicodeChar( int ch, int drawType = FONT_DRAW_DEFAULT ); + + int GetFont( const char* name, bool proportional, const char* schema ); + void SetFont( int font ); + int GetTextWidth( int font, const char* text ); + int GetFontTall( int font ); + int GetCharacterWidth( int font, int ch ); + + void CreateFont( const char *customName, const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags, int yresMin, int yresMax, bool proportional ); + bool AddCustomFontFile( const char *fontFileName ); + int GetTextureID( char const *filename ); + int ValidateTexture( const char *filename, bool hardwareFilter, bool forceReload, bool procedural ); + void SetTextureFile( int id, const char *filename, bool hardwareFilter ); + //int ValidateMaterial( const char *materialName, const char *textureGroupName ); + int GetTextureWide( int id ); + int GetTextureTall( int id ); + void SetTexture( int id ); + + void DrawTexturedRect( int x0, int y0, int width, int height ); + void DrawTexturedSubRect( int x0, int y0, int x1, int y1, float texs0, float text0, float texs1, float text1 ); + + // ------------------------------------------------------------ + // Utility functions + // ------------------------------------------------------------ + + void DrawTexturedBox( int texture, int x, int y, int wide, int tall, int r, int g, int b, int a ); + void DrawColoredText( int font, int x, int y, int r, int g, int b, int a, const char *text ); + void DrawColoredTextRect( int font, int x, int y, int w, int h, int r, int g, int b, int a, const char *text ); + +} script_surface; + +BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptSurface, "ISurface", SCRIPT_SINGLETON ) + DEFINE_SCRIPTFUNC( PlaySound, "" ) + + DEFINE_SCRIPTFUNC( SetColor, "" ) + DEFINE_SCRIPTFUNC( DrawFilledRect, "" ) + DEFINE_SCRIPTFUNC( DrawFilledRectFade, "" ) + DEFINE_SCRIPTFUNC( DrawOutlinedRect, "" ) + DEFINE_SCRIPTFUNC( DrawLine, "" ) + DEFINE_SCRIPTFUNC( DrawPolyLine, "" ) + DEFINE_SCRIPTFUNC( DrawOutlinedCircle, "" ) + + DEFINE_SCRIPTFUNC( SetTextColor, "" ) + DEFINE_SCRIPTFUNC( SetTextPos, "" ) + DEFINE_SCRIPTFUNC( DrawText, "" ) + + DEFINE_SCRIPTFUNC( GetFont, "" ) + DEFINE_SCRIPTFUNC( SetFont, "" ) + DEFINE_SCRIPTFUNC( GetTextWidth, "" ) + DEFINE_SCRIPTFUNC( GetFontTall, "" ) + DEFINE_SCRIPTFUNC( GetCharacterWidth, "" ) + + DEFINE_SCRIPTFUNC( CreateFont, SCRIPT_HIDE ) + DEFINE_SCRIPTFUNC( AddCustomFontFile, "" ) + + DEFINE_SCRIPTFUNC( GetTextureID, "" ) + DEFINE_SCRIPTFUNC( ValidateTexture, "" ) + DEFINE_SCRIPTFUNC( SetTextureFile, "" ) + DEFINE_SCRIPTFUNC( GetTextureWide, "" ) + DEFINE_SCRIPTFUNC( GetTextureTall, "" ) + DEFINE_SCRIPTFUNC( SetTexture, "" ) + + DEFINE_SCRIPTFUNC( DrawTexturedRect, "" ) + DEFINE_SCRIPTFUNC( DrawTexturedSubRect, "" ) + + DEFINE_SCRIPTFUNC( DrawTexturedBox, "" ) + DEFINE_SCRIPTFUNC( DrawColoredText, "" ) + DEFINE_SCRIPTFUNC( DrawColoredTextRect, "" ) +END_SCRIPTDESC() + + +void CScriptSurface::PlaySound( const char* sound ) +{ + surface()->PlaySound(sound); +} + +void CScriptSurface::SetColor( int r, int g, int b, int a ) +{ + surface()->DrawSetColor( r, g, b, a ); +} + +void CScriptSurface::DrawFilledRect( int x0, int y0, int width, int height ) +{ + surface()->DrawFilledRect( x0, y0, x0 + width, y0 + height ); +} + +void CScriptSurface::DrawFilledRectFade( int x0, int y0, int width, int height, int a0, int a1, bool bHorz ) +{ + surface()->DrawFilledRectFade( x0, y0, x0 + width, y0 + height, a0, a1, bHorz ); +} + +void CScriptSurface::DrawOutlinedRect( int x0, int y0, int width, int height, int thickness ) +{ + int x1 = x0 + width; + int y1 = y0 + height - thickness; + y0 += thickness; + + surface()->DrawFilledRect( x0, y0 - thickness, x1, y0 ); // top + surface()->DrawFilledRect( x1 - thickness, y0, x1, y1 ); // right + surface()->DrawFilledRect( x0, y1, x1, y1 + thickness ); // bottom + surface()->DrawFilledRect( x0, y0, x0 + thickness, y1 ); // left +} + +void CScriptSurface::DrawLine( int x0, int y0, int x1, int y1 ) +{ + surface()->DrawLine( x0, y0, x1, y1 ); +} + +void CScriptSurface::DrawPolyLine( HSCRIPT ax, HSCRIPT ay, int count ) +{ + if (count < 1) + return; + + if (count > 4096) + count = 4096; + + int *px = (int*)stackalloc( count * sizeof(int) ); + int *py = (int*)stackalloc( count * sizeof(int) ); + ScriptVariant_t vx, vy; + + int i = count; + while ( i-- ) + { + g_pScriptVM->GetValue( ax, i, &vx ); + g_pScriptVM->GetValue( ay, i, &vy ); + + px[i] = vx.m_int; + py[i] = vy.m_int; + } + + surface()->DrawPolyLine( px, py, count ); +} + +void CScriptSurface::DrawOutlinedCircle( int x, int y, int radius, int segments ) +{ + surface()->DrawOutlinedCircle( x, y, radius, segments ); +} + +void CScriptSurface::SetTextColor( int r, int g, int b, int a ) +{ + surface()->DrawSetTextColor( r, g, b, a ); +} + +void CScriptSurface::SetTextPos( int x, int y ) +{ + surface()->DrawSetTextPos( x, y ); +} + +void CScriptSurface::DrawText( const char *text, int drawType/* = FONT_DRAW_DEFAULT*/ ) +{ + wchar_t wcs[512]; + g_pVGuiLocalize->ConvertANSIToUnicode( text, wcs, sizeof(wcs) ); + surface()->DrawPrintText( wcs, wcslen(wcs), (FontDrawType_t)drawType ); +} + +int CScriptSurface::GetFont( const char* name, bool proportional, const char* schema ) +{ + HFont font = INVALID_FONT; + + if ( !schema || !schema[0] ) + { + int idx = g_ScriptFonts.Find( GetFixedFontName( name, proportional ) ); + if ( idx != g_ScriptFonts.InvalidIndex() ) + { + font = g_ScriptFonts[idx].Head().font; + } + } + else + { + HScheme sch = scheme()->GetScheme( schema ); + font = scheme()->GetIScheme(sch)->GetFont( name, proportional ); + + // Update known count + if ( font > (unsigned int)g_nFontCount ) + g_nFontCount = font; + } + + return HandleToInt( font ); +} + +void CScriptSurface::SetFont( int font ) +{ + surface()->DrawSetTextFont( IntToFontHandle(font) ); +} + +int CScriptSurface::GetTextWidth( int font, const char* text ) +{ + int w, t; + wchar_t wcs[512]; + g_pVGuiLocalize->ConvertANSIToUnicode( text, wcs, sizeof(wcs) ); + surface()->GetTextSize( IntToFontHandle(font), wcs, w, t ); + return w; +} + +int CScriptSurface::GetFontTall( int font ) +{ + return surface()->GetFontTall( IntToFontHandle(font) ); +} + +int CScriptSurface::GetCharacterWidth( int font, int ch ) +{ + return surface()->GetCharacterWidth( IntToFontHandle(font), ch ); +} + +void CScriptSurface::CreateFont( const char *customName, const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags, int yresMin, int yresMax, bool proportional ) +{ + if ( flags & ISurface::FONTFLAG_BITMAP ) + { + AssertMsg( 0, "Bitmap fonts are not supported!" ); + return; + } + + if ( proportional && yresMin ) + { + AssertMsg( 0, "Resolution cannot be defined on a proportional font!" ); + return; + } + + if ( (yresMin < 0 || yresMax < 0) || (!!yresMin != !!yresMax) ) + { + AssertMsg( 0, "Invalid resolution!" ); + return; + } + + const char *fontAlias = GetFixedFontName( customName, proportional ); + + int idx = g_ScriptFonts.Find( fontAlias ); + if ( idx != g_ScriptFonts.InvalidIndex() ) + { + fontalias_t &alias = g_ScriptFonts[idx]; + // TODO: One proportional font to fall back to amongst resolution filtered fonts. + + // if input resolutions match any of the existing fonts, + // then this must be a duplicate call. +#ifdef _DEBUG + if ( !yresMin && !yresMax ) + { + // There must be only one font registered. + Assert( alias.Count() == 1 ); + + HFont font = alias.Head().font; + int oldTall = surface()->GetFontTallRequested( font ); + int newTall = proportional ? scheme()->GetProportionalScaledValue( tall ) : tall; + const char *oldName = surface()->GetFontName( font ); + Assert( oldTall == newTall ); + Assert( !V_stricmp( oldName, windowsFontName ) ); + } +#endif + + for ( int i = 0; i < alias.Count(); ++i ) + { + FontData_t &data = alias.Element(i); + + if ( yresMin == data.yres_min && yresMax == data.yres_max ) + return; + } + + DebugMsg( "Create font add '%s' [%d %d]\n", fontAlias, yresMin, yresMax ); + + FontData_t &newFont = alias.Element( alias.AddToTail() ); +#ifdef _DEBUG + V_memset( &newFont, 0, sizeof(FontData_t) ); +#endif + newFont.font = alias.Head().font; + newFont.name = strdup( windowsFontName ); + newFont.tall = tall; + newFont.weight = weight; + newFont.blur = blur; + newFont.scanlines = scanlines; + newFont.flags = flags; + newFont.yres_min = yresMin; + newFont.yres_max = yresMax; + newFont.proportional = proportional; + + LoadFont( newFont DBG_PARAM(, fontAlias) ); + } + else + { + HFont font = surface()->CreateFont(); + + // Sanity check + Assert( font > (unsigned int)g_nFontCount && font < INT_MAX ); + + // Update known count + if ( font > (unsigned int)g_nFontCount ) + g_nFontCount = font; + + if ( yresMax && yresMin > yresMax ) + { + int t = yresMin; + yresMin = yresMax; + yresMax = t; + } + + if ( yresMin ) + DebugMsg( "Create font new '%s' [%d %d]\n", fontAlias, yresMin, yresMax ); + else + DebugMsg( "Create font new '%s'\n", fontAlias ); + + fontalias_t &alias = g_ScriptFonts.Element( g_ScriptFonts.Insert( fontAlias ) ); + FontData_t &newFont = alias.Element( alias.AddToTail() ); +#ifdef _DEBUG + V_memset( &newFont, 0, sizeof(FontData_t) ); +#endif + newFont.font = font; + newFont.name = strdup( windowsFontName ); + newFont.tall = tall; + newFont.weight = weight; + newFont.blur = blur; + newFont.scanlines = scanlines; + newFont.flags = flags; + newFont.yres_min = yresMin; + newFont.yres_max = yresMax; + newFont.proportional = proportional; + + LoadFont( newFont DBG_PARAM(, fontAlias) ); + } +} + +bool CScriptSurface::AddCustomFontFile( const char *fontFileName ) +{ + return surface()->AddCustomFontFile( NULL, fontFileName ); +} + +int CScriptSurface::GetTextureID( char const *filename ) +{ + return surface()->DrawGetTextureId( filename ); +} + +// Create texture if it does not already exist +int CScriptSurface::ValidateTexture( const char *filename, bool hardwareFilter, bool forceReload, bool procedural ) +{ + int id = surface()->DrawGetTextureId( filename ); + if ( id <= 0 ) + { + id = surface()->CreateNewTextureID( procedural ); + g_ScriptTextureIDs.AddToTail( id ); + + surface()->DrawSetTextureFile( id, filename, hardwareFilter, forceReload ); + +#ifdef _DEBUG + char tex[MAX_PATH]; + surface()->DrawGetTextureFile( id, tex, sizeof(tex)-1 ); + if ( !V_stricmp( filename, tex ) ) + { + DebugMsg( "Create texture [%i]%s\n", id, filename ); + } + else + { + DebugWarning( "Create texture [%i]%s(%s)\n", id, tex, filename ); + } +#endif + } + else if ( forceReload && g_ScriptTextureIDs.HasElement( id ) ) + { + surface()->DrawSetTextureFile( id, filename, hardwareFilter, forceReload ); + } + else + { + surface()->DrawSetTexture( id ); + } + + return id; +} + +// Replace existing texture +void CScriptSurface::SetTextureFile( int id, const char *filename, bool hardwareFilter ) +{ + if ( g_ScriptTextureIDs.HasElement(id) ) + { + Assert( surface()->IsTextureIDValid(id) ); + surface()->DrawSetTextureFile( id, filename, hardwareFilter, true ); + +#ifdef _DEBUG + char tex[MAX_PATH]; + surface()->DrawGetTextureFile( id, tex, sizeof(tex)-1 ); + if ( !V_stricmp( filename, tex ) ) + { + DebugMsg( "Set texture [%i]%s\n", id, filename ); + } + else + { + DebugWarning( "Set texture [%i]%s(%s)\n", id, tex, filename ); + } +#endif + } + +#ifdef _DEBUG + if ( !g_ScriptTextureIDs.HasElement(id) && surface()->IsTextureIDValid(id) ) + { + DebugWarning( "Tried to set non-script created texture! [%i]%s\n", id, filename ); + } + + if ( !surface()->IsTextureIDValid(id) ) + { + DebugWarning( "Tried to set invalid texture id! [%i]%s\n", id, filename ); + } +#endif +} + +int CScriptSurface::GetTextureWide( int id ) +{ + int w, t; + surface()->DrawGetTextureSize( id, w, t ); + return w; +} + +int CScriptSurface::GetTextureTall( int id ) +{ + int w, t; + surface()->DrawGetTextureSize( id, w, t ); + return t; +} + +void CScriptSurface::SetTexture( int id ) +{ + surface()->DrawSetTexture( id ); +} + +void CScriptSurface::DrawTexturedRect( int x0, int y0, int width, int height ) +{ + surface()->DrawTexturedRect( x0, y0, x0 + width, y0 + height ); +} + +void CScriptSurface::DrawTexturedSubRect( int x0, int y0, int x1, int y1, float texs0, float text0, float texs1, float text1 ) +{ + surface()->DrawTexturedSubRect( x0, y0, x1, y1, texs0, text0, texs1, text1 ); +} +#if 0 +void CScriptSurface::DrawTexturedRectUV( int x, int y, int w, int t, float uvx, float uvy, float uvw, float uvh ) +{ + Vertex_t verts[4]; + + verts[0].m_Position.Init( x, y ); + verts[0].m_TexCoord.Init( uvx, uvy ); + + verts[1].m_Position.Init( x+w, y ); + verts[1].m_TexCoord.Init( uvx+uvw, uvy ); + + verts[2].m_Position.Init( x+w, y+t ); + verts[2].m_TexCoord.Init( uvx+uvw, uvy+uvh ); + + verts[3].m_Position.Init( x, y+t ); + verts[3].m_TexCoord.Init( uvx, uvy+uvh ); + + surface()->DrawTexturedPolygon( 4, verts ); +} +#endif +void CScriptSurface::DrawTexturedBox( int texture, int x, int y, int wide, int tall, int r, int g, int b, int a ) +{ + surface()->DrawSetColor( r, g, b, a ); + surface()->DrawSetTexture( texture ); + surface()->DrawTexturedRect( x, y, x + wide, y + tall ); +} + +void CScriptSurface::DrawColoredText( int font, int x, int y, int r, int g, int b, int a, const char *text ) +{ + wchar_t wcs[512]; + g_pVGuiLocalize->ConvertANSIToUnicode( text, wcs, sizeof(wcs) ); + + surface()->DrawSetTextFont( IntToFontHandle(font) ); + surface()->DrawSetTextColor( r, g, b, a ); + surface()->DrawSetTextPos( x, y ); + surface()->DrawPrintText( wcs, wcslen(wcs) ); +} + +void CScriptSurface::DrawColoredTextRect( int font, int x, int y, int w, int h, int r, int g, int b, int a, const char *text ) +{ + MatSystemSurface()->DrawColoredTextRect( IntToFontHandle(font), x, y, w, h, r, g, b, a, text ); +} + + +//============================================================== +//============================================================== + +#define Base() this->_base + +#define BEGIN_SCRIPTDESC_VGUI( name )\ + BEGIN_SCRIPTDESC_NAMED( CScript_##name##_Helper, IScriptVGUIObject, #name, "" )\ + DEFINE_VGUI_SCRIPTFUNC_##name() + +#define DECLARE_SCRIPTVGUI_HELPER( panelClass )\ + void Create( const char *panelName ) override\ + {\ + Assert( !_base && !_vpanel );\ + _base = new panelClass( NULL, panelName );\ + } + +#define DECLARE_SCRIPTVGUI_HELPER_DEFAULT_TEXT( panelClass )\ + void Create( const char *panelName ) override\ + {\ + Assert( !_base && !_vpanel );\ + _base = new panelClass( NULL, panelName, (const char*)NULL );\ + } + +#define DEFINE_REDIRECT( retType, fnName )\ + retType fnName()\ + {\ + return Base()->##fnName();\ + } +#define DEFINE_REDIRECT_1( retType, fnName, t1 )\ + retType fnName( t1 a1 )\ + {\ + return Base()->##fnName( a1 );\ + } +#define DEFINE_REDIRECT_2( retType, fnName, t1, t2 )\ + retType fnName( t1 a1, t2 a2 )\ + {\ + return Base()->##fnName( a1, a2 );\ + } + +// +// Script helpers are wrappers that only redirect to actual vgui objects (such as CScript_Panel : Panel), +// these macros help to simplify definitions. +// +#define BEGIN_VGUI_HELPER( panelClass )\ + class CScript_##panelClass##_Helper : public IScript_##panelClass< CScript_##panelClass >\ + {\ + DECLARE_SCRIPTVGUI_HELPER( CScript_##panelClass )\ +\ + public: +#define BEGIN_VGUI_HELPER_DEFAULT_TEXT( panelClass )\ + class CScript_##panelClass##_Helper : public IScript_##panelClass< CScript_##panelClass >\ + {\ + DECLARE_SCRIPTVGUI_HELPER_DEFAULT_TEXT( CScript_##panelClass )\ +\ + public: +#define END_VGUI_HELPER()\ + }; + +// +// Macros to hide internal class names +// +#define CLASS_HELPER_INTERFACE_ROOT( panelClass )\ + template \ + class IScript_##panelClass : public CScriptVGUIObject + +#define CLASS_HELPER_INTERFACE( panelClass, baseClass )\ + template \ + class IScript_##panelClass : public IScript_##baseClass + + +#ifdef _DEBUG +#define DebugDestructor( panelClass )\ + ~CScript_##panelClass()\ + {\ + DebugDevMsg( " ~" #panelClass "() '%s'\n", GetName() );\ + } +#else +#define DebugDestructor( panelClass ) +#endif + + +#define DECLARE_SCRIPTVGUI_CLASS( panelClass )\ + typedef panelClass BaseClass;\ + typedef CScript_##panelClass ThisClass;\ +public:\ + DebugDestructor( panelClass )\ + DECLARE_SCRIPTVGUI_CLASS_INTERNAL( panelClass ) + +#define DECLARE_SCRIPTVGUI_CLASS_INTERNAL( panelClass )\ +public:\ + void OnDelete()\ + {\ + DebugMsg( #panelClass "::OnDelete() '%s'\n", GetName() );\ + IScriptVGUIObject *obj = FindInScriptPanels( GetVPanel() );\ + if ( obj )\ + {\ + obj->Destroy();\ + }\ + BaseClass::OnDelete();\ + } + +// +// Definitions for 'empty' vgui objects that do not have any script specific implementation - overrides or callbacks. +// These are required to shutdown script objects on panel death +// (on save restore where panel destructor is called after the VM is restarted while HSCRIPT members are invalid but not nullified, +// and on C++ deletion where IScriptVGUIObject::Destroy() is not automatically called). +// +#define DEFINE_VGUI_CLASS_EMPTY( panelClass )\ + class CScript_##panelClass : public panelClass\ + {\ + DECLARE_SCRIPTVGUI_CLASS( panelClass )\ + void Shutdown() {}\ +\ + public:\ + CScript_##panelClass( Panel *parent, const char *name )\ + : BaseClass( parent, name )\ + {}\ + };\ +\ + BEGIN_VGUI_HELPER( panelClass )\ + END_VGUI_HELPER()\ +\ + BEGIN_SCRIPTDESC_VGUI( panelClass )\ + END_SCRIPTDESC() + +#define DEFINE_VGUI_CLASS_EMPTY_DEFAULT_TEXT( panelClass )\ + class CScript_##panelClass : public panelClass\ + {\ + DECLARE_SCRIPTVGUI_CLASS( panelClass )\ + void Shutdown() {}\ +\ + public:\ + CScript_##panelClass( Panel *parent, const char *name, const char *text )\ + : BaseClass( parent, name, text )\ + {}\ + };\ +\ + BEGIN_VGUI_HELPER_DEFAULT_TEXT( panelClass )\ + END_VGUI_HELPER()\ +\ + BEGIN_SCRIPTDESC_VGUI( panelClass )\ + END_SCRIPTDESC() + +class IScriptVGUIObject +{ +public: +#ifdef _DEBUG + virtual const char *GetName() = 0; +#endif + //----------------------------------------------------- + // Free the VGUI panel and script instance. + //----------------------------------------------------- + virtual void Destroy() = 0; + + //----------------------------------------------------- + // Create new panel + //----------------------------------------------------- + virtual void Create( const char *panelName ) = 0; + +public: + VPANEL GetVPanel() { return _vpanel; } + HSCRIPT GetScriptInstance() { return m_hScriptInstance; } + +protected: + VPANEL _vpanel; + HSCRIPT m_hScriptInstance; + + // Called on deletion + static void ResolveChildren( VPANEL panel DBG_PARAM(, int level) ); +}; + +BEGIN_SCRIPTDESC_ROOT( IScriptVGUIObject, SCRIPT_HIDE ) +END_SCRIPTDESC() + + +IScriptVGUIObject *ToScriptVGUIObj( HSCRIPT inst ) +{ + return (IScriptVGUIObject *)g_pScriptVM->GetInstanceValue( inst, ::GetScriptDesc( (IScriptVGUIObject *)0 ) ); +} + +inline IScriptVGUIObject *FindInScriptPanels( VPANEL panel ) +{ + FOR_EACH_VEC( g_ScriptPanels, i ) + { + IScriptVGUIObject *obj = g_ScriptPanels[i]; + if ( obj->GetVPanel() == panel ) + return obj; + } + return NULL; +} + +void IScriptVGUIObject::ResolveChildren( VPANEL panel DBG_PARAM(, int level = 0) ) +{ +#ifdef _DEBUG + char indent[32]; + + if ( level > 30 ) + level = 30; + + int i = 0; + while ( i < level ) + { + indent[i++] = ' '; + indent[i++] = ' '; + } + indent[i] = 0; +#endif + + CUtlVector< VPANEL > &children = ipanel()->GetChildren( panel ); + FOR_EACH_VEC_BACK( children, i ) + { + VPANEL child = children[i]; + FOR_EACH_VEC( g_ScriptPanels, j ) + { + IScriptVGUIObject *obj = g_ScriptPanels[j]; + if ( obj->GetVPanel() == child ) + { + if ( ipanel()->IsAutoDeleteSet(child) ) + { + DebugMsg( " %sResolveChildren: '%s' (autodelete)\n", indent, obj->GetName() ); + + if ( g_pScriptVM ) + g_pScriptVM->RemoveInstance( obj->m_hScriptInstance ); + obj->m_hScriptInstance = NULL; + obj->_vpanel = NULL; + g_ScriptPanels.FastRemove( j ); + ResolveChildren( child DBG_PARAM(, level+1) ); + } + else + { + // Panel::SetAutoDelete is disabled until + // what to do on their parent death is finalised. + // + // This assert will be hit if a deleted panel has + // C++ created and autodelete disabled children who are + // also registered to script. + Assert(0); + DebugMsg( " %sResolveChildren: '%s'\n", indent, obj->GetName() ); + // ipanel()->SetParent( child, NULL ); + } + break; + } + } + } +} + +template +class CScriptVGUIObject : public IScriptVGUIObject +{ +public: + T *_base; + + CScriptVGUIObject() : _base(0) + { + _vpanel = 0; + m_hScriptInstance = 0; + } + + ~CScriptVGUIObject() + { + DebugMsg( "~CScriptVGUIObject()\n" ); + Destroy(); + } + + void Destroy() + { + if ( GetVPanel() ) + { + DebugMsg( " Destroy panel '%s'\n", _base->GetName() ); + _base->Shutdown(); + ResolveChildren( _vpanel ); + _base->MarkForDeletion(); + _vpanel = NULL; + } + + if ( m_hScriptInstance ) + { + if ( g_pScriptVM ) + g_pScriptVM->RemoveInstance( m_hScriptInstance ); + m_hScriptInstance = NULL; + } + } + + template + void CreateFromScript( HSCRIPT parent, const char *panelName, int root ) + { + Assert( !_vpanel && !m_hScriptInstance && !g_ScriptPanels.HasElement( this ) ); + + g_ScriptPanels.AddToTail( this ); + + Create( panelName && *panelName ? panelName : NULL ); + _vpanel = _base->GetVPanel(); + m_hScriptInstance = g_pScriptVM->RegisterInstance< CHelper >( static_cast< CHelper* >( this ) ); + + if ( parent ) + { + IScriptVGUIObject *obj = ToScriptVGUIObj( parent ); + if ( obj ) + { + _base->SetParent( obj->GetVPanel() ); + return; + } + + AssertMsg( 0, "invalid parent" ); + } + + VPANEL hParent = 0; + + // Script specified engine root panel. + // Match the values to vscript_vgui.nut. + // + // This parameter is hidden in script, and is defined by the return value of dummy functions. + switch ( root ) + { + case 0: + hParent = VGUI_GetScriptRootPanel( PANEL_ROOT ); + break; + case 1: + hParent = VGUI_GetScriptRootPanel( PANEL_GAMEUIDLL ); + break; + case 2: + hParent = VGUI_GetScriptRootPanel( PANEL_CLIENTDLL ); + break; + } + + _base->SetParent( hParent ); + } +}; + +//-------------------------------------------------------------- +//-------------------------------------------------------------- + +CLASS_HELPER_INTERFACE_ROOT( Panel ) +{ +public: + void MakeReadyForUse() + { + Base()->MakeReadyForUse(); + } + + const char *GetName() + { + return Base()->GetName(); + } +#if 0 + void SetAutoDelete( bool i ) + { + Base()->SetAutoDelete(i); + } +#endif + void AddTickSignal( int i ) + { + ivgui()->AddTickSignal( this->GetVPanel(), i ); + } +#if VGUI_SIGNAL_INTERFACE + void AddActionSignalTarget( HSCRIPT messageTarget ) + { + IScriptVGUIObject *obj = ToScriptVGUIObj( messageTarget ); + if ( obj ) + { + Base()->AddActionSignalTarget( obj->GetVPanel() ); + } + } +#endif + //----------------------------------------------------- + // Get script created parent + //----------------------------------------------------- + HSCRIPT GetParent() + { + VPANEL parent = ipanel()->GetParent( this->GetVPanel() ); + if ( !parent ) + return NULL; + + IScriptVGUIObject* obj = FindInScriptPanels( parent ); + if ( obj ) + { + // My parent can't be invalid. + Assert( ToScriptVGUIObj( obj->GetScriptInstance() ) ); + + return obj->GetScriptInstance(); + } + +#ifdef _DEBUG + // Is my parent one of the root panels? + bool b = false; +#if SCRIPT_ENGINE_ROOT_PANELS + if ( parent == g_pScriptRootPanel->GetVPanel() || + parent == g_pScriptClientDLLPanel->GetVPanel() || + parent == g_pScriptGameUIDLLPanel->GetVPanel() ) + { + b = true; + } + else +#endif + for ( int i = PANEL_ROOT; i <= PANEL_CLIENTDLL_TOOLS; ++i ) + { + if ( parent == enginevgui->GetPanel( (VGuiPanel_t)i ) ) + { + b = true; + break; + } + } + + // My parent wasn't registered. + AssertMsg1( b, "'%s'", ipanel()->GetName(parent) ); +#endif + + return NULL; + } + + //----------------------------------------------------- + // Set script created parent + //----------------------------------------------------- + void SetParent( HSCRIPT parent ) + { + if ( !parent ) + { + Base()->SetParent( (VPANEL)NULL ); + return; + } + + IScriptVGUIObject *obj = ToScriptVGUIObj( parent ); + if ( obj ) + { + Base()->SetParent( obj->GetVPanel() ); + return; + } + + AssertMsg( 0, "invalid parent" ); + } + + void GetChildren( HSCRIPT arr ) + { + CUtlVector< VPANEL > &children = ipanel()->GetChildren( this->GetVPanel() ); + FOR_EACH_VEC( children, i ) + { + VPANEL child = children[i]; + IScriptVGUIObject* obj = FindInScriptPanels( child ); + if ( obj ) + { + g_pScriptVM->ArrayAppend( arr, obj->GetScriptInstance() ); + } + // UNDONE: Register C++ created children of script created panels. + // It is safe to do so because their lifetime depends on their script parents. + } + } +#if 0 + void GetPos( HSCRIPT out ) + { + int x, y; + ipanel()->GetPos( this->GetVPanel(), x, y ); + g_pScriptVM->SetValue( out, (ScriptVariant_t)0, x ); + g_pScriptVM->SetValue( out, 1, y ); + } +#endif + int GetXPos() + { + int x, y; + ipanel()->GetPos( this->GetVPanel(), x, y ); + return x; + } + + int GetYPos() + { + int x, y; + ipanel()->GetPos( this->GetVPanel(), x, y ); + return y; + } + + void SetPos( int x, int y ) + { + ipanel()->SetPos( this->GetVPanel(), x, y ); + } + + void SetZPos( int i ) + { + ipanel()->SetZPos( this->GetVPanel(), i ); + } + + int GetZPos() + { + return ipanel()->GetZPos( this->GetVPanel() ); + } + + void SetSize( int w, int t ) + { + ipanel()->SetSize( this->GetVPanel(), w, t ); + } + + void SetWide( int w ) + { + ipanel()->SetSize( this->GetVPanel(), w, GetTall() ); + } + + int GetWide() + { + int w, t; + ipanel()->GetSize( this->GetVPanel(), w, t ); + return w; + } + + void SetTall( int t ) + { + ipanel()->SetSize( this->GetVPanel(), GetWide(), t ); + } + + int GetTall() + { + int w, t; + ipanel()->GetSize( this->GetVPanel(), w, t ); + return t; + } + + int GetAlpha() + { + return Base()->GetAlpha(); + } + + void SetAlpha( int i ) + { + Base()->SetAlpha( i ); + } + + void SetVisible( bool i ) + { + ipanel()->SetVisible( this->GetVPanel(), i ); + } + + bool IsVisible() + { + return ipanel()->IsVisible( this->GetVPanel() ); + } +#if BUILD_GROUPS_ENABLED + void SetProportional( bool i ) + { + Base()->SetProportional(i); + } +#endif + void LocalToScreen( HSCRIPT out ) + { + int px, py; + ipanel()->GetAbsPos( this->GetVPanel(), px, py ); + + ScriptVariant_t x, y; + g_pScriptVM->GetValue( out, (ScriptVariant_t)0, &x ); + g_pScriptVM->GetValue( out, 1, &y ); + + g_pScriptVM->SetValue( out, (ScriptVariant_t)0, x.m_int + px ); + g_pScriptVM->SetValue( out, 1, y.m_int + py ); + } + + void ScreenToLocal( HSCRIPT out ) + { + int px, py; + ipanel()->GetAbsPos( this->GetVPanel(), px, py ); + + ScriptVariant_t x, y; + g_pScriptVM->GetValue( out, (ScriptVariant_t)0, &x ); + g_pScriptVM->GetValue( out, 1, &y ); + + g_pScriptVM->SetValue( out, (ScriptVariant_t)0, x.m_int - px ); + g_pScriptVM->SetValue( out, 1, y.m_int - py ); + } + + bool IsWithin( int x, int y ) + { + return Base()->IsWithin( x, y ); + } + + void SetEnabled( bool i ) + { + Base()->SetEnabled(i); + } + + bool IsEnabled() + { + return Base()->IsEnabled(); + } + + void SetPaintEnabled( bool i ) + { + Base()->SetPaintEnabled(i); + } + + void SetPaintBackgroundEnabled( bool i ) + { + Base()->SetPaintBackgroundEnabled(i); + } + + void SetPaintBorderEnabled( bool i ) + { + Base()->SetPaintBorderEnabled(i); + } + + void SetPostChildPaintEnabled( bool i ) + { + Base()->SetPostChildPaintEnabled(i); + } + + // 0 for normal(opaque), 1 for single texture from Texture1, and 2 for rounded box w/ four corner textures + void SetPaintBackgroundType( int i ) + { + Base()->SetPaintBackgroundType(i); + } + + void SetFgColor( int r, int g, int b, int a ) + { + Base()->SetFgColor( Color( r, g, b, a ) ); + } + + void SetBgColor( int r, int g, int b, int a ) + { + Base()->SetBgColor( Color( r, g, b, a ) ); + } +#if 0 + void SetScheme( const char *tag ) + { + return Base()->SetScheme( tag ); + } +#endif + void SetCursor( int cursor ) + { + AssertMsg( cursor >= 0 && cursor < dc_last, "invalid cursor" ); + + if ( cursor < 0 ) + cursor = 0; + + else if ( cursor >= dc_last ) + cursor = 0; + + return Base()->SetCursor( (HCursor)cursor ); + } + + bool IsCursorOver() + { + return Base()->IsCursorOver(); + } + + bool HasFocus() + { + return Base()->HasFocus(); + } + + void RequestFocus() + { + Base()->RequestFocus(); + } + + void MakePopup() + { + Base()->MakePopup(); + } + + void MoveToFront() + { + Base()->MoveToFront(); + } + + void SetMouseInputEnabled( bool i ) + { + Base()->SetMouseInputEnabled(i); + } + + void SetKeyBoardInputEnabled( bool i ) + { + Base()->SetKeyBoardInputEnabled(i); + } + + // ----------------------- + // Drawing utility + // ----------------------- + //void SetRoundedCorners( int cornerFlags ) + //{ + // Base()->SetRoundedCorners( cornerFlags & 0xff ); + //} + + void DrawBox( int x, int y, int wide, int tall, int r, int g, int b, int a, bool hollow ) + { + Base()->DrawBox( x, y, wide, tall, Color(r, g, b, a), 1.0f, hollow ); + } + + void DrawBoxFade( int x, int y, int wide, int tall, int r, int g, int b, int a, int alpha0, int alpha1, bool bHorizontal, bool hollow ) + { + Base()->DrawBoxFade( x, y, wide, tall, Color(r, g, b, a), 1.0f, alpha0, alpha1, bHorizontal, hollow ); + } +#if 0 + // ----------------------- + // drag drop + // ----------------------- + void SetDragEnabled( bool i ) + { + Base()->SetDragEnabled(i); + } + + bool IsDragEnabled() + { + return Base()->IsDragEnabled(); + } + + void SetDropEnabled( bool i ) + { + Base()->SetDropEnabled( i, 0.0f ); + } + + bool IsDropEnabled() + { + return Base()->IsDropEnabled(); + } + + void SetShowDragHelper( int i ) + { + Base()->SetShowDragHelper(i); + } + + int GetDragStartTolerance() + { + return Base()->GetDragStartTolerance(); + } + + void SetDragStartTolerance( int i ) + { + Base()->SetDragSTartTolerance(i); + } +#endif +}; + +#define DEFINE_VGUI_SCRIPTFUNC_Panel()\ + DEFINE_SCRIPTFUNC( Destroy, "" )\ + DEFINE_SCRIPTFUNC( MakeReadyForUse, "" )\ + DEFINE_SCRIPTFUNC( GetName, "" )\ + DEFINE_SCRIPTFUNC( AddTickSignal, "" )\ +\ + DEFINE_SCRIPTFUNC( GetParent, "" )\ + DEFINE_SCRIPTFUNC( SetParent, "" )\ + DEFINE_SCRIPTFUNC( GetChildren, "" )\ +\ + DEFINE_SCRIPTFUNC( GetXPos, "" )\ + DEFINE_SCRIPTFUNC( GetYPos, "" )\ + DEFINE_SCRIPTFUNC( SetPos, "" )\ +\ + DEFINE_SCRIPTFUNC( GetZPos, "" )\ + DEFINE_SCRIPTFUNC( SetZPos, "" )\ +\ + DEFINE_SCRIPTFUNC( SetSize, "" )\ + DEFINE_SCRIPTFUNC( GetWide, "" )\ + DEFINE_SCRIPTFUNC( SetWide, "" )\ +\ + DEFINE_SCRIPTFUNC( GetTall, "" )\ + DEFINE_SCRIPTFUNC( SetTall, "" )\ +\ + DEFINE_SCRIPTFUNC( GetAlpha, "" )\ + DEFINE_SCRIPTFUNC( SetAlpha, "" )\ +\ + DEFINE_SCRIPTFUNC( SetVisible, "" )\ + DEFINE_SCRIPTFUNC( IsVisible, "" )\ +\ + DEFINE_SCRIPTFUNC( LocalToScreen, "" )\ + DEFINE_SCRIPTFUNC( ScreenToLocal, "" )\ + DEFINE_SCRIPTFUNC( IsWithin, "" )\ +\ + DEFINE_SCRIPTFUNC( SetEnabled, "" )\ + DEFINE_SCRIPTFUNC( IsEnabled, "" )\ +\ + DEFINE_SCRIPTFUNC( SetPaintEnabled, "" )\ + DEFINE_SCRIPTFUNC( SetPaintBackgroundEnabled, "" )\ + DEFINE_SCRIPTFUNC( SetPaintBorderEnabled, "" )\ + DEFINE_SCRIPTFUNC( SetPostChildPaintEnabled, "" )\ + DEFINE_SCRIPTFUNC( SetPaintBackgroundType, "" )\ +\ + DEFINE_SCRIPTFUNC( SetFgColor, "" )\ + DEFINE_SCRIPTFUNC( SetBgColor, "" )\ +\ + DEFINE_SCRIPTFUNC( SetCursor, "" )\ + DEFINE_SCRIPTFUNC( IsCursorOver, "" )\ + DEFINE_SCRIPTFUNC( HasFocus, "" )\ + DEFINE_SCRIPTFUNC( RequestFocus, "" )\ + DEFINE_SCRIPTFUNC( MakePopup, "" )\ + DEFINE_SCRIPTFUNC( MoveToFront, "" )\ + DEFINE_SCRIPTFUNC( SetMouseInputEnabled, "" )\ + DEFINE_SCRIPTFUNC( SetKeyBoardInputEnabled, "" )\ +\ + DEFINE_SCRIPTFUNC( DrawBox, "" )\ + DEFINE_SCRIPTFUNC( DrawBoxFade, "" )\ + +//-------------------------------------------------------------- +//-------------------------------------------------------------- +// These need more testing. +// TODO: IScript_Panel::FindChildByName() +// TODO: DECLARE_BUILD_FACTORY_SCRIPT() to create overridable script panels from controls file +// TODO: CScript_EditablePanel::ApplySchemeSettings() callback +// (IScheme parameter can be passed as null until schemes are also tested) +#if BUILD_GROUPS_ENABLED +CLASS_HELPER_INTERFACE( EditablePanel, Panel ) +{ +public: + // Call on creation or on ApplySchemeSettings() + void LoadControlSettings( const char *resName ) + { + Base()->LoadControlSettings( resName ); + } +}; + +#define DEFINE_VGUI_SCRIPTFUNC_EditablePanel()\ + DEFINE_VGUI_SCRIPTFUNC_Panel()\ + DEFINE_SCRIPTFUNC( LoadControlSettings, "" ) +#endif +//-------------------------------------------------------------- +//-------------------------------------------------------------- + +CLASS_HELPER_INTERFACE( Label, Panel ) +{ +public: + void SetText( const char *text ) + { + wchar_t wcs[512]; + g_pVGuiLocalize->ConvertANSIToUnicode( text, wcs, sizeof(wcs) ); + Base()->SetText( wcs ); + } + + void SetFont( int i ) + { + Base()->SetFont( IntToFontHandle(i) ); + } + + void SetAllCaps( bool i ) + { + Base()->SetAllCaps(i); + } + + void SetWrap( bool i ) + { + Base()->SetWrap(i); + } + + void SetCenterWrap( bool i ) + { + Base()->SetCenterWrap(i); + } + + void SetContentAlignment( int i ) + { + Base()->SetContentAlignment( (Label::Alignment)i ); + } + + void SetTextInset( int x, int y ) + { + Base()->SetTextInset( x, y ); + } + + void SizeToContents() + { + Base()->SizeToContents(); + } + + void SetAssociatedControl( HSCRIPT control ) + { + IScriptVGUIObject *obj = ToScriptVGUIObj( control ); + if ( obj ) + { + Base()->SetAssociatedControl( ipanel()->GetPanel( obj->GetVPanel(), GetControlsModuleName() ) ); + } + } + + void AddColorChange( int r, int g, int b, int a, int iTextStreamIndex ) + { + Base()->GetTextImage()->AddColorChange( Color( r, g, b, a ), iTextStreamIndex ); + } + + void ClearColorChangeStream() + { + Base()->GetTextImage()->ClearColorChangeStream(); + } +#if 0 + void SetTextImageIndex( int index ) + { + Base()->SetTextImageIndex( index ); + } + + void SetImageAtIndex( int index, const char *imageName, bool hardwareFilter, int offset ) + { + // Escape 'vgui/' prepended to the file name in CSchemeManager::GetImage(). + char fileName[MAX_PATH]; + V_snprintf( fileName, sizeof(fileName), "../%s", imageName ); + + return Base()->SetImageAtIndex( index, scheme()->GetImage( fileName, hardwareFilter ), offset); + } + + int AddImage( const char *imageName, bool hardwareFilter, int offset ) + { + // Escape 'vgui/' prepended to the file name in CSchemeManager::GetImage(). + char fileName[MAX_PATH]; + V_snprintf( fileName, sizeof(fileName), "../%s", imageName ); + + return Base()->AddImage( scheme()->GetImage( fileName, hardwareFilter ), offset ); + } +#endif +}; + +#define DEFINE_VGUI_SCRIPTFUNC_Label()\ + DEFINE_VGUI_SCRIPTFUNC_Panel()\ + DEFINE_SCRIPTFUNC( SetText, "" )\ + DEFINE_SCRIPTFUNC( SetFont, "" )\ + DEFINE_SCRIPTFUNC( SetAllCaps, "" )\ + DEFINE_SCRIPTFUNC( SetWrap, "" )\ + DEFINE_SCRIPTFUNC( SetCenterWrap, "" )\ + DEFINE_SCRIPTFUNC( SetContentAlignment, "" )\ + DEFINE_SCRIPTFUNC( SetTextInset, "" )\ + DEFINE_SCRIPTFUNC( SizeToContents, "" )\ + DEFINE_SCRIPTFUNC( SetAssociatedControl, "" )\ + DEFINE_SCRIPTFUNC( AddColorChange, "" )\ + DEFINE_SCRIPTFUNC( ClearColorChangeStream, "" )\ + +//-------------------------------------------------------------- +//-------------------------------------------------------------- + +CLASS_HELPER_INTERFACE( Button, Label ) +{ +public: + // NOTE: This is used if DoClick() callback is not implemented in CScript_Button. + // This changes where and how button command is processed - + // whether in the button [ DoClick() ] or in an external panel [ OnCommand(cmd) ]. + // It is fine to always use DoClick() instead of vgui messages + // because of the dynamic nature of script closures. +#if VGUI_SIGNAL_INTERFACE + void SetCommand( const char *command ) + { + if ( !V_strncmp( command, "url ", 4 ) ) + { + Base()->SetCommand( (KeyValues*)NULL ); + + g_pScriptVM->RaiseException("invalid button command"); + return; + } + + Base()->SetCommand( command ); + } +#endif + void SetButtonActivationType( int activationType ) + { + Base()->SetButtonActivationType( (Button::ActivationType_t)activationType ); + } + + bool IsArmed() + { + return Base()->IsArmed(); + } + + void SetArmed( bool state ) + { + Base()->SetArmed(state); + } + + bool IsSelected() + { + return Base()->IsSelected(); + } + + void SetSelected( bool state ) + { + Base()->SetSelected(state); + } + + bool IsDepressed() + { + return Base()->IsDepressed(); + } + + void ForceDepressed( bool state ) + { + Base()->ForceDepressed(state); + } + + bool IsBlinking() + { + return Base()->IsBlinking(); + } + + void SetBlink( bool state ) + { + Base()->SetBlink(state); + } + + void SetMouseClickEnabled( int code, bool state ) + { + Base()->SetMouseClickEnabled( (MouseCode)code, state ); + } + + bool IsMouseClickEnabled( int code ) + { + return Base()->IsMouseClickEnabled( (MouseCode)code ); + } + + void SetButtonBorderEnabled( bool state ) + { + Base()->SetButtonBorderEnabled( state ); + } + + void SetDefaultColor( int fr, int fg, int fb, int fa, int br, int bg, int bb, int ba ) + { + Base()->SetDefaultColor( Color(fr, fg, fb, fa), Color(br, bg, bb, ba) ); + } + + void SetArmedColor( int fr, int fg, int fb, int fa, int br, int bg, int bb, int ba ) + { + Base()->SetArmedColor( Color(fr, fg, fb, fa), Color(br, bg, bb, ba) ); + } + + void SetSelectedColor( int fr, int fg, int fb, int fa, int br, int bg, int bb, int ba ) + { + Base()->SetSelectedColor( Color(fr, fg, fb, fa), Color(br, bg, bb, ba) ); + } + + void SetDepressedColor( int fr, int fg, int fb, int fa, int br, int bg, int bb, int ba ) + { + Base()->SetDepressedColor( Color(fr, fg, fb, fa), Color(br, bg, bb, ba) ); + } + + void SetBlinkColor( int r, int g, int b, int a ) + { + Base()->SetBlinkColor( Color(r, g, b, a) ); + } + + void SetArmedSound( const char *sound ) + { + Base()->SetArmedSound( sound ); + } + + void SetDepressedSound( const char *sound ) + { + Base()->SetDepressedSound( sound ); + } + + void SetReleasedSound( const char *sound ) + { + Base()->SetReleasedSound( sound ); + } +}; + +#define DEFINE_VGUI_SCRIPTFUNC_Button()\ + DEFINE_VGUI_SCRIPTFUNC_Label()\ + DEFINE_SCRIPTFUNC( SetButtonActivationType, "" )\ + DEFINE_SCRIPTFUNC( IsArmed, "" )\ + DEFINE_SCRIPTFUNC( SetArmed, "" )\ + DEFINE_SCRIPTFUNC( IsSelected, "" )\ + DEFINE_SCRIPTFUNC( SetSelected, "" )\ + DEFINE_SCRIPTFUNC( IsDepressed, "" )\ + DEFINE_SCRIPTFUNC( ForceDepressed, "" )\ + DEFINE_SCRIPTFUNC( IsBlinking, "" )\ + DEFINE_SCRIPTFUNC( SetBlink, "" )\ + DEFINE_SCRIPTFUNC( SetMouseClickEnabled, "" )\ + DEFINE_SCRIPTFUNC( IsMouseClickEnabled, "" )\ + DEFINE_SCRIPTFUNC( SetButtonBorderEnabled, "" )\ + DEFINE_SCRIPTFUNC( SetDefaultColor, "" )\ + DEFINE_SCRIPTFUNC( SetArmedColor, "" )\ + DEFINE_SCRIPTFUNC( SetSelectedColor, "" )\ + DEFINE_SCRIPTFUNC( SetDepressedColor, "" )\ + DEFINE_SCRIPTFUNC( SetBlinkColor, "" )\ + DEFINE_SCRIPTFUNC( SetArmedSound, "" )\ + DEFINE_SCRIPTFUNC( SetDepressedSound, "" )\ + DEFINE_SCRIPTFUNC( SetReleasedSound, "" )\ + +//-------------------------------------------------------------- +//-------------------------------------------------------------- + +CLASS_HELPER_INTERFACE( ImagePanel, Panel ) +{ +public: + void SetImage( const char *imageName, bool hardwareFilter ) + { + // Escape 'vgui/' prepended to the file name in CSchemeManager::GetImage(). + // This makes script interfaces for textures consistent, but diverges from the original C++ interface. + char fileName[MAX_PATH]; + V_snprintf( fileName, sizeof(fileName), "../%s", imageName ); + + Base()->EvictImage(); + Base()->SetImage( scheme()->GetImage( fileName, hardwareFilter ) ); + } + + void SetDrawColor( int r, int g, int b, int a ) + { + Base()->SetDrawColor( Color( r, g, b, a ) ); + } + + void SetTileImage( bool bTile ) + { + Base()->SetTileImage( bTile ); + } + + void SetShouldScaleImage( bool state ) + { + Base()->SetShouldScaleImage( state ); + } + + void SetFrame( int nFrame ) + { + Base()->SetFrame( nFrame ); + } +}; + +#define DEFINE_VGUI_SCRIPTFUNC_ImagePanel()\ + DEFINE_VGUI_SCRIPTFUNC_Panel()\ + DEFINE_SCRIPTFUNC( SetImage, "" )\ + DEFINE_SCRIPTFUNC( SetDrawColor, "" )\ + DEFINE_SCRIPTFUNC( SetTileImage, "" )\ + DEFINE_SCRIPTFUNC( SetShouldScaleImage, "" )\ + DEFINE_SCRIPTFUNC( SetFrame, "" )\ + +//-------------------------------------------------------------- +//-------------------------------------------------------------- + +CLASS_HELPER_INTERFACE( Frame, Panel ) +{ +public: + void SetMinimumSize( int wide, int tall ) + { + Base()->SetMinimumSize( wide, tall ); + } + + void SetTitle( const char* titel ) + { + Base()->SetTitle( titel, false ); + } + + void Close() + { + Base()->Close(); + } + + void SetDeleteSelfOnClose( bool state ) + { + Base()->SetDeleteSelfOnClose( state ); + } + + void SetMoveable( bool state ) + { + Base()->SetMoveable( state ); + } + + void SetSizeable( bool state ) + { + Base()->SetSizeable( state ); + } + + void SetCloseButtonVisible( bool state ) + { + Base()->SetCloseButtonVisible( state ); + } + + void SetTitleBarVisible( bool state ) + { + Base()->SetTitleBarVisible( state ); + } + + void SetFadeEffectDisabled( bool disabled ) + { + Base()->SetFadeEffectDisableOverride( disabled ); + } + + void SetChainKeysToParent( bool state ) + { + Base()->SetChainKeysToParent( state ); + } +}; + +#define DEFINE_VGUI_SCRIPTFUNC_Frame()\ + DEFINE_VGUI_SCRIPTFUNC_Panel()\ + DEFINE_SCRIPTFUNC( SetMinimumSize, "" )\ + DEFINE_SCRIPTFUNC( SetTitle, "" )\ + DEFINE_SCRIPTFUNC( Close, "" )\ + DEFINE_SCRIPTFUNC( SetDeleteSelfOnClose, "" )\ + DEFINE_SCRIPTFUNC( SetMoveable, "" )\ + DEFINE_SCRIPTFUNC( SetSizeable, "" )\ + DEFINE_SCRIPTFUNC( SetCloseButtonVisible, "" )\ + DEFINE_SCRIPTFUNC( SetTitleBarVisible, "" )\ + DEFINE_SCRIPTFUNC( SetFadeEffectDisabled, "" )\ + DEFINE_SCRIPTFUNC( SetChainKeysToParent, "" )\ + +//-------------------------------------------------------------- +//-------------------------------------------------------------- + +CLASS_HELPER_INTERFACE( RichText, Panel ) +{ +public: + void SetText( const char* text ) + { + Base()->SetText( text ); + } + + void SetFont( int font ) + { + Base()->SetFont( IntToFontHandle(font) ); + } + + void InsertString( const char* text ) + { + Base()->InsertString( text ); + } + + void SetPanelInteractive( bool bInteractive ) + { + Base()->SetPanelInteractive( bInteractive ); + } + + void SetUnusedScrollbarInvisible( bool bInvis ) + { + Base()->SetUnusedScrollbarInvisible( bInvis ); + } + + void GotoTextStart() + { + Base()->GotoTextStart(); + } + + void GotoTextEnd() + { + Base()->GotoTextEnd(); + } + + void SetMaximumCharCount( int maxChars ) + { + Base()->SetMaximumCharCount( maxChars ); + } + + void InsertColorChange( int r, int g, int b, int a ) + { + Base()->InsertColorChange( Color( r, g, b, a ) ); + } + + int GetNumLines() + { + return Base()->GetNumLines(); + } + + void SetDrawTextOnly() + { + Base()->SetDrawTextOnly(); + } +}; + +#define DEFINE_VGUI_SCRIPTFUNC_RichText()\ + DEFINE_VGUI_SCRIPTFUNC_Panel()\ + DEFINE_SCRIPTFUNC( SetText, "" )\ + DEFINE_SCRIPTFUNC( SetFont, "" )\ + DEFINE_SCRIPTFUNC( InsertString, "" )\ + DEFINE_SCRIPTFUNC( SetPanelInteractive, "" )\ + DEFINE_SCRIPTFUNC( SetUnusedScrollbarInvisible, "" )\ + DEFINE_SCRIPTFUNC( GotoTextStart, "" )\ + DEFINE_SCRIPTFUNC( GotoTextEnd, "" )\ + DEFINE_SCRIPTFUNC( SetMaximumCharCount, "" )\ + DEFINE_SCRIPTFUNC( InsertColorChange, "" )\ + DEFINE_SCRIPTFUNC( GetNumLines, "" )\ + DEFINE_SCRIPTFUNC( SetDrawTextOnly, "" )\ + +//-------------------------------------------------------------- +//-------------------------------------------------------------- + +CLASS_HELPER_INTERFACE( TextEntry, Panel ) +{ +public: + void SetText( const char* text ) + { + wchar_t wcs[512]; + g_pVGuiLocalize->ConvertANSIToUnicode( text, wcs, sizeof(wcs) ); + Base()->SetText( wcs ); + } + + const char *GetText() + { + static char sz[512]; + Base()->GetText( sz, sizeof(sz) ); + return sz; + } + + void SetFont( int font ) + { + Base()->SetFont( IntToFontHandle(font) ); + } + + void SetEditable( bool state ) + { + Base()->SetEditable( state ); + } + + void GotoTextStart() + { + Base()->GotoTextStart(); + } + + void GotoTextEnd() + { + Base()->GotoTextEnd(); + } + + void InsertString( const char* text ) + { + Base()->InsertString( text ); + } + + void SelectNone() + { + Base()->SelectNone(); + } + + void SetMultiline( bool state ) + { + Base()->SetMultiline( state ); + } + + void SetVerticalScrollbar( bool state ) + { + Base()->SetVerticalScrollbar( state ); + } +#if 0 + void SetHorizontalScrolling( bool status ) + { + Base()->SetHorizontalScrolling( status ); + } +#endif + void SetCatchEnterKey( bool state ) + { + Base()->SetCatchEnterKey( state ); + } + + void SetMaximumCharCount( int maxChars ) + { + Base()->SetMaximumCharCount( maxChars ); + } + + void SetWrap( bool wrap ) + { + Base()->SetWrap( wrap ); + } + + void SetAllowNumericInputOnly( bool state ) + { + Base()->SetAllowNumericInputOnly( state ); + } +#if 0 + void SetDisabledBgColor( int r, int g, int b, int a ) + { + Base()->SetDisabledBgColor( Color( r, g, b, a ) ); + } + + void SetSelectionTextColor( int r, int g, int b, int a ) + { + Base()->SetSelectionTextColor( Color( r, g, b, a ) ); + } + + void SetSelectionBgColor( int r, int g, int b, int a ) + { + Base()->SetSelectionBgColor( Color( r, g, b, a ) ); + } + + void SetSelectionUnfocusedBgColor( int r, int g, int b, int a ) + { + Base()->SetSelectionUnfocusedBgColor( Color( r, g, b, a ) ); + } +#endif +}; + +#define DEFINE_VGUI_SCRIPTFUNC_TextEntry()\ + DEFINE_VGUI_SCRIPTFUNC_Panel()\ + DEFINE_SCRIPTFUNC( SetText, "" )\ + DEFINE_SCRIPTFUNC( GetText, "" )\ + DEFINE_SCRIPTFUNC( SetFont, "" )\ + DEFINE_SCRIPTFUNC( SetEditable, "" )\ + DEFINE_SCRIPTFUNC( GotoTextStart, "" )\ + DEFINE_SCRIPTFUNC( GotoTextEnd, "" )\ + DEFINE_SCRIPTFUNC( InsertString, "" )\ + DEFINE_SCRIPTFUNC( SelectNone, "" )\ + DEFINE_SCRIPTFUNC( SetMultiline, "" )\ + DEFINE_SCRIPTFUNC( SetVerticalScrollbar, "" )\ + DEFINE_SCRIPTFUNC( SetCatchEnterKey, "" )\ + DEFINE_SCRIPTFUNC( SetMaximumCharCount, "" )\ + DEFINE_SCRIPTFUNC( SetWrap, "" )\ + DEFINE_SCRIPTFUNC( SetAllowNumericInputOnly, "" )\ + +//-------------------------------------------------------------- +//-------------------------------------------------------------- + +//-------------------------------------------------------------- +//-------------------------------------------------------------- + + +//============================================================== +//============================================================== + + +#define SetHScript( var, val ) \ + if ( var && g_pScriptVM ) \ + g_pScriptVM->ReleaseScript( var ); \ + var = val; + +#define CheckCallback(s)\ + if ( FStrEq( cb, #s ) )\ + {\ + SetHScript( m_hfn##s, fn );\ + return;\ + } + +//-------------------------------------------------------- +// C++ objects for vgui overrides and messages. +//-------------------------------------------------------- + + +class CScript_Panel : public Panel +{ + DECLARE_SCRIPTVGUI_CLASS( Panel ); + +private: + HSCRIPT m_hfnPaint; + HSCRIPT m_hfnPaintBackground; + HSCRIPT m_hfnPostChildPaint; + + HSCRIPT m_hfnPerformLayout; + HSCRIPT m_hfnOnTick; + HSCRIPT m_hfnOnScreenSizeChanged; + + HSCRIPT m_hfnOnCursorEntered; + HSCRIPT m_hfnOnCursorExited; + + HSCRIPT m_hfnOnMousePressed; + HSCRIPT m_hfnOnMouseDoublePressed; + HSCRIPT m_hfnOnMouseReleased; + HSCRIPT m_hfnOnMouseWheeled; + + HSCRIPT m_hfnOnKeyCodeTyped; + +public: + CScript_Panel( Panel *parent, const char *name ) : + BaseClass( parent, name ), + + m_hfnPaint(NULL), + m_hfnPaintBackground(NULL), + m_hfnPostChildPaint(NULL), + + m_hfnPerformLayout(NULL), + m_hfnOnTick(NULL), + m_hfnOnScreenSizeChanged(NULL), + + m_hfnOnCursorEntered(NULL), + m_hfnOnCursorExited(NULL), + + m_hfnOnMousePressed(NULL), + m_hfnOnMouseDoublePressed(NULL), + m_hfnOnMouseReleased(NULL), + m_hfnOnMouseWheeled(NULL), + + m_hfnOnKeyCodeTyped(NULL) + {} + + void Shutdown() + { + ivgui()->RemoveTickSignal( GetVPanel() ); + + SetHScript( m_hfnPaint, NULL ); + SetHScript( m_hfnPaintBackground, NULL ); + SetHScript( m_hfnPostChildPaint, NULL ); + + SetHScript( m_hfnPerformLayout, NULL ); + SetHScript( m_hfnOnTick, NULL ); + SetHScript( m_hfnOnScreenSizeChanged, NULL ); + + SetHScript( m_hfnOnCursorEntered, NULL ); + SetHScript( m_hfnOnCursorExited, NULL ); + + SetHScript( m_hfnOnMousePressed, NULL ); + SetHScript( m_hfnOnMouseDoublePressed, NULL ); + SetHScript( m_hfnOnMouseReleased, NULL ); + SetHScript( m_hfnOnMouseWheeled, NULL ); + + SetHScript( m_hfnOnKeyCodeTyped, NULL ); + } + +public: + void Paint() + { + g_pScriptVM->ExecuteFunction( m_hfnPaint, NULL, 0, NULL, NULL, true ); + } + + void PaintBackground() + { + if ( m_hfnPaintBackground ) + { + g_pScriptVM->ExecuteFunction( m_hfnPaintBackground, NULL, 0, NULL, NULL, true ); + } + else + { + BaseClass::PaintBackground(); + } + } + + void PostChildPaint() + { + g_pScriptVM->ExecuteFunction( m_hfnPostChildPaint, NULL, 0, NULL, NULL, true ); + } + + void PerformLayout() + { + BaseClass::PerformLayout(); + + if ( m_hfnPerformLayout ) + { + g_pScriptVM->ExecuteFunction( m_hfnPerformLayout, NULL, 0, NULL, NULL, true ); + } + } + + void OnTick() + { + g_pScriptVM->ExecuteFunction( m_hfnOnTick, NULL, 0, NULL, NULL, true ); + } + + void OnScreenSizeChanged( int oldwide, int oldtall ) + { + BaseClass::OnScreenSizeChanged( oldwide, oldtall ); + + if ( m_hfnOnScreenSizeChanged ) + { + ScriptVariant_t args[2] = { oldwide, oldtall }; + g_pScriptVM->ExecuteFunction( m_hfnOnScreenSizeChanged, args, 2, NULL, NULL, true ); + } + } +#if VGUI_SIGNAL_INTERFACE + void OnCommand( const char *command ) + { + if ( m_hfnOnCommand ) + { + ScriptVariant_t ret, arg = command; + g_pScriptVM->ExecuteFunction( m_hfnOnCommand, &arg, 1, &ret, NULL, true ); + + // Return true to swallow, otherwise fallback + if ( ret.m_type == FIELD_BOOLEAN && ret.m_bool ) + return; + } + + BaseClass::OnCommand( command ); + } +#endif + void OnCursorEntered() + { + if ( m_hfnOnCursorEntered ) + { + g_pScriptVM->ExecuteFunction( m_hfnOnCursorEntered, NULL, 0, NULL, NULL, true ); + } + } + + void OnCursorExited() + { + if ( m_hfnOnCursorExited ) + { + g_pScriptVM->ExecuteFunction( m_hfnOnCursorExited, NULL, 0, NULL, NULL, true ); + } + } + + void OnMousePressed( MouseCode code ) + { + if ( m_hfnOnMousePressed ) + { + ScriptVariant_t arg = (int)code; + g_pScriptVM->ExecuteFunction( m_hfnOnMousePressed, &arg, 1, NULL, NULL, true ); + } + } + + void OnMouseDoublePressed( MouseCode code ) + { + if ( m_hfnOnMouseDoublePressed ) + { + ScriptVariant_t arg = (int)code; + g_pScriptVM->ExecuteFunction( m_hfnOnMouseDoublePressed, &arg, 1, NULL, NULL, true ); + } + } + + void OnMouseReleased( MouseCode code ) + { + if ( m_hfnOnMouseReleased ) + { + ScriptVariant_t arg = (int)code; + g_pScriptVM->ExecuteFunction( m_hfnOnMouseReleased, &arg, 1, NULL, NULL, true ); + } + } + + void OnMouseWheeled( int delta ) + { + if ( m_hfnOnMouseWheeled ) + { + ScriptVariant_t arg = (int)delta; + g_pScriptVM->ExecuteFunction( m_hfnOnMouseWheeled, &arg, 1, NULL, NULL, true ); + } + } + + void OnKeyCodeTyped( KeyCode code ) + { + BaseClass::OnKeyCodeTyped( code ); + + if ( m_hfnOnKeyCodeTyped ) + { + ScriptVariant_t arg = (int)code; + g_pScriptVM->ExecuteFunction( m_hfnOnKeyCodeTyped, &arg, 1, NULL, NULL, true ); + } + } +public: + void SetCallback( const char* cb, HSCRIPT fn ) + { + CheckCallback( Paint ); + CheckCallback( PaintBackground ); + CheckCallback( PostChildPaint ); + + CheckCallback( PerformLayout ); + CheckCallback( OnTick ); + CheckCallback( OnScreenSizeChanged ); + + CheckCallback( OnCursorEntered ); + CheckCallback( OnCursorExited ); + + CheckCallback( OnMousePressed ); + CheckCallback( OnMouseDoublePressed ); + CheckCallback( OnMouseReleased ); + CheckCallback( OnMouseWheeled ); + + CheckCallback( OnKeyCodeTyped ); + + g_pScriptVM->RaiseException("invalid callback"); + } +}; + +//-------------------------------------------------------------- +//-------------------------------------------------------------- + +class CScript_Frame : public Frame +{ + DECLARE_SCRIPTVGUI_CLASS( Frame ); + +private: + HSCRIPT m_hfnPaint; + HSCRIPT m_hfnPaintBackground; + + HSCRIPT m_hfnPerformLayout; + HSCRIPT m_hfnOnTick; + HSCRIPT m_hfnOnScreenSizeChanged; + + HSCRIPT m_hfnOnCursorEntered; + HSCRIPT m_hfnOnCursorExited; + + HSCRIPT m_hfnOnMousePressed; + HSCRIPT m_hfnOnMouseDoublePressed; + HSCRIPT m_hfnOnMouseReleased; + HSCRIPT m_hfnOnMouseWheeled; + + HSCRIPT m_hfnOnKeyCodeTyped; + +public: + CScript_Frame( Panel *parent, const char *name ) : + + // Start without popup + BaseClass( parent, name, false, false ), + + m_hfnPaint(NULL), + m_hfnPaintBackground(NULL), + + m_hfnPerformLayout(NULL), + m_hfnOnTick(NULL), + m_hfnOnScreenSizeChanged(NULL), + + m_hfnOnCursorEntered(NULL), + m_hfnOnCursorExited(NULL), + + m_hfnOnMousePressed(NULL), + m_hfnOnMouseDoublePressed(NULL), + m_hfnOnMouseReleased(NULL), + m_hfnOnMouseWheeled(NULL), + + m_hfnOnKeyCodeTyped(NULL) + {} + + void Shutdown() + { + ivgui()->RemoveTickSignal( GetVPanel() ); + + SetHScript( m_hfnPaint, NULL ); + SetHScript( m_hfnPaintBackground, NULL ); + + SetHScript( m_hfnPerformLayout, NULL ); + SetHScript( m_hfnOnTick, NULL ); + SetHScript( m_hfnOnScreenSizeChanged, NULL ); + + SetHScript( m_hfnOnMousePressed, NULL ); + SetHScript( m_hfnOnMouseDoublePressed, NULL ); + SetHScript( m_hfnOnMouseReleased, NULL ); + SetHScript( m_hfnOnMouseWheeled, NULL ); + SetHScript( m_hfnOnKeyCodeTyped, NULL ); + } + +public: + void Paint() + { + g_pScriptVM->ExecuteFunction( m_hfnPaint, NULL, 0, NULL, NULL, true ); + } + + void PaintBackground() + { + if ( m_hfnPaintBackground ) + { + g_pScriptVM->ExecuteFunction( m_hfnPaintBackground, NULL, 0, NULL, NULL, true ); + } + else + { + BaseClass::PaintBackground(); + } + } + + void PerformLayout() + { + BaseClass::PerformLayout(); + + if ( m_hfnPerformLayout ) + { + g_pScriptVM->ExecuteFunction( m_hfnPerformLayout, NULL, 0, NULL, NULL, true ); + } + } + + void OnTick() + { + g_pScriptVM->ExecuteFunction( m_hfnOnTick, NULL, 0, NULL, NULL, true ); + } + + void OnScreenSizeChanged( int oldwide, int oldtall ) + { + BaseClass::OnScreenSizeChanged( oldwide, oldtall ); + + if ( m_hfnOnScreenSizeChanged ) + { + ScriptVariant_t args[2] = { oldwide, oldtall }; + g_pScriptVM->ExecuteFunction( m_hfnOnScreenSizeChanged, args, 2, NULL, NULL, true ); + } + } + + void OnCursorEntered() + { + if ( m_hfnOnCursorEntered ) + { + g_pScriptVM->ExecuteFunction( m_hfnOnCursorEntered, NULL, 0, NULL, NULL, true ); + } + } + + void OnCursorExited() + { + if ( m_hfnOnCursorExited ) + { + g_pScriptVM->ExecuteFunction( m_hfnOnCursorExited, NULL, 0, NULL, NULL, true ); + } + } + + void OnMousePressed( MouseCode code ) + { + BaseClass::OnMousePressed( code ); + + if ( m_hfnOnMousePressed ) + { + ScriptVariant_t arg = (int)code; + g_pScriptVM->ExecuteFunction( m_hfnOnMousePressed, &arg, 1, NULL, NULL, true ); + } + } + + void OnMouseDoublePressed( MouseCode code ) + { + if ( m_hfnOnMouseDoublePressed ) + { + ScriptVariant_t arg = (int)code; + g_pScriptVM->ExecuteFunction( m_hfnOnMouseDoublePressed, &arg, 1, NULL, NULL, true ); + } + } + + void OnMouseReleased( MouseCode code ) + { + if ( m_hfnOnMouseReleased ) + { + ScriptVariant_t arg = (int)code; + g_pScriptVM->ExecuteFunction( m_hfnOnMouseReleased, &arg, 1, NULL, NULL, true ); + } + } + + void OnMouseWheeled( int delta ) + { + if ( m_hfnOnMouseWheeled ) + { + ScriptVariant_t arg = (int)delta; + g_pScriptVM->ExecuteFunction( m_hfnOnMouseWheeled, &arg, 1, NULL, NULL, true ); + } + } + + void OnKeyCodeTyped( KeyCode code ) + { + if ( m_hfnOnKeyCodeTyped ) + { + ScriptVariant_t arg = (int)code; + g_pScriptVM->ExecuteFunction( m_hfnOnKeyCodeTyped, &arg, 1, NULL, NULL, true ); + + if ( CanChainKeysToParent() ) + { + BaseClass::OnKeyCodeTyped( code ); + } + } + else + { + BaseClass::OnKeyCodeTyped( code ); + } + } +public: + void SetCallback( const char* cb, HSCRIPT fn ) + { + CheckCallback( Paint ); + CheckCallback( PaintBackground ); + + CheckCallback( PerformLayout ); + CheckCallback( OnTick ); + CheckCallback( OnScreenSizeChanged ); + + CheckCallback( OnCursorEntered ); + CheckCallback( OnCursorExited ); + + CheckCallback( OnMousePressed ); + CheckCallback( OnMouseDoublePressed ); + CheckCallback( OnMouseReleased ); + CheckCallback( OnMouseWheeled ); + + CheckCallback( OnKeyCodeTyped ); + + g_pScriptVM->RaiseException("invalid callback"); + } +}; + +//-------------------------------------------------------------- +//-------------------------------------------------------------- + +class CScript_Button : public Button +{ + DECLARE_SCRIPTVGUI_CLASS( Button ); + +private: + HSCRIPT m_hfnPaint; + HSCRIPT m_hfnPaintBackground; + HSCRIPT m_hfnDoClick; + +public: + CScript_Button( Panel *parent, const char *name, const char *text ) : + BaseClass( parent, name, text ), + + m_hfnPaint(NULL), + m_hfnPaintBackground(NULL), + + m_hfnDoClick(NULL) + {} + + void Shutdown() + { + SetHScript( m_hfnDoClick, NULL ); + } + +public: + void Paint() + { + if ( m_hfnPaint ) + { + g_pScriptVM->ExecuteFunction( m_hfnPaint, NULL, 0, NULL, NULL, true ); + } + else + { + BaseClass::Paint(); + } + } + + void PaintBackground() + { + if ( m_hfnPaintBackground ) + { + g_pScriptVM->ExecuteFunction( m_hfnPaintBackground, NULL, 0, NULL, NULL, true ); + } + else + { + BaseClass::PaintBackground(); + } + } + + void DoClick() + { + BaseClass::DoClick(); + + if ( m_hfnDoClick ) + { + g_pScriptVM->ExecuteFunction( m_hfnDoClick, NULL, 0, NULL, NULL, true ); + } + } + +public: + void SetCallback( const char* cb, HSCRIPT fn ) + { + CheckCallback( Paint ); + CheckCallback( PaintBackground ); + CheckCallback( DoClick ); + + g_pScriptVM->RaiseException("invalid callback"); + } +}; + +//-------------------------------------------------------------- +//-------------------------------------------------------------- + +class CScript_TextEntry : public TextEntry +{ + DECLARE_SCRIPTVGUI_CLASS( TextEntry ); + +private: + HSCRIPT m_hfnTextChanged; + +public: + CScript_TextEntry( Panel *parent, const char *name ) : + BaseClass( parent, name ), + + m_hfnTextChanged(NULL) + {} + + void Shutdown() + { + SetHScript( m_hfnTextChanged, NULL ); + } + +public: + //--------------------------------------------- + // On "TextMessage" message. + // Used for responding to user input as it is typed. + //--------------------------------------------- + void FireActionSignal() + { + BaseClass::FireActionSignal(); + + if ( m_hfnTextChanged ) + { + g_pScriptVM->ExecuteFunction( m_hfnTextChanged, NULL, 0, NULL, NULL, true ); + } + } + +public: + void SetCallback( const char* cb, HSCRIPT fn ) + { + CheckCallback( TextChanged ); + + g_pScriptVM->RaiseException("invalid callback"); + } +}; + +//-------------------------------------------------------------- +//-------------------------------------------------------------- + +//-------------------------------------------------------------- +//-------------------------------------------------------------- + + +//============================================================== +//============================================================== + +//-------------------------------------------------------- +// Script objects +//-------------------------------------------------------- + +DEFINE_VGUI_CLASS_EMPTY_DEFAULT_TEXT( Label ) +DEFINE_VGUI_CLASS_EMPTY( ImagePanel ) +DEFINE_VGUI_CLASS_EMPTY( RichText ) + +//-------------------------------------------------------------- +//-------------------------------------------------------------- + +BEGIN_VGUI_HELPER( Panel ) + DEFINE_REDIRECT_2( void, SetCallback, const char*, HSCRIPT ) +END_VGUI_HELPER() + +BEGIN_SCRIPTDESC_VGUI( Panel ) + DEFINE_SCRIPTFUNC( SetCallback, "" ) +END_SCRIPTDESC() + +//-------------------------------------------------------------- +//-------------------------------------------------------------- + +BEGIN_VGUI_HELPER( Frame ) + DEFINE_REDIRECT_2( void, SetCallback, const char*, HSCRIPT ) +END_VGUI_HELPER() + +BEGIN_SCRIPTDESC_VGUI( Frame ) + DEFINE_SCRIPTFUNC( SetCallback, "" ) +END_SCRIPTDESC() + +//-------------------------------------------------------------- +//-------------------------------------------------------------- + +BEGIN_VGUI_HELPER_DEFAULT_TEXT( Button ) + DEFINE_REDIRECT_2( void, SetCallback, const char*, HSCRIPT ) +END_VGUI_HELPER() + +BEGIN_SCRIPTDESC_VGUI( Button ) + DEFINE_SCRIPTFUNC( SetCallback, "" ) +END_SCRIPTDESC() + +//-------------------------------------------------------------- +//-------------------------------------------------------------- + +BEGIN_VGUI_HELPER( TextEntry ) + DEFINE_REDIRECT_2( void, SetCallback, const char*, HSCRIPT ) +END_VGUI_HELPER() + +BEGIN_SCRIPTDESC_VGUI( TextEntry ) + DEFINE_SCRIPTFUNC( SetCallback, "" ) +END_SCRIPTDESC() + +//-------------------------------------------------------------- +//-------------------------------------------------------------- + +//-------------------------------------------------------------- +//-------------------------------------------------------------- + + +//============================================================== +//============================================================== + + +class CScriptVGUI : public CAutoGameSystem +{ +public: + void LevelShutdownPostEntity(); + void Shutdown(); + +public: + HSCRIPT Create( const char* panelClass, HSCRIPT parent, const char* panelName, int root ); + //void LoadSchemeFromFile( const char *filename, const char *tag ); + +} script_vgui; + +BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptVGUI, "IVGui", SCRIPT_SINGLETON ) + DEFINE_SCRIPTFUNC( Create, SCRIPT_HIDE ) +END_SCRIPTDESC() + + +HSCRIPT CScriptVGUI::Create( const char* panelClass, HSCRIPT parent, const char* panelName, int root ) +{ +#define Check( _name )\ + if ( FStrEq( panelClass, #_name ) )\ + {\ + DebugDevMsg( "Create vgui %s '%s'\n", panelClass, panelName );\ + CScript_##_name##_Helper *helper = new CScript_##_name##_Helper;\ + helper->CreateFromScript< CScript_##_name##_Helper >( (HSCRIPT)parent, panelName, root );\ + Assert( !V_stricmp( g_ScriptPanels.Tail()->GetName(), panelName ) );\ + return helper->GetScriptInstance();\ + } + + Check( Panel ); + Check( Label ); + Check( Button ); + Check( ImagePanel ); + Check( Frame ); + Check( RichText ); + Check( TextEntry ); + + g_pScriptVM->RaiseException("invalid vgui class"); + return NULL; + +#undef Check +} + +void CScriptVGUI::LevelShutdownPostEntity() +{ + DebugMsg( "LevelShutdownPostEntity()\n" ); + + FOR_EACH_VEC( g_ScriptPanels, i ) + { + g_ScriptPanels[i]->Destroy(); + } + g_ScriptPanels.PurgeAndDeleteElements(); + + FOR_EACH_VEC( g_ScriptTextureIDs, i ) + { +#ifdef _DEBUG + char tex[MAX_PATH]; + surface()->DrawGetTextureFile( g_ScriptTextureIDs[i], tex, sizeof(tex)-1 ); + DebugMsg( "Destroy texture [%i]%s\n", g_ScriptTextureIDs[i], tex ); +#endif + surface()->DestroyTextureID( g_ScriptTextureIDs[i] ); + } + g_ScriptTextureIDs.Purge(); +} + +void CScriptVGUI::Shutdown() +{ + VGUI_DestroyScriptRootPanels(); + + FOR_EACH_DICT_FAST( g_ScriptFonts, i ) + { + fontalias_t &alias = g_ScriptFonts[i]; + for ( int j = 0; j < alias.Count(); ++j ) + { + char *pName = alias.Element(j).name; + if ( pName ) + { + free( pName ); + alias.Element(j).name = NULL; + } + } + + alias.Purge(); + } + + g_ScriptFonts.Purge(); +} + + +class CScriptIInput +{ +public: + void MakeWeaponSelection( HSCRIPT weapon ) + { + ::input->MakeWeaponSelection( HScriptToClass< C_BaseCombatWeapon >( weapon ) ); + } +#if 0 + int GetButtonBits() + { + return ::input->GetButtonBits(0); + } + + void ClearInputButton( int i ) + { + return ::input->ClearInputButton(i); + } +#endif + void GetCursorPos( HSCRIPT out ) + { + int x, y; + vgui::input()->GetCursorPos( x, y ); + g_pScriptVM->SetValue( out, (ScriptVariant_t)0, x ); + g_pScriptVM->SetValue( out, 1, y ); + } + + void SetCursorPos( int x, int y ) + { + vgui::input()->SetCursorPos( x, y ); + } + + int GetAnalogValue( int code ) + { + return inputsystem->GetAnalogValue( (AnalogCode_t)code ); + } + + int GetAnalogDelta( int code ) + { + return inputsystem->GetAnalogDelta( (AnalogCode_t)code ); + } + + bool IsButtonDown( int code ) + { + return inputsystem->IsButtonDown( (ButtonCode_t)code ); + } + + int GetButtonCodeForBind( const char *bind ) + { + return inputsystem->StringToButtonCode( bind ); + } + + const char *LookupBinding( const char *binding ) + { + return engine->Key_LookupBinding( binding ); + } + + const char *BindingForKey( int code ) + { + return engine->Key_BindingForKey( (ButtonCode_t)code ); + } +#if 0 + const char *GetIMELanguageShortCode() + { + static char ret[5]; + wchar_t get[5]; + get[0] = L'\0'; + vgui::input()->GetIMELanguageShortCode( get, wcslen(get) ); + g_pVGuiLocalize->ConvertUnicodeToANSI( get, ret, sizeof(ret) ); + return ret; + } +#endif +} script_input; + +BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptIInput, "IInput", SCRIPT_SINGLETON ) + DEFINE_SCRIPTFUNC( MakeWeaponSelection, "" ) + + DEFINE_SCRIPTFUNC( GetCursorPos, "" ) + DEFINE_SCRIPTFUNC( SetCursorPos, "" ) + + DEFINE_SCRIPTFUNC( GetAnalogValue, "" ) + DEFINE_SCRIPTFUNC( GetAnalogDelta, "" ) + DEFINE_SCRIPTFUNC( IsButtonDown, "" ) + + DEFINE_SCRIPTFUNC( GetButtonCodeForBind, "" ) + DEFINE_SCRIPTFUNC( LookupBinding, "" ) + DEFINE_SCRIPTFUNC( BindingForKey, "" ) +END_SCRIPTDESC() + + +void SetClipboardText( const char *text ) +{ + system()->SetClipboardText( text, V_strlen(text) ); +} + +//============================================================== +//============================================================== + + +//----------------------------------------------------------------------------- +// Get world position in screen space [0,1]. Return true if on screen. +//----------------------------------------------------------------------------- +inline bool WorldToScreen( const Vector &pos, int &ix, int &iy ) +{ + int scrw, scrh; + surface()->GetScreenSize( scrw, scrh ); + + const VMatrix &worldToScreen = engine->WorldToScreenMatrix(); + bool bOnScreen; + + // VMatrix * Vector (position projective) + vec_t w = worldToScreen[3][0] * pos[0] + worldToScreen[3][1] * pos[1] + worldToScreen[3][2] * pos[2] + worldToScreen[3][3]; + vec_t fx = worldToScreen[0][0] * pos[0] + worldToScreen[0][1] * pos[1] + worldToScreen[0][2] * pos[2] + worldToScreen[0][3]; + vec_t fy = worldToScreen[1][0] * pos[0] + worldToScreen[1][1] * pos[1] + worldToScreen[1][2] * pos[2] + worldToScreen[1][3]; + + if ( w < 0.001f ) + { + fx *= 1e5f; + fy *= 1e5f; + bOnScreen = false; + } + else + { + w = 1.0f / w; + fx *= w; + fy *= w; + bOnScreen = true; + } + + ix = (int)( scrw * 0.5f * ( 1.0f + fx ) + 0.5f ); + iy = (int)( scrh * 0.5f * ( 1.0f - fy ) + 0.5f ); + + return bOnScreen; +} + +//----------------------------------------------------------------------------- +// Get screen pixel position [0,1] in world space. +//----------------------------------------------------------------------------- +inline void ScreenToWorld( int x, int y, Vector &out ) +{ + int scrw, scrh; + surface()->GetScreenSize( scrw, scrh ); + float scrx = (float)x / (float)scrw; + float scry = (float)y / (float)scrh; + + vec_t tmp[2]; + tmp[0] = 2.0f * scrx - 1.0f; + tmp[1] = 1.0f - 2.0f * scry; + //tmp[2] = 1.0f; + //tmp[3] = 1.0f; + + VMatrix screenToWorld; + MatrixInverseGeneral( engine->WorldToScreenMatrix(), screenToWorld ); + + // VMatrix * Vector (position projective) + vec_t iw = 1.0f / ( screenToWorld[3][0] * tmp[0] + screenToWorld[3][1] * tmp[1] + screenToWorld[3][2] + screenToWorld[3][3] ); + out[0] = iw * ( screenToWorld[0][0] * tmp[0] + screenToWorld[0][1] * tmp[1] + screenToWorld[0][2] + screenToWorld[0][3] ); + out[1] = iw * ( screenToWorld[1][0] * tmp[0] + screenToWorld[1][1] * tmp[1] + screenToWorld[1][2] + screenToWorld[1][3] ); + out[2] = iw * ( screenToWorld[2][0] * tmp[0] + screenToWorld[2][1] * tmp[1] + screenToWorld[2][2] + screenToWorld[2][3] ); +} + + +static bool ScriptWorldToScreen( const Vector &pos, HSCRIPT out ) +{ + int ix, iy; + bool r = WorldToScreen( pos, ix, iy ); + + g_pScriptVM->SetValue( out, (ScriptVariant_t)0, ix ); + g_pScriptVM->SetValue( out, 1, iy ); + return r; +} + +static const Vector& ScriptScreenToWorld( int x, int y ) +{ + static Vector out; + ScreenToWorld( x, y, out ); + return out; +} + +static const Vector& ScreenToRay( int x, int y ) +{ + static Vector out; + ScreenToWorld( x, y, out ); + VectorSubtract( out, CurrentViewOrigin(), out ); + VectorNormalize( out ); + return out; +} + +//----------------------------------------------------------------------------- +// Get world position normalised in screen space. Return true if on screen. +//----------------------------------------------------------------------------- +int ScreenTransform( const Vector& point, Vector& screen ); +static bool ScriptScreenTransform( const Vector &pos, HSCRIPT out ) +{ + Vector v; + bool r = ScreenTransform( pos, v ); + float x = 0.5f * ( 1.0f + v[0] ); + float y = 0.5f * ( 1.0f - v[1] ); + + g_pScriptVM->SetValue( out, (ScriptVariant_t)0, x ); + g_pScriptVM->SetValue( out, 1, y ); + return !r; +} + +int ScriptScreenWidth() +{ + int w, h; + surface()->GetScreenSize( w, h ); + return w; +} + +int ScriptScreenHeight() +{ + int w, h; + surface()->GetScreenSize( w, h ); + return h; +} + +vgui::HFont GetScriptFont( const char *name, bool proportional ) +{ + return script_surface.GetFont( name, proportional, NULL ); +} + + +void RegisterScriptVGUI() +{ + ScriptRegisterFunction( g_pScriptVM, SetClipboardText, "" ); + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptWorldToScreen, "WorldToScreen", "Get world position in screen space [0,1]. Return true if on screen." ); + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptScreenToWorld, "ScreenToWorld", "Get screen pixel position [0,1] in world space." ); + ScriptRegisterFunction( g_pScriptVM, ScreenToRay, "Get a ray from screen pixel position to world space." ); + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptScreenTransform, "ScreenTransform", "Get world position normalised in screen space. Return true if on screen." ); + + g_pScriptVM->Run( g_Script_vgui_init ); + + g_pScriptVM->RegisterInstance( &script_surface, "surface" ); + g_pScriptVM->RegisterInstance( &script_input, "input" ); + g_pScriptVM->RegisterInstance( &script_vgui, "vgui" ); +} diff --git a/sp/src/game/client/mapbase/vscript_vgui.h b/sp/src/game/client/mapbase/vscript_vgui.h new file mode 100644 index 0000000000..d521407367 --- /dev/null +++ b/sp/src/game/client/mapbase/vscript_vgui.h @@ -0,0 +1,16 @@ +//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VSCRIPT_VGUI_H +#define VSCRIPT_VGUI_H +#ifdef _WIN32 +#pragma once +#endif + +void RegisterScriptVGUI(); + +#endif diff --git a/sp/src/game/client/mapbase/vscript_vgui.nut b/sp/src/game/client/mapbase/vscript_vgui.nut new file mode 100644 index 0000000000..3fcb7ad955 --- /dev/null +++ b/sp/src/game/client/mapbase/vscript_vgui.nut @@ -0,0 +1,216 @@ +static const char* g_Script_vgui_init = R"script( + +local _Schemes = {} +local _FontTall = {} +local DoCreateFont = ISurface.CreateFont; + +ISurface.CreateFont <- function( name, props ) +{ + if ( !("name" in props) || typeof props.name != "string" ) + throw "invalid parameter 'name'"; + + if ( !("tall" in props) || typeof props.tall != "integer" || !props.tall ) + throw "invalid parameter 'tall'"; + + if ( !("weight" in props) || typeof props.weight != "integer" ) + throw "invalid parameter 'weight'"; + + local yres_min = 0, yres_max = 0; + + if ( "yres" in props && typeof props.yres == "string" ) + { + local ss = ::split( props.yres, " " ); + try + { + yres_min = ss[0].tointeger(); + yres_max = ss[1].tointeger(); + } + catch(x) + { + throw "invalid parameter 'yres'"; + } + } + + if ( ( (!("proportional" in props) || typeof props.proportional != "bool") ) && !yres_min ) + { + throw "parameter 'proportional' or 'yres' not found"; + } + else if ( "proportional" in props && props.proportional && yres_min ) + { + throw "resolution definition on a proportional font" + } + + local blur = 0; + local scanlines = 0; + local proportional = false; + + if ( "blur" in props && typeof props.blur == "integer" ) + blur = props.blur; + + if ( "scanlines" in props && typeof props.scanlines == "integer" ) + scanlines = props.scanlines; + + if ( "proportional" in props && typeof props.proportional == "bool" ) + proportional = props.proportional; + + local flags = 0; + + if ( "italic" in props && props.italic == true ) + flags = flags | 0x001; + + if ( "underline" in props && props.underline == true ) + flags = flags | 0x002; + + if ( "strikeout" in props && props.strikeout == true ) + flags = flags | 0x004; + + if ( "symbol" in props && props.symbol == true ) + flags = flags | 0x008; + + if ( "antialias" in props && props.antialias == true ) + flags = flags | 0x010; + + if ( "gaussianblur" in props && props.gaussianblur == true ) + flags = flags | 0x020; + + if ( "rotary" in props && props.rotary == true ) + flags = flags | 0x040; + + if ( "dropshadow" in props && props.dropshadow == true ) + flags = flags | 0x080; + + if ( "additive" in props && props.additive == true ) + flags = flags | 0x100; + + if ( "outline" in props && props.outline == true ) + flags = flags | 0x200; + + if ( "custom" in props && props.custom == true ) + flags = flags | 0x400; + + if ( "bitmap" in props && props.bitmap == true ) + flags = flags | 0x800; + + return DoCreateFont( name, props.name, props.tall, props.weight, blur, scanlines, flags, yres_min, yres_max, proportional ); +} +__Documentation.RegisterHelp( "ISurface::CreateFont", "void ISurface::CreateFont(string, handle)", "" ); + + +local DoGetFont = ISurface.DoGetFont <- ISurface.GetFont; +local DoGetFontTall = ISurface.GetFontTall; + +ISurface.GetFont <- function( name, proportional = false, sch = "" ) +{ + if ( sch in _Schemes ) + { + local fonts = _Schemes[sch][proportional.tointeger()]; + if ( name in fonts ) + return fonts[name]; + } + else + { + _Schemes[sch] <- [{}, {}]; + } + + local id = DoGetFont( name, proportional, sch ); + if ( id > 0 ) + _Schemes[sch][proportional.tointeger()][name] <- id; + + return id; +} + +ISurface.GetFontTall <- function( id ) +{ + if ( id in _FontTall ) + return _FontTall[id]; + return _FontTall[id] <- DoGetFontTall( id ); +} + + +local _Textures = {} +local DoGetTextureID = ISurface.GetTextureID; +local DoValidateTexture = ISurface.ValidateTexture; +local DoSetTextureFile = ISurface.SetTextureFile; + +ISurface.ValidateTexture <- function( filename, hardwareFilter, forceReload = false, procedural = false ) +{ + return DoValidateTexture( filename, hardwareFilter, forceReload, procedural ); +} + +ISurface.SetTextureFile <- function( id, filename, hardwareFilter ) +{ + if ( filename in _Textures ) + delete _Textures[filename]; + + return DoSetTextureFile( id, filename, hardwareFilter ); +} + +ISurface.GetTextureID <- function( name ) +{ + if ( name in _Textures ) + return _Textures[name]; + + local id = DoGetTextureID( name ); + if ( id > 0 ) + _Textures[name] <- id; + + return id; +} + +// Forward compatibility +IVGui.GetRootPanel <- function() { return 1000 } +IVGui.GetGameUIDLLPanel <- function() { return 1001 } +IVGui.GetClientDLLPanel <- function() { return 1002 } + +local CreatePanel = IVGui.Create; +IVGui.Create <- function( type, parent, name ) +{ + if ( !parent ) + throw "invalid parent"; + + local root = 0; + + if ( typeof parent == "integer" ) + { + switch ( parent ) + { + case 1000: + root = 0; + break; + + case 1001: + root = 1; + break; + + case 1002: + root = 2; + break; + + default: + throw "invalid root panel"; + } + + parent = null; + } + + return CreatePanel( type, parent, name, root ); +} +__Documentation.RegisterHelp( "IVGui::Create", "handle IVGui::Create(string, handle, string)", "" ); + + +local pw = ScreenWidth() / 640.0; +local ph = ScreenHeight() / 480.0; + +local k = getconsttable(); +k.XRES <- function(x) { return x * pw } +k.YRES <- function(y) { return y * ph } + +ISurface.__OnScreenSizeChanged <- function() +{ + pw = ScreenWidth() / 640.0; + ph = ScreenHeight() / 480.0; + + _FontTall.clear(); +} + +)script"; diff --git a/sp/src/game/client/vscript_client.cpp b/sp/src/game/client/vscript_client.cpp index 1b2891ab1d..5479975e79 100644 --- a/sp/src/game/client/vscript_client.cpp +++ b/sp/src/game/client/vscript_client.cpp @@ -22,6 +22,7 @@ #include "materialsystem/imaterialvar.h" #include "mapbase/matchers.h" #include "mapbase/vscript_singletons.h" +#include "mapbase/vscript_vgui.h" #endif extern IScriptManager *scriptmanager; @@ -521,6 +522,9 @@ bool DoIncludeScript( const char *pszScript, HSCRIPT hScope ) } #ifdef MAPBASE_VSCRIPT +int ScriptScreenWidth(); +int ScriptScreenHeight(); + static float FrameTime() { return gpGlobals->frametime; @@ -536,27 +540,6 @@ static bool IsWindowedMode() return engine->IsWindowedMode(); } -int ScreenTransform( const Vector& point, Vector& screen ); - -//----------------------------------------------------------------------------- -// Input array [x,y], set normalised screen space pos. Return true if on screen -//----------------------------------------------------------------------------- -static bool ScriptScreenTransform( const Vector &pos, HSCRIPT hArray ) -{ - if ( g_pScriptVM->GetNumTableEntries(hArray) >= 2 ) - { - Vector v; - bool r = ScreenTransform( pos, v ); - float x = 0.5f * ( 1.0f + v[0] ); - float y = 0.5f * ( 1.0f - v[1] ); - - g_pScriptVM->SetValue( hArray, ScriptVariant_t(0), x ); - g_pScriptVM->SetValue( hArray, 1, y ); - return !r; - } - return false; -} - // Creates a client-side prop HSCRIPT CreateProp( const char *pszEntityName, const Vector &vOrigin, const char *pszModelName, int iAnim ) { @@ -652,10 +635,9 @@ bool VScriptClientInit() #ifdef MAPBASE_VSCRIPT ScriptRegisterFunction( g_pScriptVM, FrameTime, "Get the time spent on the client in the last frame" ); ScriptRegisterFunction( g_pScriptVM, Con_IsVisible, "Returns true if the console is visible" ); - ScriptRegisterFunction( g_pScriptVM, ScreenWidth, "Width of the screen in pixels" ); - ScriptRegisterFunction( g_pScriptVM, ScreenHeight, "Height of the screen in pixels" ); + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptScreenWidth, "ScreenWidth", "Width of the screen in pixels" ); + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptScreenHeight, "ScreenHeight", "Height of the screen in pixels" ); ScriptRegisterFunction( g_pScriptVM, IsWindowedMode, "" ); - ScriptRegisterFunctionNamed( g_pScriptVM, ScriptScreenTransform, "ScreenTransform", "Get the x & y positions of a world position in screen space. Returns true if it's onscreen" ); ScriptRegisterFunction( g_pScriptVM, MainViewOrigin, "" ); ScriptRegisterFunction( g_pScriptVM, MainViewAngles, "" ); @@ -690,6 +672,7 @@ bool VScriptClientInit() RegisterSharedScriptConstants(); RegisterSharedScriptFunctions(); + RegisterScriptVGUI(); #else //g_pScriptVM->RegisterInstance( &g_ScriptEntityIterator, "Entities" ); #endif