Compare commits

...

6 Commits

7 changed files with 295 additions and 77 deletions

View File

@@ -0,0 +1,41 @@
# Experimental VGUI2 Support
Thanks to @kungfulon contributions, Xash3D FWGS now supports VGUI2.
VGUI2 is undocumented UI system from Source Engine that GoldSrc used in some games and it's main menu.
## Support status
Doesn't draw anything, doesn't take any input.
## List of games that require VGUI2 support
- Counter-Strike 1.6
- Counter-Strike: Condition Zero
- Counter-Strike: Condition Zero Deleted Scenes
- Day of Defeat
- Half-Life: Blue Shift
## How to enable VGUI2 support
By default, engine doesn't initialize VGUI2 to not confuse existing games and mods that use or do not use VGUI1. This support also relies on a number of proprietary libraries, that we better not redistribute, so you have to supply them yourself. Keep in mind, that these libraries are compiled only for 32-bit Windows, Linux and OSX, you shouldn't expect them running anywhere else.
1. Download latest Half-Life from Steam.
2. Open local files.
3. Copy libraries in the list below according to your platform, to folder where Xash3D searches it's libraries (usually in same folder where executable is located)
| Linux | Windows
| -------- | --------
| `chromehtml.so` | `chromehtml.dll`
| `vgui2.so` | `vgui2.dll`
| `libcef.so` | `libcef.dll`
| `libtier0.so` | `tier0.dll`
| `libvstdlib.so` | `vstdlib.dll`
| `libsteam_api.so` | `steam_api.dll`
Some files must also be copied:
- `cef_gtk.pak`
Additionally, on Linux other libraries must be provided. Use `ldd` tool to figure out which libraries you miss. Many of them can be pulled from Steam Runtime.
Do not recommend using RoDir with VGUI2 games. Many of them are broken. Steam API will crash without `steam_appid.txt` in Xash root directory.

View File

@@ -3922,7 +3922,7 @@ qboolean CL_LoadProgs( const char *name )
// during LoadLibrary // during LoadLibrary
if( !GI->internal_vgui_support && VGui_LoadProgs( NULL )) if( !GI->internal_vgui_support && VGui_LoadProgs( NULL ))
{ {
VGui_Startup( refState.width, refState.height ); VGui_Startup( NULL, refState.width, refState.height );
} }
else else
{ {
@@ -3938,7 +3938,8 @@ qboolean CL_LoadProgs( const char *name )
// delayed vgui initialization for internal support // delayed vgui initialization for internal support
if( GI->internal_vgui_support && VGui_LoadProgs( clgame.hInstance )) if( GI->internal_vgui_support && VGui_LoadProgs( clgame.hInstance ))
{ {
VGui_Startup( refState.width, refState.height ); // do not pass client pointer yet
VGui_Startup( NULL, refState.width, refState.height );
} }
// clear exports // clear exports
@@ -4021,6 +4022,9 @@ qboolean CL_LoadProgs( const char *name )
return false; return false;
} }
// try to load VGUI2
VGui_Startup( clgame.hInstance, refState.width, refState.height );
Cvar_FullSet( "host_clientloaded", "1", FCVAR_READ_ONLY ); Cvar_FullSet( "host_clientloaded", "1", FCVAR_READ_ONLY );
clgame.maxRemapInfos = 0; // will be alloc on first call CL_InitEdicts(); clgame.maxRemapInfos = 0; // will be alloc on first call CL_InitEdicts();

View File

@@ -715,7 +715,9 @@ void SCR_VidInit( void )
// notify vgui about screen size change // notify vgui about screen size change
if( clgame.hInstance ) if( clgame.hInstance )
{ {
VGui_Startup( refState.width, refState.height ); // do not pass client pointer, we do not want to
// re-initialize vgui2
VGui_Startup( NULL, refState.width, refState.height );
} }
CL_ClearSpriteTextures(); // now all hud sprites are invalid CL_ClearSpriteTextures(); // now all hud sprites are invalid

View File

@@ -35,7 +35,7 @@ static qboolean GAME_EXPORT VGUI_IsInGame( void );
static struct static struct
{ {
qboolean initialized; qboolean initialized;
vguiapi_t dllFuncs; vgui_support_interface_t dllFuncs;
VGUI_DefaultCursor cursor; VGUI_DefaultCursor cursor;
HINSTANCE hInstance; HINSTANCE hInstance;
@@ -44,32 +44,7 @@ static struct
} vgui = } vgui =
{ {
false, false,
{ { 0 }, // not initialized yet
false, // Not initialized yet
NULL, // VGUI_DrawInit,
NULL, // VGUI_DrawShutdown,
NULL, // VGUI_SetupDrawingText,
NULL, // VGUI_SetupDrawingRect,
NULL, // VGUI_SetupDrawingImage,
NULL, // VGUI_BindTexture,
NULL, // VGUI_EnableTexture,
NULL, // VGUI_CreateTexture,
NULL, // VGUI_UploadTexture,
NULL, // VGUI_UploadTextureBlock,
NULL, // VGUI_DrawQuad,
NULL, // VGUI_GetTextureSizes,
NULL, // VGUI_GenerateTexture,
VGUI_EngineMalloc,
VGUI_CursorSelect,
VGUI_GetColor,
VGUI_IsInGame,
Key_EnableTextInput,
VGUI_GetMousePos,
VGUI_UtfProcessChar,
Platform_GetClipboardText,
Platform_SetClipboardText,
Platform_GetKeyModifiers,
},
-1 -1
}; };
@@ -117,7 +92,37 @@ qboolean VGui_IsActive( void )
return vgui.initialized; return vgui.initialized;
} }
static void VGui_FillAPIFromRef( vguiapi_t *to, const ref_interface_t *from ) static vgui_support_api_t gEngfuncs =
{
NULL, // VGUI_DrawInit,
NULL, // VGUI_DrawShutdown,
NULL, // VGUI_SetupDrawingText,
NULL, // VGUI_SetupDrawingRect,
NULL, // VGUI_SetupDrawingImage,
NULL, // VGUI_BindTexture,
NULL, // VGUI_EnableTexture,
NULL, // VGUI_CreateTexture,
NULL, // VGUI_UploadTexture,
NULL, // VGUI_UploadTextureBlock,
NULL, // VGUI_DrawQuad,
NULL, // VGUI_GetTextureSizes,
NULL, // VGUI_GenerateTexture,
VGUI_EngineMalloc,
VGUI_CursorSelect,
VGUI_GetColor,
VGUI_IsInGame,
Key_EnableTextInput,
VGUI_GetMousePos,
VGUI_UtfProcessChar,
Platform_GetClipboardText,
Platform_SetClipboardText,
Platform_GetKeyModifiers,
COM_LoadLibrary,
COM_FreeLibrary,
COM_GetProcAddress,
};
static void VGui_FillAPIFromRef( vgui_support_api_t *to, const ref_interface_t *from )
{ {
to->DrawInit = from->VGUI_DrawInit; to->DrawInit = from->VGUI_DrawInit;
to->DrawShutdown = from->VGUI_DrawShutdown; to->DrawShutdown = from->VGUI_DrawShutdown;
@@ -139,56 +144,144 @@ void VGui_RegisterCvars( void )
Cvar_RegisterVariable( &vgui_utf8 ); Cvar_RegisterVariable( &vgui_utf8 );
} }
static HINSTANCE VGui_LoadSupportLibrary( void )
{
string vguiloader;
string vguilib;
HINSTANCE hInstance;
// HACKHACK: try to load path from custom path
// to support having different versions of VGUI
if( Sys_GetParmFromCmdLine( "-vguilib", vguilib ) && !COM_LoadLibrary( vguilib, false, false ))
{
Con_Reportf( S_WARN "VGUI preloading failed. Default library will be used! Reason: %s", COM_GetLibraryError());
}
if( !Sys_GetParmFromCmdLine( "-vguiloader", vguiloader ))
{
Q_strncpy( vguiloader, VGUI_SUPPORT_DLL, sizeof( vguiloader ));
}
hInstance = COM_LoadLibrary( vguiloader, false, false );
if( !hInstance )
{
if( FS_FileExists( vguiloader, false ))
Con_Reportf( S_ERROR "Failed to load vgui_support library: %s\n", COM_GetLibraryError() );
else Con_Reportf( "vgui_support: not found\n" );
}
return hInstance;
}
static qboolean VGui_ProbeNewAPI( HINSTANCE hInstance,
vgui_support_interface_t *iface, const vgui_support_api_t *api )
{
const int version = VGUI_SUPPORT_API_VERSION;
static vgui_support_api_t localapi;
VGUISUPPORTAPI F;
F = COM_GetProcAddress( hInstance, GET_VGUI_SUPPORT_API );
if( !F )
return false;
// keep local temporary copy, do not let vgui_support to mess up here
memcpy( &localapi, api, sizeof( localapi ));
if( F( version, iface, &localapi ) != version )
return false;
Con_Reportf( "vgui_support: initialized new API\n" );
return true;
}
static qboolean VGui_ProbeOldAPI( HINSTANCE hInstance,
vgui_support_interface_t *iface, const vgui_support_api_t *api,
qboolean client )
{
static legacy_vguiapi_t localapi;
LEGACY_VGUISUPPORTAPI F;
F = COM_GetProcAddress( hInstance, client ? LEGACY_CLIENT_GET_VGUI_SUPPORT_API : LEGACY_GET_VGUI_SUPPORT_API );
if( !F )
return false;
memset( &localapi, 0, sizeof( localapi ));
localapi.DrawInit = api->DrawInit;
localapi.DrawShutdown = api->DrawShutdown;
localapi.SetupDrawingText = api->SetupDrawingText;
localapi.SetupDrawingRect = api->SetupDrawingRect;
localapi.SetupDrawingImage = api->SetupDrawingImage;
localapi.BindTexture = api->BindTexture;
localapi.EnableTexture = api->EnableTexture;
localapi.CreateTexture = api->CreateTexture;
localapi.UploadTexture = api->UploadTexture;
localapi.UploadTextureBlock = api->UploadTextureBlock;
localapi.DrawQuad = api->DrawQuad;
localapi.GetTextureSizes = api->GetTextureSizes;
localapi.GenerateTexture = api->GenerateTexture;
localapi.EngineMalloc = api->EngineMalloc;
localapi.CursorSelect = api->CursorSelect;
localapi.GetColor = api->GetColor;
localapi.IsInGame = api->IsInGame;
localapi.EnableTextInput = api->EnableTextInput;
localapi.GetCursorPos = api->GetCursorPos;
localapi.ProcessUtfChar = api->ProcessUtfChar;
localapi.GetClipboardText = api->GetClipboardText;
localapi.SetClipboardText = api->SetClipboardText;
localapi.GetKeyModifiers = api->GetKeyModifiers;
F( &localapi );
localapi.initialized = true;
iface->Startup = localapi.Startup;
iface->Shutdown = localapi.Shutdown;
iface->GetPanel = localapi.GetPanel;
iface->Paint = localapi.Paint;
iface->Mouse = localapi.Mouse;
iface->Key = localapi.Key;
iface->MouseMove = localapi.MouseMove;
iface->TextInput = localapi.TextInput;
Con_Reportf( "vgui_support: initialized legacy API in %s module\n", client ? "client" : "support" );
return true;
}
qboolean VGui_LoadProgs( HINSTANCE hInstance ) qboolean VGui_LoadProgs( HINSTANCE hInstance )
{ {
void (*F)( vguiapi_t* ); LEGACY_VGUISUPPORTAPI F;
qboolean client = hInstance != NULL; qboolean client = hInstance != NULL;
// not loading interface from client.dll, load vgui_support.dll instead // not loading interface from client.dll, load vgui_support.dll instead
if( !client ) if( !client )
{ {
string vguiloader, vguilib; hInstance = vgui.hInstance = VGui_LoadSupportLibrary();
// HACKHACK: try to load path from custom path if( !hInstance )
// to support having different versions of VGUI return false;
if( Sys_GetParmFromCmdLine( "-vguilib", vguilib ) && !COM_LoadLibrary( vguilib, false, false )) }
// prepare api funcs
VGui_FillAPIFromRef( &gEngfuncs, &ref.dllFuncs );
// try new API first
if( !VGui_ProbeNewAPI( vgui.hInstance, &vgui.dllFuncs, &gEngfuncs ))
{
// try legacy API next
if( !VGui_ProbeOldAPI( vgui.hInstance, &vgui.dllFuncs, &gEngfuncs, client ))
{ {
Con_Reportf( S_WARN "VGUI preloading failed. Default library will be used! Reason: %s", COM_GetLibraryError()); Con_Reportf( S_ERROR "Failed to find VGUI support API entry point in %s module\n", client ? "client" : "support" );
}
if( !Sys_GetParmFromCmdLine( "-vguiloader", vguiloader ))
{
Q_strncpy( vguiloader, VGUI_SUPPORT_DLL, sizeof( vguiloader ));
}
hInstance = vgui.hInstance = COM_LoadLibrary( vguiloader, false, false );
if( !vgui.hInstance )
{
if( FS_FileExists( vguiloader, false ))
Con_Reportf( S_ERROR "Failed to load vgui_support library: %s\n", COM_GetLibraryError() );
else Con_Reportf( "vgui_support: not found\n" );
return false; return false;
} }
} }
// try legacy API first vgui.initialized = true;
F = COM_GetProcAddress( hInstance, client ? "InitVGUISupportAPI" : "InitAPI" ); return true;
if( F )
{
VGui_FillAPIFromRef( &vgui.dllFuncs, &ref.dllFuncs );
F( &vgui.dllFuncs );
vgui.initialized = vgui.dllFuncs.initialized = true;
Con_Reportf( "vgui_support: initialized legacy API in %s module\n", client ? "client" : "support" );
return true;
}
Con_Reportf( S_ERROR "Failed to find VGUI support API entry point in %s module\n", client ? "client" : "support" );
return false;
} }
/* /*
@@ -197,7 +290,7 @@ VGui_Startup
================ ================
*/ */
void VGui_Startup( int width, int height ) void VGui_Startup( HINSTANCE clientInstance, int width, int height )
{ {
// vgui not initialized from both support and client modules, skip // vgui not initialized from both support and client modules, skip
if( !vgui.initialized ) if( !vgui.initialized )
@@ -212,12 +305,18 @@ void VGui_Startup( int width, int height )
else if( width <= 1280 ) width = 1280; else if( width <= 1280 ) width = 1280;
else if( width <= 1600 ) width = 1600; else if( width <= 1600 ) width = 1600;
if( vgui.dllFuncs.Startup ) if( !clientInstance )
vgui.dllFuncs.Startup( width, height ); {
if( vgui.dllFuncs.Startup )
vgui.dllFuncs.Startup( width, height );
}
else
{
if( vgui.dllFuncs.ClientStartup )
vgui.dllFuncs.ClientStartup( clientInstance, width, height );
}
} }
/* /*
================ ================
VGui_Shutdown VGui_Shutdown

View File

@@ -21,7 +21,7 @@ GNU General Public License for more details.
// //
void VGui_RegisterCvars( void ); void VGui_RegisterCvars( void );
qboolean VGui_LoadProgs( HINSTANCE hInstance ); qboolean VGui_LoadProgs( HINSTANCE hInstance );
void VGui_Startup( int width, int height ); void VGui_Startup( HINSTANCE clientInstance, int width, int height );
void VGui_Shutdown( void ); void VGui_Shutdown( void );
void VGui_Paint( void ); void VGui_Paint( void );
void VGui_RunFrame( void ); void VGui_RunFrame( void );

View File

@@ -19,6 +19,12 @@ GNU General Public License for more details.
#include "key_modifiers.h" #include "key_modifiers.h"
#include "cursor_type.h" #include "cursor_type.h"
// VGUI support API changelog:
// 1. Initial revision
#define VGUI_SUPPORT_API_VERSION 1
#define ENABLE_LEGACY_API_SUPPORT 1
// VGUI generic vertex // VGUI generic vertex
typedef struct typedef struct
@@ -151,6 +157,7 @@ enum VGUI_KeyAction
KA_PRESSED, KA_PRESSED,
KA_RELEASED KA_RELEASED
}; };
enum VGUI_MouseAction enum VGUI_MouseAction
{ {
MA_PRESSED=0, MA_PRESSED=0,
@@ -159,7 +166,8 @@ enum VGUI_MouseAction
MA_WHEEL MA_WHEEL
}; };
typedef struct vguiapi_s #if ENABLE_LEGACY_API_SUPPORT
typedef struct legacy_vguiapi_s
{ {
qboolean initialized; qboolean initialized;
// called from vgui_support // called from vgui_support
@@ -195,5 +203,69 @@ typedef struct vguiapi_s
void (*Key)( enum VGUI_KeyAction action, enum VGUI_KeyCode code ); void (*Key)( enum VGUI_KeyAction action, enum VGUI_KeyCode code );
void (*MouseMove)( int x, int y ); void (*MouseMove)( int x, int y );
void (*TextInput)( const char *text ); void (*TextInput)( const char *text );
} vguiapi_t; } legacy_vguiapi_t;
typedef void (*LEGACY_VGUISUPPORTAPI)( legacy_vguiapi_t * );
#define LEGACY_GET_VGUI_SUPPORT_API "InitAPI"
#define LEGACY_CLIENT_GET_VGUI_SUPPORT_API "InitVGUISupportAPI"
#define vguiapi_t legacy_vguiapi_t
#endif // ENABLE_LEGACY_API_SUPPORT
typedef struct vgui_support_api_s
{
// LEGACY COMPATIBLE FUNCTIONS
void (*DrawInit)( void );
void (*DrawShutdown)( void );
void (*SetupDrawingText)( int *pColor );
void (*SetupDrawingRect)( int *pColor );
void (*SetupDrawingImage)( int *pColor );
void (*BindTexture)( int id );
void (*EnableTexture)( qboolean enable );
void (*CreateTexture)( int id, int width, int height );
void (*UploadTexture)( int id, const char *buffer, int width, int height );
void (*UploadTextureBlock)( int id, int drawX, int drawY, const byte *rgba, int blockWidth, int blockHeight );
void (*DrawQuad)( const vpoint_t *ul, const vpoint_t *lr );
void (*GetTextureSizes)( int *width, int *height );
int (*GenerateTexture)( void );
void *(*EngineMalloc)( size_t size );
void (*CursorSelect)( VGUI_DefaultCursor cursor );
byte (*GetColor)( int i, int j );
qboolean (*IsInGame)( void );
void (*EnableTextInput)( qboolean enable, qboolean force );
void (*GetCursorPos)( int *x, int *y );
int (*ProcessUtfChar)( int ch );
int (*GetClipboardText)( char *buffer, size_t bufferSize );
void (*SetClipboardText)( const char *text );
key_modifier_t (*GetKeyModifiers)( void );
// END OF LEGACY COMPATIBLE FUCNTIONS
// DON'T BREAK ABI, ONLY ADD NEW FUNCTIONS TO THE END OF STRUCTURE
void *(*LoadLibrary)( const char *dllname, int build_ordinals_table, qboolean directpath );
void (*FreeLibrary)( void *hInstance );
void *(*GetProcAddress)( void *hInstance, const char *name );
} vgui_support_api_t;
typedef struct vgui_support_interface_s
{
// LEGACY COMPATIBLE FUNCTIONS
void (*Startup)( int width, int height );
void (*Shutdown)( void );
void *(*GetPanel)( void );
void (*Paint)( void );
void (*Mouse)( enum VGUI_MouseAction action, int code );
void (*Key)( enum VGUI_KeyAction action, enum VGUI_KeyCode code );
void (*MouseMove)( int x, int y );
void (*TextInput)( const char *text );
// END OF LEGACY COMPATIBLE FUCNTIONS
// DON'T BREAK ABI, ONLY ADD NEW FUNCTIONS TO THE END OF STRUCTURE
// initialize VGUI2 after client.dll was loaded
void (*ClientStartup)( void *clientInstance, int width, int height );
} vgui_support_interface_t;
typedef int (*VGUISUPPORTAPI)( int version, vgui_support_interface_t *pFunctionTable, vgui_support_api_t *engfuncs );
#define GET_VGUI_SUPPORT_API "GetVGUISupportAPI"
#endif // VGUI_API_H #endif // VGUI_API_H