2
0
mirror of https://github.com/FWGS/xash3d-fwgs synced 2024-11-22 09:56:22 +01:00
xash3d-fwgs/engine/client/cl_gameui.c

1460 lines
31 KiB
C
Raw Permalink Normal View History

/*
cl_menu.c - menu dlls interaction
Copyright (C) 2010 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "common.h"
#include "client.h"
#include "const.h"
#include "library.h"
#include "input.h"
2018-04-20 23:36:14 +02:00
#include "server.h" // !!svgame.hInstance
#include "vid_common.h"
static void UI_UpdateUserinfo( void );
gameui_static_t gameui;
static void UI_ToggleAllowConsole_f( void )
{
host.allow_console = host.allow_console_init = true;
if( gameui.globals )
gameui.globals->developer = true;
}
void UI_UpdateMenu( float realtime )
{
if( !gameui.hInstance ) return;
2018-10-04 08:08:48 +02:00
// if some deferred cmds is waiting
if( UI_IsVisible() && COM_CheckString( host.deferred_cmd ))
{
Cbuf_AddText( host.deferred_cmd );
host.deferred_cmd[0] = '\0';
Cbuf_Execute();
return;
}
// don't show menu while level is loaded
if( GameState->nextstate != STATE_RUNFRAME && !GameState->loadGame )
return;
// menu time (not paused, not clamped)
gameui.globals->time = host.realtime;
gameui.globals->frametime = host.realframetime;
gameui.globals->demoplayback = cls.demoplayback;
gameui.globals->demorecording = cls.demorecording;
gameui.globals->developer = host.allow_console;
gameui.dllFuncs.pfnRedraw( realtime );
UI_UpdateUserinfo();
}
void UI_KeyEvent( int key, qboolean down )
{
if( !gameui.hInstance ) return;
gameui.dllFuncs.pfnKeyEvent( key, down );
}
void UI_MouseMove( int x, int y )
{
if( !gameui.hInstance ) return;
gameui.dllFuncs.pfnMouseMove( x, y );
}
void UI_SetActiveMenu( qboolean fActive )
{
movie_state_t *cin_state;
if( !gameui.hInstance )
{
if( !fActive )
Key_SetKeyDest( key_game );
return;
}
gameui.drawLogo = fActive;
gameui.dllFuncs.pfnSetActiveMenu( fActive );
if( !fActive )
{
// close logo when menu is shutdown
cin_state = AVI_GetState( CIN_LOGO );
AVI_CloseVideo( cin_state );
}
}
void UI_AddServerToList( netadr_t adr, const char *info )
{
if( !gameui.hInstance ) return;
gameui.dllFuncs.pfnAddServerToList( adr, info );
}
void UI_GetCursorPos( int *pos_x, int *pos_y )
{
if( !gameui.hInstance ) return;
gameui.dllFuncs.pfnGetCursorPos( pos_x, pos_y );
}
void UI_SetCursorPos( int pos_x, int pos_y )
{
if( !gameui.hInstance ) return;
gameui.dllFuncs.pfnSetCursorPos( pos_x, pos_y );
}
void UI_ShowCursor( qboolean show )
{
if( !gameui.hInstance ) return;
gameui.dllFuncs.pfnShowCursor( show );
}
qboolean UI_CreditsActive( void )
{
if( !gameui.hInstance ) return 0;
return gameui.dllFuncs.pfnCreditsActive();
}
void UI_CharEvent( int key )
{
if( !gameui.hInstance ) return;
gameui.dllFuncs.pfnCharEvent( key );
}
qboolean UI_MouseInRect( void )
{
if( !gameui.hInstance ) return 1;
return gameui.dllFuncs.pfnMouseInRect();
}
qboolean UI_IsVisible( void )
{
if( !gameui.hInstance ) return 0;
return gameui.dllFuncs.pfnIsVisible();
}
/*
=======================
UI_AddTouchButtonToList
send button parameters to menu
=======================
*/
void UI_AddTouchButtonToList( const char *name, const char *texture, const char *command, unsigned char *color, int flags )
{
if( gameui.dllFuncs2.pfnAddTouchButtonToList )
{
gameui.dllFuncs2.pfnAddTouchButtonToList( name, texture, command, color, flags );
}
}
/*
=================
UI_ResetPing
notify gameui dll about latency reset
=================
*/
void UI_ResetPing( void )
{
if( gameui.dllFuncs2.pfnResetPing )
{
gameui.dllFuncs2.pfnResetPing( );
}
}
/*
=================
UI_ShowConnectionWarning
show connection warning dialog implemented by gameui dll
=================
*/
void UI_ShowConnectionWarning( void )
{
if( cls.state != ca_connected )
return;
if( Host_IsLocalClient() )
return;
if( ++cl.lostpackets == 8 )
{
CL_Disconnect();
if( gameui.dllFuncs2.pfnShowConnectionWarning )
{
gameui.dllFuncs2.pfnShowConnectionWarning();
}
Con_DPrintf( S_WARN "Too many lost packets! Showing Network options menu\n" );
}
}
/*
=================
UI_ShowConnectionWarning
show update dialog
=================
*/
void UI_ShowUpdateDialog( qboolean preferStore )
{
if( gameui.dllFuncs2.pfnShowUpdateDialog )
{
gameui.dllFuncs2.pfnShowUpdateDialog( preferStore );
}
Con_Printf( S_WARN "This version is not supported anymore. To continue, install latest engine version\n" );
}
/*
=================
UI_ShowConnectionWarning
show message box
=================
*/
qboolean UI_ShowMessageBox( const char *text )
{
if( gameui.dllFuncs2.pfnShowMessageBox )
{
gameui.dllFuncs2.pfnShowMessageBox( text );
return true;
}
return false;
}
void UI_ConnectionProgress_Disconnect( void )
{
if( gameui.dllFuncs2.pfnConnectionProgress_Disconnect )
{
gameui.dllFuncs2.pfnConnectionProgress_Disconnect( );
}
}
void UI_ConnectionProgress_Download( const char *pszFileName, const char *pszServerName, const char *pszServerPath, int iCurrent, int iTotal, const char *comment )
{
if( !gameui.dllFuncs2.pfnConnectionProgress_Download )
return;
if( pszServerPath )
{
char serverpath[MAX_SYSPATH];
Q_snprintf( serverpath, sizeof( serverpath ), "%s%s", pszServerName, pszServerPath );
gameui.dllFuncs2.pfnConnectionProgress_Download( pszFileName, serverpath, iCurrent, iTotal, comment );
}
else
{
gameui.dllFuncs2.pfnConnectionProgress_Download( pszFileName, pszServerName, iCurrent, iTotal, comment );
}
}
void UI_ConnectionProgress_DownloadEnd( void )
{
if( gameui.dllFuncs2.pfnConnectionProgress_DownloadEnd )
{
gameui.dllFuncs2.pfnConnectionProgress_DownloadEnd( );
}
}
void UI_ConnectionProgress_Precache( void )
{
if( gameui.dllFuncs2.pfnConnectionProgress_Precache )
{
gameui.dllFuncs2.pfnConnectionProgress_Precache( );
}
}
void UI_ConnectionProgress_Connect( const char *server ) // NULL for local server
{
if( gameui.dllFuncs2.pfnConnectionProgress_Connect )
{
gameui.dllFuncs2.pfnConnectionProgress_Connect( server );
}
}
void UI_ConnectionProgress_ChangeLevel( void )
{
if( gameui.dllFuncs2.pfnConnectionProgress_ChangeLevel )
{
gameui.dllFuncs2.pfnConnectionProgress_ChangeLevel( );
}
}
void UI_ConnectionProgress_ParseServerInfo( const char *server )
{
if( gameui.dllFuncs2.pfnConnectionProgress_ParseServerInfo )
{
gameui.dllFuncs2.pfnConnectionProgress_ParseServerInfo( server );
}
}
2020-01-19 02:15:54 +01:00
static void GAME_EXPORT UI_DrawLogo( const char *filename, float x, float y, float width, float height )
{
static float cin_time;
static int last_frame = -1;
byte *cin_data = NULL;
movie_state_t *cin_state;
int cin_frame;
qboolean redraw = false;
if( !gameui.drawLogo ) return;
cin_state = AVI_GetState( CIN_LOGO );
if( !AVI_IsActive( cin_state ))
{
string path;
const char *fullpath;
// run cinematic if not
Q_snprintf( path, sizeof( path ), "media/%s", filename );
COM_DefaultExtension( path, ".avi", sizeof( path ));
fullpath = FS_GetDiskPath( path, false );
if( FS_FileExists( path, false ) && !fullpath )
{
2018-10-04 08:08:48 +02:00
Con_Printf( S_ERROR "Couldn't load %s from packfile. Please extract it\n", path );
gameui.drawLogo = false;
return;
}
AVI_OpenVideo( cin_state, fullpath, false, true );
if( !( AVI_GetVideoInfo( cin_state, &gameui.logo_xres, &gameui.logo_yres, &gameui.logo_length )))
{
AVI_CloseVideo( cin_state );
gameui.drawLogo = false;
return;
}
cin_time = 0.0f;
last_frame = -1;
}
if( width <= 0 || height <= 0 )
{
// precache call, don't draw
cin_time = 0.0f;
last_frame = -1;
return;
}
// advances cinematic time (ignores maxfps and host_framerate settings)
cin_time += host.realframetime;
// restarts the cinematic
if( cin_time > gameui.logo_length )
cin_time = 0.0f;
// read the next frame
cin_frame = AVI_GetVideoFrameNumber( cin_state, cin_time );
if( cin_frame != last_frame )
{
cin_data = AVI_GetVideoFrame( cin_state, cin_frame );
last_frame = cin_frame;
redraw = true;
}
ref.dllFuncs.R_DrawStretchRaw( x, y, width, height, gameui.logo_xres, gameui.logo_yres, cin_data, redraw );
}
2020-01-19 02:15:54 +01:00
static int GAME_EXPORT UI_GetLogoWidth( void )
{
return gameui.logo_xres;
}
2020-01-19 02:15:54 +01:00
static int GAME_EXPORT UI_GetLogoHeight( void )
{
return gameui.logo_yres;
}
2020-01-19 02:15:54 +01:00
static float GAME_EXPORT UI_GetLogoLength( void )
{
return gameui.logo_length;
}
static void UI_UpdateUserinfo( void )
{
player_info_t *player;
if( !host.userinfo_changed )
return;
player = &gameui.playerinfo;
Q_strncpy( player->userinfo, cls.userinfo, sizeof( player->userinfo ));
Q_strncpy( player->name, Info_ValueForKey( player->userinfo, "name" ), sizeof( player->name ));
Q_strncpy( player->model, Info_ValueForKey( player->userinfo, "model" ), sizeof( player->model ));
player->topcolor = Q_atoi( Info_ValueForKey( player->userinfo, "topcolor" ));
player->bottomcolor = Q_atoi( Info_ValueForKey( player->userinfo, "bottomcolor" ));
host.userinfo_changed = false; // we got it
}
void Host_Credits( void )
{
if( !gameui.hInstance ) return;
gameui.dllFuncs.pfnFinalCredits();
}
static void UI_ConvertGameInfo( gameinfo2_t *out, const gameinfo_t *in )
{
out->gi_version = GAMEINFO_VERSION;
Q_strncpy( out->gamefolder, in->gamefolder, sizeof( out->gamefolder ));
Q_strncpy( out->startmap, in->startmap, sizeof( out->startmap ));
Q_strncpy( out->trainmap, in->trainmap, sizeof( out->trainmap ));
Q_strncpy( out->demomap, in->demomap, sizeof( out->demomap ));
Q_strncpy( out->title, in->title, sizeof( out->title ));
Q_snprintf( out->version, sizeof( out->version ), "%g", in->version );
Q_strncpy( out->iconpath, in->iconpath, sizeof( out->iconpath ));
Q_strncpy( out->game_url, in->game_url, sizeof( out->game_url ));
Q_strncpy( out->update_url, in->update_url, sizeof( out->update_url ));
out->size = in->size;
Q_strncpy( out->type, in->type, sizeof( out->type ));
Q_strncpy( out->date, in->date, sizeof( out->date ));
out->gamemode = in->gamemode;
if( in->nomodels )
SetBits( out->flags, GFL_NOMODELS );
2018-10-27 22:31:55 +02:00
if( in->noskills )
SetBits( out->flags, GFL_NOSKILLS );
if( in->render_picbutton_text )
SetBits( out->flags, GFL_RENDER_PICBUTTON_TEXT );
if( in->hd_background )
SetBits( out->flags, GFL_HD_BACKGROUND );
if( in->animated_title )
SetBits( out->flags, GFL_ANIMATED_TITLE );
}
static void UI_ToOldGameInfo( GAMEINFO *out, const gameinfo2_t *in )
{
Q_strncpy( out->gamefolder, in->gamefolder, sizeof( out->gamefolder ));
Q_strncpy( out->startmap, in->startmap, sizeof( out->startmap ));
Q_strncpy( out->trainmap, in->trainmap, sizeof( out->trainmap ));
Q_strncpy( out->title, in->title, sizeof( out->title ));
Q_strncpy( out->version, in->version, sizeof( out->version ));
out->flags = in->flags & 0xFFFF;
Q_strncpy( out->game_url, in->game_url, sizeof( out->game_url ));
Q_strncpy( out->update_url, in->update_url, sizeof( out->update_url ));
Q_strncpy( out->size, Q_memprint( in->size ), sizeof( out->size ));
Q_strncpy( out->type, in->type, sizeof( out->type ));
Q_strncpy( out->date, in->date, sizeof( out->date ));
out->gamemode = in->gamemode;
}
static void UI_GetModsInfo( void )
{
int i;
gameui.modsInfo = Mem_Calloc( gameui.mempool, sizeof( *gameui.modsInfo ) * FI->numgames );
for( i = 0; i < FI->numgames; i++ )
UI_ConvertGameInfo( &gameui.modsInfo[i], FI->games[i] );
}
/*
====================
PIC_DrawGeneric
draw hudsprite routine
====================
*/
static void PIC_DrawGeneric( float x, float y, float width, float height, const wrect_t *prc )
{
float s1, s2, t1, t2;
int w, h;
// assume we get sizes from image
R_GetTextureParms( &w, &h, gameui.ds.gl_texturenum );
if( prc )
{
// calc user-defined rectangle
s1 = prc->left / (float)w;
t1 = prc->top / (float)h;
s2 = prc->right / (float)w;
t2 = prc->bottom / (float)h;
if( width == -1 && height == -1 )
{
width = prc->right - prc->left;
height = prc->bottom - prc->top;
}
}
else
{
s1 = t1 = 0.0f;
s2 = t2 = 1.0f;
}
if( width == -1 && height == -1 )
{
width = w;
height = h;
}
// pass scissor test if supposed
if( !CL_Scissor( &gameui.ds.scissor, &x, &y, &width, &height, &s1, &t1, &s2, &t2 ))
return;
ref.dllFuncs.R_DrawStretchPic( x, y, width, height, s1, t1, s2, t2, gameui.ds.gl_texturenum );
ref.dllFuncs.Color4ub( 255, 255, 255, 255 );
}
/*
===============================================================================
MainUI Builtin Functions
===============================================================================
*/
/*
=========
pfnPIC_Load
=========
*/
2020-01-19 02:15:54 +01:00
static HIMAGE GAME_EXPORT pfnPIC_Load( const char *szPicName, const byte *image_buf, int image_size, int flags )
{
HIMAGE tx;
2019-05-19 14:01:23 +02:00
if( !COM_CheckString( szPicName ))
{
Con_Reportf( S_ERROR "%s: refusing to load image with empty name\n", __func__ );
return 0;
}
// add default parms to image
SetBits( flags, TF_IMAGE );
Image_SetForceFlags( IL_LOAD_DECAL ); // allow decal images for menu
tx = ref.dllFuncs.GL_LoadTexture( szPicName, image_buf, image_size, flags );
Image_ClearForceFlags();
return tx;
}
/*
=========
pfnPIC_Width
=========
*/
2020-01-19 02:15:54 +01:00
static int GAME_EXPORT pfnPIC_Width( HIMAGE hPic )
{
int picWidth;
R_GetTextureParms( &picWidth, NULL, hPic );
return picWidth;
}
/*
=========
pfnPIC_Height
=========
*/
2020-01-19 02:15:54 +01:00
static int GAME_EXPORT pfnPIC_Height( HIMAGE hPic )
{
int picHeight;
R_GetTextureParms( NULL, &picHeight, hPic );
return picHeight;
}
/*
=========
pfnPIC_Set
=========
*/
static void GAME_EXPORT pfnPIC_Set( HIMAGE hPic, int r, int g, int b, int a )
{
gameui.ds.gl_texturenum = hPic;
r = bound( 0, r, 255 );
g = bound( 0, g, 255 );
b = bound( 0, b, 255 );
a = bound( 0, a, 255 );
ref.dllFuncs.Color4ub( r, g, b, a );
}
/*
=========
pfnPIC_Draw
=========
*/
static void GAME_EXPORT pfnPIC_Draw( int x, int y, int width, int height, const wrect_t *prc )
{
ref.dllFuncs.GL_SetRenderMode( kRenderNormal );
PIC_DrawGeneric( x, y, width, height, prc );
}
/*
=========
pfnPIC_DrawTrans
=========
*/
static void GAME_EXPORT pfnPIC_DrawTrans( int x, int y, int width, int height, const wrect_t *prc )
{
ref.dllFuncs.GL_SetRenderMode( kRenderTransTexture );
PIC_DrawGeneric( x, y, width, height, prc );
}
/*
=========
pfnPIC_DrawHoles
=========
*/
static void GAME_EXPORT pfnPIC_DrawHoles( int x, int y, int width, int height, const wrect_t *prc )
{
ref.dllFuncs.GL_SetRenderMode( kRenderTransAlpha );
PIC_DrawGeneric( x, y, width, height, prc );
}
/*
=========
pfnPIC_DrawAdditive
=========
*/
static void GAME_EXPORT pfnPIC_DrawAdditive( int x, int y, int width, int height, const wrect_t *prc )
{
ref.dllFuncs.GL_SetRenderMode( kRenderTransAdd );
PIC_DrawGeneric( x, y, width, height, prc );
}
/*
=========
pfnPIC_EnableScissor
=========
*/
2020-01-19 02:15:54 +01:00
static void GAME_EXPORT pfnPIC_EnableScissor( int x, int y, int width, int height )
{
// check bounds
x = bound( 0, x, gameui.globals->scrWidth );
y = bound( 0, y, gameui.globals->scrHeight );
width = bound( 0, width, gameui.globals->scrWidth - x );
height = bound( 0, height, gameui.globals->scrHeight - y );
CL_EnableScissor( &gameui.ds.scissor, x, y, width, height );
}
/*
=========
pfnPIC_DisableScissor
=========
*/
2020-01-19 02:15:54 +01:00
static void GAME_EXPORT pfnPIC_DisableScissor( void )
{
CL_DisableScissor( &gameui.ds.scissor );
}
/*
=============
pfnFillRGBA
=============
*/
2020-01-19 02:15:54 +01:00
static void GAME_EXPORT pfnFillRGBA( int x, int y, int width, int height, int r, int g, int b, int a )
{
r = bound( 0, r, 255 );
g = bound( 0, g, 255 );
b = bound( 0, b, 255 );
a = bound( 0, a, 255 );
ref.dllFuncs.FillRGBA( kRenderTransTexture, x, y, width, height, r, g, b, a );
}
/*
=============
pfnCvar_RegisterVariable
=============
*/
static cvar_t *GAME_EXPORT pfnCvar_RegisterGameUIVariable( const char *szName, const char *szValue, int flags )
{
return (cvar_t *)Cvar_Get( szName, szValue, flags|FCVAR_GAMEUIDLL, Cvar_BuildAutoDescription( szName, flags|FCVAR_GAMEUIDLL ));
}
/*
=============
pfnClientCmd
=============
*/
2020-01-19 02:15:54 +01:00
static void GAME_EXPORT pfnClientCmd( int exec_now, const char *szCmdString )
{
if( !szCmdString || !szCmdString[0] )
return;
Cbuf_AddText( szCmdString );
Cbuf_AddText( "\n" );
// client command executes immediately
if( exec_now ) Cbuf_Execute();
}
/*
=============
pfnPlaySound
=============
*/
2020-01-19 02:15:54 +01:00
static void GAME_EXPORT pfnPlaySound( const char *szSound )
{
if( !COM_CheckString( szSound )) return;
S_StartLocalSound( szSound, VOL_NORM, false );
}
/*
=============
pfnDrawCharacter
quakefont draw character
=============
*/
2020-01-19 02:15:54 +01:00
static void GAME_EXPORT pfnDrawCharacter( int ix, int iy, int iwidth, int iheight, int ch, int ulRGBA, HIMAGE hFont )
{
rgba_t color;
float row, col, size;
float s1, t1, s2, t2;
float x = ix, y = iy;
float width = iwidth;
float height = iheight;
ch &= 255;
if( ch == ' ' ) return;
if( y < -height ) return;
color[3] = (ulRGBA & 0xFF000000) >> 24;
color[0] = (ulRGBA & 0xFF0000) >> 16;
color[1] = (ulRGBA & 0xFF00) >> 8;
color[2] = (ulRGBA & 0xFF) >> 0;
ref.dllFuncs.Color4ub( color[0], color[1], color[2], color[3] );
col = (ch & 15) * 0.0625f + (0.5f / 256.0f);
row = (ch >> 4) * 0.0625f + (0.5f / 256.0f);
size = 0.0625f - (1.0f / 256.0f);
s1 = col;
t1 = row;
s2 = s1 + size;
t2 = t1 + size;
// pass scissor test if supposed
if( !CL_Scissor( &gameui.ds.scissor, &x, &y, &width, &height, &s1, &t1, &s2, &t2 ))
return;
ref.dllFuncs.GL_SetRenderMode( kRenderTransTexture );
ref.dllFuncs.R_DrawStretchPic( x, y, width, height, s1, t1, s2, t2, hFont );
ref.dllFuncs.Color4ub( 255, 255, 255, 255 );
}
/*
=============
UI_DrawConsoleString
drawing string like a console string
=============
*/
2020-01-19 02:15:54 +01:00
static int GAME_EXPORT UI_DrawConsoleString( int x, int y, const char *string )
{
int drawLen;
if( !string || !*string ) return 0; // silent ignore
drawLen = Con_DrawString( x, y, string, gameui.ds.textColor );
MakeRGBA( gameui.ds.textColor, 255, 255, 255, 255 );
return (x + drawLen); // exclude color prexfixes
}
/*
=============
pfnDrawSetTextColor
set color for anything
=============
*/
2020-01-19 02:15:54 +01:00
static void GAME_EXPORT UI_DrawSetTextColor( int r, int g, int b, int alpha )
{
// bound color and convert to byte
gameui.ds.textColor[0] = r;
gameui.ds.textColor[1] = g;
gameui.ds.textColor[2] = b;
gameui.ds.textColor[3] = alpha;
}
/*
====================
pfnGetPlayerModel
for drawing playermodel previews
====================
*/
2020-01-19 02:15:54 +01:00
static cl_entity_t* GAME_EXPORT pfnGetPlayerModel( void )
{
return &gameui.playermodel;
}
/*
====================
pfnSetPlayerModel
for drawing playermodel previews
====================
*/
2020-01-19 02:15:54 +01:00
static void GAME_EXPORT pfnSetPlayerModel( cl_entity_t *ent, const char *path )
{
ent->model = Mod_ForName( path, false, false );
ent->curstate.modelindex = MAX_MODELS; // unreachable index
}
/*
====================
pfnClearScene
for drawing playermodel previews
====================
*/
2020-01-19 02:15:54 +01:00
static void GAME_EXPORT pfnClearScene( void )
{
ref.dllFuncs.R_PushScene();
ref.dllFuncs.R_ClearScene();
}
/*
====================
pfnRenderScene
for drawing playermodel previews
====================
*/
2020-01-19 02:15:54 +01:00
static void GAME_EXPORT pfnRenderScene( const ref_viewpass_t *rvp )
{
2018-11-16 13:09:40 +01:00
ref_viewpass_t copy;
// to avoid division by zero
if( !rvp || rvp->fov_x <= 0.0f || rvp->fov_y <= 0.0f )
return;
2018-11-16 13:09:40 +01:00
copy = *rvp;
// don't allow special modes from menu
2018-11-16 13:09:40 +01:00
copy.flags = 0;
ref.dllFuncs.R_Set2DMode( false );
GL_RenderFrame( &copy );
ref.dllFuncs.R_Set2DMode( true );
ref.dllFuncs.R_PopScene();
}
/*
====================
pfnAddEntity
adding player model into visible list
====================
*/
2020-01-19 02:15:54 +01:00
static int GAME_EXPORT pfnAddEntity( int entityType, cl_entity_t *ent )
{
if( !ref.dllFuncs.R_AddEntity( ent, entityType ))
return false;
return true;
}
/*
====================
pfnClientJoin
send client connect
====================
*/
2020-01-19 02:15:54 +01:00
static void GAME_EXPORT pfnClientJoin( const netadr_t adr )
{
Cbuf_AddTextf( "connect %s\n", NET_AdrToString( adr ));
}
/*
====================
pfnKeyGetOverstrikeMode
get global key overstrike state
====================
*/
2020-01-19 02:15:54 +01:00
static int GAME_EXPORT pfnKeyGetOverstrikeMode( void )
{
return host.key_overstrike;
}
/*
====================
pfnKeySetOverstrikeMode
set global key overstrike mode
====================
*/
2020-01-19 02:15:54 +01:00
static void GAME_EXPORT pfnKeySetOverstrikeMode( int fActive )
{
host.key_overstrike = fActive;
}
/*
====================
pfnKeyGetState
returns kbutton struct if found
====================
*/
static void *pfnKeyGetState( const char *name )
{
if( clgame.dllFuncs.KB_Find )
return clgame.dllFuncs.KB_Find( name );
return NULL;
}
/*
=========
pfnMemAlloc
=========
*/
static void *pfnMemAlloc( size_t cb, const char *filename, const int fileline )
{
2018-06-09 00:28:35 +02:00
return _Mem_Alloc( gameui.mempool, cb, true, filename, fileline );
}
/*
=========
pfnMemFree
=========
*/
2020-01-19 02:15:54 +01:00
static void GAME_EXPORT pfnMemFree( void *mem, const char *filename, const int fileline )
{
_Mem_Free( mem, filename, fileline );
}
/*
=========
pfnGetGameInfo
=========
*/
static int GAME_EXPORT pfnGetOldGameInfo( GAMEINFO *pgameinfo )
{
if( !pgameinfo )
return 0;
UI_ToOldGameInfo( pgameinfo, &gameui.gameInfo );
return 1;
}
/*
=========
pfnGetGamesList
=========
*/
2020-01-19 02:15:54 +01:00
static GAMEINFO ** GAME_EXPORT pfnGetGamesList( int *numGames )
{
if( numGames )
*numGames = FI->numgames;
if( !gameui.oldModsInfo )
{
int i;
if( !gameui.modsInfo )
UI_GetModsInfo();
// first allocate array of pointers
gameui.oldModsInfo = Mem_Calloc( gameui.mempool, sizeof( *gameui.oldModsInfo ) * FI->numgames );
for( i = 0; i < FI->numgames; i++ )
{
gameui.oldModsInfo[i] = Mem_Calloc( gameui.mempool, sizeof( *gameui.oldModsInfo[i] ));
UI_ToOldGameInfo( gameui.oldModsInfo[i], &gameui.modsInfo[i] );
}
}
return gameui.oldModsInfo;
}
/*
=========
pfnGetFilesList
release prev search on a next call
=========
*/
2020-01-19 02:15:54 +01:00
static char ** GAME_EXPORT pfnGetFilesList( const char *pattern, int *numFiles, int gamedironly )
{
static search_t *t = NULL;
if( t ) Mem_Free( t ); // release prev search
t = FS_Search( pattern, true, gamedironly );
if( !t )
{
if( numFiles ) *numFiles = 0;
return NULL;
}
if( numFiles ) *numFiles = t->numfilenames;
return t->filenames;
}
/*
=========
pfnGetClipboardData
pointer must be released in call place
=========
*/
static char *pfnGetClipboardData( void )
{
return Sys_GetClipboardData();
}
/*
=========
pfnCheckGameDll
=========
*/
2024-01-27 17:48:17 +01:00
static int GAME_EXPORT pfnCheckGameDll( void )
{
#ifdef XASH_INTERNAL_GAMELIBS
2018-04-20 23:36:14 +02:00
return true;
#else
string dllpath;
2018-04-20 23:36:14 +02:00
if( svgame.hInstance )
return true;
COM_GetCommonLibraryPath( LIBRARY_SERVER, dllpath, sizeof( dllpath ));
if( FS_FileExists( dllpath, false ))
return true;
return false;
#endif
}
/*
=========
pfnChangeInstance
=========
*/
2020-01-19 02:15:54 +01:00
static void GAME_EXPORT pfnChangeInstance( const char *newInstance, const char *szFinalMessage )
{
Con_Reportf( S_ERROR "%s menu call is deprecated!\n", __func__ );
}
/*
=========
pfnHostEndGame
=========
*/
2020-01-19 02:15:54 +01:00
static void GAME_EXPORT pfnHostEndGame( const char *szFinalMessage )
{
if( !szFinalMessage ) szFinalMessage = "";
2019-05-25 01:44:24 +02:00
Host_EndGame( false, "%s", szFinalMessage );
}
/*
=========
pfnStartBackgroundTrack
=========
*/
2020-01-19 02:15:54 +01:00
static void GAME_EXPORT pfnStartBackgroundTrack( const char *introTrack, const char *mainTrack )
{
S_StartBackgroundTrack( introTrack, mainTrack, 0, false );
}
2020-01-19 02:15:54 +01:00
static void GAME_EXPORT GL_ProcessTexture( int texnum, float gamma, int topColor, int bottomColor )
{
ref.dllFuncs.GL_ProcessTexture( texnum, gamma, topColor, bottomColor );
}
/*
=================
UI_ShellExecute
=================
*/
2020-01-19 02:15:54 +01:00
static void GAME_EXPORT UI_ShellExecute( const char *path, const char *parms, int shouldExit )
{
Platform_ShellExecute( path, parms );
if( shouldExit )
Sys_Quit();
}
/*
==============
pfnParseFile
legacy wrapper
==============
*/
static char *pfnParseFile( char *buf, char *token )
{
2021-10-01 19:12:31 +02:00
return COM_ParseFile( buf, token, INT_MAX );
}
/*
=============
pfnFileExists
legacy wrapper
=============
*/
static int pfnFileExists( const char *path, int gamedironly )
{
return FS_FileExists( path, gamedironly );
}
/*
=============
pfnDelete
legacy wrapper
=============
*/
static int pfnDelete( const char *path )
{
return FS_Delete( path );
}
static void GAME_EXPORT pfnCon_DefaultColor( int r, int g, int b )
{
Con_DefaultColor( r, g, b, true );
}
static void GAME_EXPORT pfnSetCursor( void *hCursor )
{
uintptr_t cursor;
if( !gameui.use_extended_api )
return; // ignore original Xash menus
cursor = (uintptr_t)hCursor;
if( cursor < dc_user || cursor > dc_last )
return;
Platform_SetCursorType( cursor );
}
// engine callbacks
static const ui_enginefuncs_t gEngfuncs =
{
pfnPIC_Load,
GL_FreeImage,
pfnPIC_Width,
pfnPIC_Height,
pfnPIC_Set,
pfnPIC_Draw,
pfnPIC_DrawHoles,
pfnPIC_DrawTrans,
pfnPIC_DrawAdditive,
pfnPIC_EnableScissor,
pfnPIC_DisableScissor,
pfnFillRGBA,
pfnCvar_RegisterGameUIVariable,
Cvar_VariableValue,
Cvar_VariableString,
Cvar_Set,
Cvar_SetValue,
Cmd_AddGameUICommand,
pfnClientCmd,
Cmd_RemoveCommand,
Cmd_Argc,
Cmd_Argv,
Cmd_Args,
Con_Printf,
Con_DPrintf,
UI_NPrintf,
UI_NXPrintf,
pfnPlaySound,
UI_DrawLogo,
UI_GetLogoWidth,
UI_GetLogoHeight,
UI_GetLogoLength,
pfnDrawCharacter,
UI_DrawConsoleString,
UI_DrawSetTextColor,
Con_DrawStringLen,
pfnCon_DefaultColor,
pfnGetPlayerModel,
pfnSetPlayerModel,
pfnClearScene,
pfnRenderScene,
pfnAddEntity,
Host_Error,
pfnFileExists,
pfnGetGameDir,
Cmd_CheckMapsList,
CL_Active,
pfnClientJoin,
COM_LoadFileForMe,
pfnParseFile,
COM_FreeFile,
Key_ClearStates,
Key_SetKeyDest,
Key_KeynumToString,
Key_GetBinding,
Key_SetBinding,
Key_IsDown,
pfnKeyGetOverstrikeMode,
pfnKeySetOverstrikeMode,
pfnKeyGetState,
pfnMemAlloc,
pfnMemFree,
pfnGetOldGameInfo,
pfnGetGamesList,
pfnGetFilesList,
SV_GetSaveComment,
CL_GetDemoComment,
pfnCheckGameDll,
pfnGetClipboardData,
UI_ShellExecute,
Host_WriteServerConfig,
pfnChangeInstance,
pfnStartBackgroundTrack,
pfnHostEndGame,
COM_RandomFloat,
COM_RandomLong,
pfnSetCursor,
pfnIsMapValid,
GL_ProcessTexture,
pfnCompareFileTime,
VID_GetModeString,
2018-04-24 04:54:57 +02:00
(void*)COM_SaveFile,
pfnDelete
};
2018-04-17 02:53:15 +02:00
static void pfnEnableTextInput( int enable )
{
Key_EnableTextInput( enable, false );
}
static int pfnGetRenderers( unsigned int num, char *shortName, size_t size1, char *readableName, size_t size2 )
{
if( num >= ref.numRenderers )
return 0;
if( shortName && size1 )
Q_strncpy( shortName, ref.shortNames[num], size1 );
if( readableName && size2 )
Q_strncpy( readableName, ref.readableNames[num], size2 );
return 1;
}
static char *pfnParseFileSafe( char *data, char *buf, const int size, unsigned int flags, int *len )
{
return COM_ParseFileSafe( data, buf, size, flags, len, NULL );
}
static gameinfo2_t *pfnGetGameInfo( int gi_version )
{
if( gi_version != gameui.gameInfo.gi_version )
return NULL;
return &gameui.gameInfo;
}
static gameinfo2_t *pfnGetModInfo( int gi_version, int i )
{
if( i < 0 || i >= FI->numgames )
return NULL;
if( !gameui.modsInfo )
UI_GetModsInfo();
if( gi_version != gameui.modsInfo[i].gi_version )
return NULL;
return &gameui.modsInfo[i];
}
static int pfnIsCvarReadOnly( const char *name )
{
convar_t *cv = Cvar_FindVar( name );
if( !cv )
return -1;
return FBitSet( cv->flags, FCVAR_READ_ONLY ) ? 1 : 0;
}
static ui_extendedfuncs_t gExtendedfuncs =
2018-04-17 02:53:15 +02:00
{
pfnEnableTextInput,
Con_UtfProcessChar,
Con_UtfMoveLeft,
Con_UtfMoveRight,
2020-03-04 05:23:38 +01:00
pfnGetRenderers,
Sys_DoubleTime,
pfnParseFileSafe,
NET_AdrToString,
NET_CompareAdrSort,
Sys_GetNativeObject,
&gNetApi,
pfnGetGameInfo,
pfnGetModInfo,
pfnIsCvarReadOnly,
2018-04-17 02:53:15 +02:00
};
void UI_UnloadProgs( void )
{
if( !gameui.hInstance ) return;
// deinitialize game
gameui.dllFuncs.pfnShutdown();
Cmd_RemoveCommand( "ui_allowconsole" );
Cvar_FullSet( "host_gameuiloaded", "0", FCVAR_READ_ONLY );
Cvar_Unlink( FCVAR_GAMEUIDLL );
Cmd_Unlink( CMD_GAMEUIDLL );
COM_FreeLibrary( gameui.hInstance );
Mem_FreePool( &gameui.mempool );
memset( &gameui, 0, sizeof( gameui ));
}
qboolean UI_LoadProgs( void )
{
static ui_enginefuncs_t gpEngfuncs;
static ui_extendedfuncs_t gpExtendedfuncs;
static ui_globalvars_t gpGlobals;
UIEXTENEDEDAPI GetExtAPI;
UITEXTAPI GiveTextApi;
MENUAPI GetMenuAPI;
string dllpath;
int i;
if( gameui.hInstance ) UI_UnloadProgs();
// setup globals
gameui.globals = &gpGlobals;
COM_GetCommonLibraryPath( LIBRARY_GAMEUI, dllpath, sizeof( dllpath ));
if(!( gameui.hInstance = COM_LoadLibrary( dllpath, false, false )))
{
string path = OS_LIB_PREFIX "menu." OS_LIB_EXT;
2018-04-17 02:53:15 +02:00
FS_AllowDirectPaths( true );
// no use to load it from engine directory, as library loader
// that implements internal gamelibs already knows how to load it
#ifndef XASH_INTERNAL_GAMELIBS
if(!( gameui.hInstance = COM_LoadLibrary( path, false, true )))
#endif
2018-04-17 02:53:15 +02:00
{
FS_AllowDirectPaths( false );
return false;
2018-04-17 02:53:15 +02:00
}
}
2018-04-17 02:53:15 +02:00
FS_AllowDirectPaths( false );
if(( GetMenuAPI = (MENUAPI)COM_GetProcAddress( gameui.hInstance, "GetMenuAPI" )) == NULL )
{
COM_FreeLibrary( gameui.hInstance );
Con_Reportf( "%s: can't init menu API\n", __func__ );
gameui.hInstance = NULL;
return false;
}
2018-04-17 02:53:15 +02:00
gameui.use_extended_api = false;
2018-04-17 02:53:15 +02:00
2018-10-06 02:28:40 +02:00
// make local copy of engfuncs to prevent overwrite it with user dll
gpEngfuncs = gEngfuncs;
2018-10-06 02:28:40 +02:00
gameui.mempool = Mem_AllocPool( "Menu Pool" );
if( !GetMenuAPI( &gameui.dllFuncs, &gpEngfuncs, gameui.globals ))
{
COM_FreeLibrary( gameui.hInstance );
Con_Reportf( "%s: can't init menu API\n", __func__ );
2018-10-06 02:28:40 +02:00
Mem_FreePool( &gameui.mempool );
gameui.hInstance = NULL;
return false;
}
// make local copy of engfuncs to prevent overwrite it with user dll
gpExtendedfuncs = gExtendedfuncs;
memset( &gameui.dllFuncs2, 0, sizeof( gameui.dllFuncs2 ));
// try to initialize new extended API
if( ( GetExtAPI = (UIEXTENEDEDAPI)COM_GetProcAddress( gameui.hInstance, "GetExtAPI" ) ) )
2018-04-17 02:53:15 +02:00
{
Con_Reportf( "%s: extended Menu API found\n", __func__ );
if( GetExtAPI( MENU_EXTENDED_API_VERSION, &gameui.dllFuncs2, &gpExtendedfuncs ) )
{
Con_Reportf( "%s: extended Menu API initialized\n", __func__ );
gameui.use_extended_api = true;
}
2018-04-17 02:53:15 +02:00
}
else // otherwise, fallback to old and deprecated extensions
2018-04-17 02:53:15 +02:00
{
if( ( GiveTextApi = (UITEXTAPI)COM_GetProcAddress( gameui.hInstance, "GiveTextAPI" ) ) )
{
Con_Reportf( "%s: extended text API found\n", __func__ );
Con_Reportf( S_WARN "Text API is deprecated! If you are mod developer, consider moving to Extended Menu API!\n" );
if( GiveTextApi( &gpExtendedfuncs ) ) // they are binary compatible, so we can just pass extended funcs API to menu
{
Con_Reportf( "%s: extended text API initialized\n", __func__ );
gameui.use_extended_api = true;
}
}
gameui.dllFuncs2.pfnAddTouchButtonToList = (ADDTOUCHBUTTONTOLIST)COM_GetProcAddress( gameui.hInstance, "AddTouchButtonToList" );
if( gameui.dllFuncs2.pfnAddTouchButtonToList )
{
Con_Reportf( "%s: AddTouchButtonToList call found\n", __func__ );
Con_Reportf( S_WARN "AddTouchButtonToList is deprecated! If you are mod developer, consider moving to Extended Menu API!\n" );
}
2018-04-17 02:53:15 +02:00
}
Cvar_FullSet( "host_gameuiloaded", "1", FCVAR_READ_ONLY );
Cmd_AddRestrictedCommand( "ui_allowconsole", UI_ToggleAllowConsole_f, "unlocks developer console" );
UI_ConvertGameInfo( &gameui.gameInfo, FI->GameInfo ); // current gameinfo
// setup globals
gameui.globals->developer = host.allow_console;
// initialize game
gameui.dllFuncs.pfnInit();
return true;
2018-04-17 02:53:15 +02:00
}