Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New vgui support api #1346

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion 3rdparty/vgui_support
41 changes: 41 additions & 0 deletions Documentation/vgui2-support.md
Original file line number Diff line number Diff line change
@@ -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.
8 changes: 6 additions & 2 deletions engine/client/cl_game.c
Original file line number Diff line number Diff line change
Expand Up @@ -3922,7 +3922,7 @@ qboolean CL_LoadProgs( const char *name )
// during LoadLibrary
if( !GI->internal_vgui_support && VGui_LoadProgs( NULL ))
{
VGui_Startup( refState.width, refState.height );
VGui_Startup( NULL, refState.width, refState.height );
}
else
{
Expand All @@ -3938,7 +3938,8 @@ qboolean CL_LoadProgs( const char *name )
// delayed vgui initialization for internal support
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
Expand Down Expand Up @@ -4021,6 +4022,9 @@ qboolean CL_LoadProgs( const char *name )
return false;
}

// try to load VGUI2
VGui_Startup( clgame.hInstance, refState.width, refState.height );

Cvar_FullSet( "host_clientloaded", "1", FCVAR_READ_ONLY );

clgame.maxRemapInfos = 0; // will be alloc on first call CL_InitEdicts();
Expand Down
4 changes: 3 additions & 1 deletion engine/client/cl_scrn.c
Original file line number Diff line number Diff line change
Expand Up @@ -715,7 +715,9 @@ void SCR_VidInit( void )
// notify vgui about screen size change
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
Expand Down
235 changes: 167 additions & 68 deletions engine/client/vgui/vgui_draw.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ static qboolean GAME_EXPORT VGUI_IsInGame( void );
static struct
{
qboolean initialized;
vguiapi_t dllFuncs;
vgui_support_interface_t dllFuncs;
VGUI_DefaultCursor cursor;

HINSTANCE hInstance;
Expand All @@ -44,32 +44,7 @@ static struct
} vgui =
{
false,
{
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,
},
{ 0 }, // not initialized yet
-1
};

Expand Down Expand Up @@ -117,7 +92,37 @@ qboolean VGui_IsActive( void )
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->DrawShutdown = from->VGUI_DrawShutdown;
Expand All @@ -139,56 +144,144 @@ void VGui_RegisterCvars( void )
Cvar_RegisterVariable( &vgui_utf8 );
}

qboolean VGui_LoadProgs( HINSTANCE hInstance )
static HINSTANCE VGui_LoadSupportLibrary( void )
{
void (*F)( vguiapi_t* );
qboolean client = hInstance != NULL;
string vguiloader;
string vguilib;
HINSTANCE hInstance;

// not loading interface from client.dll, load vgui_support.dll instead
if( !client )
// 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 ))
{
string vguiloader, vguilib;
Con_Reportf( S_WARN "VGUI preloading failed. Default library will be used! Reason: %s", COM_GetLibraryError());
}

// 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 ));
}

if( !Sys_GetParmFromCmdLine( "-vguiloader", vguiloader ))
{
Q_strncpy( vguiloader, VGUI_SUPPORT_DLL, sizeof( vguiloader ));
}
hInstance = COM_LoadLibrary( vguiloader, false, false );

hInstance = vgui.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" );
}

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 hInstance;
}

return false;
}
}
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 ));

// try legacy API first
F = COM_GetProcAddress( hInstance, client ? "InitVGUISupportAPI" : "InitAPI" );
if( F( version, iface, &localapi ) != version )
return false;

if( F )
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 )
{
LEGACY_VGUISUPPORTAPI F;
qboolean client = hInstance != NULL;

// not loading interface from client.dll, load vgui_support.dll instead
if( !client )
{
VGui_FillAPIFromRef( &vgui.dllFuncs, &ref.dllFuncs );
F( &vgui.dllFuncs );
hInstance = vgui.hInstance = VGui_LoadSupportLibrary();

if( !hInstance )
return false;
}

vgui.initialized = vgui.dllFuncs.initialized = true;
Con_Reportf( "vgui_support: initialized legacy API in %s module\n", client ? "client" : "support" );
// prepare api funcs
VGui_FillAPIFromRef( &gEngfuncs, &ref.dllFuncs );

return true;
// 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_ERROR "Failed to find VGUI support API entry point in %s module\n", client ? "client" : "support" );
return false;
}
}

Con_Reportf( S_ERROR "Failed to find VGUI support API entry point in %s module\n", client ? "client" : "support" );
return false;
vgui.initialized = true;
return true;
}

/*
Expand All @@ -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
if( !vgui.initialized )
Expand All @@ -212,12 +305,18 @@ void VGui_Startup( int width, int height )
else if( width <= 1280 ) width = 1280;
else if( width <= 1600 ) width = 1600;

if( vgui.dllFuncs.Startup )
vgui.dllFuncs.Startup( width, height );
if( !clientInstance )
{
if( vgui.dllFuncs.Startup )
vgui.dllFuncs.Startup( width, height );
}
else
{
if( vgui.dllFuncs.ClientStartup )
vgui.dllFuncs.ClientStartup( clientInstance, width, height );
}
}



/*
================
VGui_Shutdown
Expand Down
2 changes: 1 addition & 1 deletion engine/client/vgui/vgui_draw.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ GNU General Public License for more details.
//
void VGui_RegisterCvars( void );
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_Paint( void );
void VGui_RunFrame( void );
Expand Down
Loading