You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1138 lines
23 KiB
1138 lines
23 KiB
/* |
|
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 "gl_local.h" |
|
#include "library.h" |
|
#include "input.h" |
|
#include "server.h" // !!svgame.hInstance |
|
|
|
static MENUAPI GetMenuAPI; |
|
static ADDTOUCHBUTTONTOLIST pfnAddTouchButtonToList; |
|
static void UI_UpdateUserinfo( void ); |
|
|
|
gameui_static_t gameui; |
|
|
|
void UI_UpdateMenu( float realtime ) |
|
{ |
|
if( !gameui.hInstance ) 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(); |
|
} |
|
|
|
static void 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" ); |
|
fullpath = FS_GetDiskPath( path, false ); |
|
|
|
if( FS_FileExists( path, false ) && !fullpath ) |
|
{ |
|
MsgDev( D_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; |
|
} |
|
|
|
R_DrawStretchRaw( x, y, width, height, gameui.logo_xres, gameui.logo_yres, cin_data, redraw ); |
|
} |
|
|
|
static int UI_GetLogoWidth( void ) |
|
{ |
|
return gameui.logo_xres; |
|
} |
|
|
|
static int UI_GetLogoHeight( void ) |
|
{ |
|
return gameui.logo_yres; |
|
} |
|
|
|
static float 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( GAMEINFO *out, gameinfo_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, va( "%g", in->version ), sizeof( out->version )); |
|
|
|
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_pretifymem( in->size, 0 ), 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; |
|
|
|
if( in->nomodels ) |
|
out->flags |= GFL_NOMODELS; |
|
} |
|
|
|
static qboolean PIC_Scissor( float *x, float *y, float *width, float *height, float *u0, float *v0, float *u1, float *v1 ) |
|
{ |
|
float dudx, dvdy; |
|
|
|
// clip sub rect to sprite |
|
if(( width == 0 ) || ( height == 0 )) |
|
return false; |
|
|
|
if( *x + *width <= gameui.ds.scissor_x ) |
|
return false; |
|
if( *x >= gameui.ds.scissor_x + gameui.ds.scissor_width ) |
|
return false; |
|
if( *y + *height <= gameui.ds.scissor_y ) |
|
return false; |
|
if( *y >= gameui.ds.scissor_y + gameui.ds.scissor_height ) |
|
return false; |
|
|
|
dudx = (*u1 - *u0) / *width; |
|
dvdy = (*v1 - *v0) / *height; |
|
|
|
if( *x < gameui.ds.scissor_x ) |
|
{ |
|
*u0 += (gameui.ds.scissor_x - *x) * dudx; |
|
*width -= gameui.ds.scissor_x - *x; |
|
*x = gameui.ds.scissor_x; |
|
} |
|
|
|
if( *x + *width > gameui.ds.scissor_x + gameui.ds.scissor_width ) |
|
{ |
|
*u1 -= (*x + *width - (gameui.ds.scissor_x + gameui.ds.scissor_width)) * dudx; |
|
*width = gameui.ds.scissor_x + gameui.ds.scissor_width - *x; |
|
} |
|
|
|
if( *y < gameui.ds.scissor_y ) |
|
{ |
|
*v0 += (gameui.ds.scissor_y - *y) * dvdy; |
|
*height -= gameui.ds.scissor_y - *y; |
|
*y = gameui.ds.scissor_y; |
|
} |
|
|
|
if( *y + *height > gameui.ds.scissor_y + gameui.ds.scissor_height ) |
|
{ |
|
*v1 -= (*y + *height - (gameui.ds.scissor_y + gameui.ds.scissor_height)) * dvdy; |
|
*height = gameui.ds.scissor_y + gameui.ds.scissor_height - *y; |
|
} |
|
return true; |
|
} |
|
|
|
/* |
|
==================== |
|
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 = (float)prc->left / (float)w; |
|
t1 = (float)prc->top / (float)h; |
|
s2 = (float)prc->right / (float)w; |
|
t2 = (float)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( gameui.ds.scissor_test && !PIC_Scissor( &x, &y, &width, &height, &s1, &t1, &s2, &t2 )) |
|
return; |
|
|
|
PicAdjustSize( &x, &y, &width, &height ); |
|
R_DrawStretchPic( x, y, width, height, s1, t1, s2, t2, gameui.ds.gl_texturenum ); |
|
pglColor4ub( 255, 255, 255, 255 ); |
|
} |
|
|
|
/* |
|
=============================================================================== |
|
MainUI Builtin Functions |
|
|
|
=============================================================================== |
|
*/ |
|
/* |
|
========= |
|
pfnPIC_Load |
|
|
|
========= |
|
*/ |
|
static HIMAGE pfnPIC_Load( const char *szPicName, const byte *image_buf, long image_size, long flags ) |
|
{ |
|
HIMAGE tx; |
|
|
|
if( !szPicName || !*szPicName ) |
|
{ |
|
MsgDev( D_ERROR, "CL_LoadImage: bad name!\n" ); |
|
return 0; |
|
} |
|
|
|
// add default parms to image |
|
SetBits( flags, TF_IMAGE ); |
|
|
|
Image_SetForceFlags( IL_LOAD_DECAL ); // allow decal images for menu |
|
tx = GL_LoadTexture( szPicName, image_buf, image_size, flags, NULL ); |
|
Image_ClearForceFlags(); |
|
|
|
return tx; |
|
} |
|
|
|
/* |
|
========= |
|
pfnPIC_Width |
|
|
|
========= |
|
*/ |
|
static int pfnPIC_Width( HIMAGE hPic ) |
|
{ |
|
int picWidth; |
|
|
|
R_GetTextureParms( &picWidth, NULL, hPic ); |
|
|
|
return picWidth; |
|
} |
|
|
|
/* |
|
========= |
|
pfnPIC_Height |
|
|
|
========= |
|
*/ |
|
static int pfnPIC_Height( HIMAGE hPic ) |
|
{ |
|
int picHeight; |
|
|
|
R_GetTextureParms( NULL, &picHeight, hPic ); |
|
|
|
return picHeight; |
|
} |
|
|
|
/* |
|
========= |
|
pfnPIC_Set |
|
|
|
========= |
|
*/ |
|
void 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 ); |
|
pglColor4ub( r, g, b, a ); |
|
} |
|
|
|
/* |
|
========= |
|
pfnPIC_Draw |
|
|
|
========= |
|
*/ |
|
void pfnPIC_Draw( int x, int y, int width, int height, const wrect_t *prc ) |
|
{ |
|
GL_SetRenderMode( kRenderNormal ); |
|
PIC_DrawGeneric( x, y, width, height, prc ); |
|
} |
|
|
|
/* |
|
========= |
|
pfnPIC_DrawTrans |
|
|
|
========= |
|
*/ |
|
void pfnPIC_DrawTrans( int x, int y, int width, int height, const wrect_t *prc ) |
|
{ |
|
GL_SetRenderMode( kRenderTransTexture ); |
|
PIC_DrawGeneric( x, y, width, height, prc ); |
|
} |
|
|
|
/* |
|
========= |
|
pfnPIC_DrawHoles |
|
|
|
========= |
|
*/ |
|
void pfnPIC_DrawHoles( int x, int y, int width, int height, const wrect_t *prc ) |
|
{ |
|
GL_SetRenderMode( kRenderTransAlpha ); |
|
PIC_DrawGeneric( x, y, width, height, prc ); |
|
} |
|
|
|
/* |
|
========= |
|
pfnPIC_DrawAdditive |
|
|
|
========= |
|
*/ |
|
void pfnPIC_DrawAdditive( int x, int y, int width, int height, const wrect_t *prc ) |
|
{ |
|
GL_SetRenderMode( kRenderTransAdd ); |
|
PIC_DrawGeneric( x, y, width, height, prc ); |
|
} |
|
|
|
/* |
|
======================= |
|
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( pfnAddTouchButtonToList ) |
|
{ |
|
pfnAddTouchButtonToList( name, texture, command, color, flags ); |
|
} |
|
} |
|
|
|
/* |
|
========= |
|
pfnPIC_EnableScissor |
|
|
|
========= |
|
*/ |
|
static void 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 ); |
|
|
|
gameui.ds.scissor_x = x; |
|
gameui.ds.scissor_width = width; |
|
gameui.ds.scissor_y = y; |
|
gameui.ds.scissor_height = height; |
|
gameui.ds.scissor_test = true; |
|
} |
|
|
|
/* |
|
========= |
|
pfnPIC_DisableScissor |
|
|
|
========= |
|
*/ |
|
static void pfnPIC_DisableScissor( void ) |
|
{ |
|
gameui.ds.scissor_x = 0; |
|
gameui.ds.scissor_width = 0; |
|
gameui.ds.scissor_y = 0; |
|
gameui.ds.scissor_height = 0; |
|
gameui.ds.scissor_test = false; |
|
} |
|
|
|
/* |
|
============= |
|
pfnFillRGBA |
|
|
|
============= |
|
*/ |
|
static void 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 ); |
|
pglColor4ub( r, g, b, a ); |
|
GL_SetRenderMode( kRenderTransTexture ); |
|
R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, tr.whiteTexture ); |
|
pglColor4ub( 255, 255, 255, 255 ); |
|
} |
|
|
|
/* |
|
============= |
|
pfnClientCmd |
|
|
|
============= |
|
*/ |
|
static void 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 |
|
|
|
============= |
|
*/ |
|
static void pfnPlaySound( const char *szSound ) |
|
{ |
|
if( !COM_CheckString( szSound )) return; |
|
S_StartLocalSound( szSound, VOL_NORM, false ); |
|
} |
|
|
|
/* |
|
============= |
|
pfnDrawCharacter |
|
|
|
quakefont draw character |
|
============= |
|
*/ |
|
static void 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; |
|
pglColor4ubv( color ); |
|
|
|
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( gameui.ds.scissor_test && !PIC_Scissor( &x, &y, &width, &height, &s1, &t1, &s2, &t2 )) |
|
return; |
|
|
|
GL_SetRenderMode( kRenderTransTexture ); |
|
R_DrawStretchPic( x, y, width, height, s1, t1, s2, t2, hFont ); |
|
pglColor4ub( 255, 255, 255, 255 ); |
|
} |
|
|
|
/* |
|
============= |
|
UI_DrawConsoleString |
|
|
|
drawing string like a console string |
|
============= |
|
*/ |
|
static int 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 |
|
============= |
|
*/ |
|
static void 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 |
|
==================== |
|
*/ |
|
static cl_entity_t* pfnGetPlayerModel( void ) |
|
{ |
|
return &gameui.playermodel; |
|
} |
|
|
|
/* |
|
==================== |
|
pfnSetPlayerModel |
|
|
|
for drawing playermodel previews |
|
==================== |
|
*/ |
|
static void 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 |
|
==================== |
|
*/ |
|
static void pfnClearScene( void ) |
|
{ |
|
R_PushScene(); |
|
R_ClearScene(); |
|
} |
|
|
|
/* |
|
==================== |
|
pfnRenderScene |
|
|
|
for drawing playermodel previews |
|
==================== |
|
*/ |
|
static void pfnRenderScene( const ref_viewpass_t *rvp ) |
|
{ |
|
// to avoid division by zero |
|
if( !rvp || rvp->fov_x <= 0.0f || rvp->fov_y <= 0.0f ) |
|
return; |
|
|
|
// don't allow special modes from menu |
|
((ref_viewpass_t *)&rvp)->flags = 0; |
|
|
|
R_Set2DMode( false ); |
|
R_RenderFrame( rvp ); |
|
R_Set2DMode( true ); |
|
R_PopScene(); |
|
} |
|
|
|
/* |
|
==================== |
|
pfnAddEntity |
|
|
|
adding player model into visible list |
|
==================== |
|
*/ |
|
static int pfnAddEntity( int entityType, cl_entity_t *ent ) |
|
{ |
|
if( !R_AddEntity( ent, entityType )) |
|
return false; |
|
return true; |
|
} |
|
|
|
/* |
|
==================== |
|
pfnClientJoin |
|
|
|
send client connect |
|
==================== |
|
*/ |
|
static void pfnClientJoin( const netadr_t adr ) |
|
{ |
|
Cbuf_AddText( va( "connect %s\n", NET_AdrToString( adr ))); |
|
} |
|
|
|
/* |
|
==================== |
|
pfnKeyGetOverstrikeMode |
|
|
|
get global key overstrike state |
|
==================== |
|
*/ |
|
static int pfnKeyGetOverstrikeMode( void ) |
|
{ |
|
return host.key_overstrike; |
|
} |
|
|
|
/* |
|
==================== |
|
pfnKeySetOverstrikeMode |
|
|
|
set global key overstrike mode |
|
==================== |
|
*/ |
|
static void 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 ) |
|
{ |
|
return _Mem_Alloc( gameui.mempool, cb, filename, fileline ); |
|
} |
|
|
|
/* |
|
========= |
|
pfnMemFree |
|
|
|
========= |
|
*/ |
|
static void pfnMemFree( void *mem, const char *filename, const int fileline ) |
|
{ |
|
_Mem_Free( mem, filename, fileline ); |
|
} |
|
|
|
/* |
|
========= |
|
pfnGetGameInfo |
|
|
|
========= |
|
*/ |
|
static int pfnGetGameInfo( GAMEINFO *pgameinfo ) |
|
{ |
|
if( !pgameinfo ) return 0; |
|
|
|
*pgameinfo = gameui.gameInfo; |
|
return 1; |
|
} |
|
|
|
/* |
|
========= |
|
pfnGetGamesList |
|
|
|
========= |
|
*/ |
|
static GAMEINFO **pfnGetGamesList( int *numGames ) |
|
{ |
|
if( numGames ) *numGames = SI.numgames; |
|
return gameui.modsInfo; |
|
} |
|
|
|
/* |
|
========= |
|
pfnGetFilesList |
|
|
|
release prev search on a next call |
|
========= |
|
*/ |
|
static char **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 |
|
|
|
========= |
|
*/ |
|
int pfnCheckGameDll( void ) |
|
{ |
|
void *hInst; |
|
|
|
#if TARGET_OS_IPHONE |
|
// loading server library drains too many ram |
|
// so 512MB iPod Touch cannot even connect to |
|
// to servers in cstrike |
|
return true; |
|
#endif |
|
|
|
if( svgame.hInstance ) |
|
return true; |
|
|
|
COM_ResetLibraryError(); |
|
if(( hInst = COM_LoadLibrary( SI.gamedll, true, false )) != NULL ) |
|
{ |
|
COM_FreeLibrary( hInst ); // don't increase linker's reference counter |
|
return true; |
|
} |
|
MsgDev( D_WARN, "Could not load server library:\n%s", COM_GetLibraryError() ); |
|
COM_ResetLibraryError(); |
|
return false; |
|
} |
|
|
|
/* |
|
========= |
|
pfnChangeInstance |
|
|
|
========= |
|
*/ |
|
static void pfnChangeInstance( const char *newInstance, const char *szFinalMessage ) |
|
{ |
|
if( !szFinalMessage ) szFinalMessage = ""; |
|
if( !newInstance || !*newInstance ) return; |
|
|
|
Host_NewInstance( newInstance, szFinalMessage ); |
|
} |
|
|
|
/* |
|
========= |
|
pfnHostEndGame |
|
|
|
========= |
|
*/ |
|
static void pfnHostEndGame( const char *szFinalMessage ) |
|
{ |
|
if( !szFinalMessage ) szFinalMessage = ""; |
|
Host_EndGame( true, "%s", szFinalMessage ); |
|
} |
|
|
|
/* |
|
========= |
|
pfnStartBackgroundTrack |
|
|
|
========= |
|
*/ |
|
static void pfnStartBackgroundTrack( const char *introTrack, const char *mainTrack ) |
|
{ |
|
S_StartBackgroundTrack( introTrack, mainTrack, 0, false ); |
|
} |
|
|
|
// engine callbacks |
|
static 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, |
|
Con_DefaultColor, |
|
pfnGetPlayerModel, |
|
pfnSetPlayerModel, |
|
pfnClearScene, |
|
pfnRenderScene, |
|
pfnAddEntity, |
|
Host_Error, |
|
FS_FileExists, |
|
pfnGetGameDir, |
|
Cmd_CheckMapsList, |
|
CL_Active, |
|
pfnClientJoin, |
|
COM_LoadFileForMe, |
|
COM_ParseFile, |
|
COM_FreeFile, |
|
Key_ClearStates, |
|
Key_SetKeyDest, |
|
Key_KeynumToString, |
|
Key_GetBinding, |
|
Key_SetBinding, |
|
Key_IsDown, |
|
pfnKeyGetOverstrikeMode, |
|
pfnKeySetOverstrikeMode, |
|
pfnKeyGetState, |
|
pfnMemAlloc, |
|
pfnMemFree, |
|
pfnGetGameInfo, |
|
pfnGetGamesList, |
|
pfnGetFilesList, |
|
SV_GetSaveComment, |
|
CL_GetDemoComment, |
|
pfnCheckGameDll, |
|
pfnGetClipboardData, |
|
Sys_ShellExecute, |
|
Host_WriteServerConfig, |
|
pfnChangeInstance, |
|
pfnStartBackgroundTrack, |
|
pfnHostEndGame, |
|
COM_RandomFloat, |
|
COM_RandomLong, |
|
IN_SetCursor, |
|
pfnIsMapValid, |
|
GL_ProcessTexture, |
|
COM_CompareFileTime, |
|
VID_GetModeString, |
|
}; |
|
|
|
static void pfnEnableTextInput( int enable ) |
|
{ |
|
Key_EnableTextInput( enable, false ); |
|
} |
|
|
|
static ui_textfuncs_t gTextfuncs = |
|
{ |
|
pfnEnableTextInput, |
|
Con_UtfProcessChar, |
|
Con_UtfMoveLeft, |
|
Con_UtfMoveRight |
|
}; |
|
|
|
void UI_UnloadProgs( void ) |
|
{ |
|
if( !gameui.hInstance ) return; |
|
|
|
// deinitialize game |
|
gameui.dllFuncs.pfnShutdown(); |
|
|
|
Cvar_FullSet( "host_gameuiloaded", "0", FCVAR_READ_ONLY ); |
|
|
|
COM_FreeLibrary( gameui.hInstance ); |
|
Mem_FreePool( &gameui.mempool ); |
|
memset( &gameui, 0, sizeof( gameui )); |
|
|
|
Cvar_Unlink( FCVAR_GAMEUIDLL ); |
|
Cmd_Unlink( CMD_GAMEUIDLL ); |
|
} |
|
|
|
qboolean UI_LoadProgs( void ) |
|
{ |
|
static ui_enginefuncs_t gpEngfuncs; |
|
static ui_textfuncs_t gpTextfuncs; |
|
static ui_globalvars_t gpGlobals; |
|
UITEXTAPI GiveTextApi; |
|
int i; |
|
|
|
if( gameui.hInstance ) UI_UnloadProgs(); |
|
|
|
// setup globals |
|
gameui.globals = &gpGlobals; |
|
|
|
#ifdef XASH_INTERNAL_GAMELIBS |
|
if(!( gameui.hInstance = COM_LoadLibrary( "menu", false, false ))) |
|
return false; |
|
#else |
|
if(!( gameui.hInstance = COM_LoadLibrary( va( "%s/" MENUDLL, GI->dll_path ), false, false ))) |
|
{ |
|
FS_AllowDirectPaths( true ); |
|
|
|
if(!( gameui.hInstance = COM_LoadLibrary( "../" MENUDLL, false, false )) |
|
&& !( gameui.hInstance = COM_LoadLibrary( MENUDLL, false, false ))) |
|
|
|
{ |
|
FS_AllowDirectPaths( false ); |
|
return false; |
|
} |
|
} |
|
#endif |
|
FS_AllowDirectPaths( false ); |
|
|
|
if(( GetMenuAPI = (MENUAPI)COM_GetProcAddress( gameui.hInstance, "GetMenuAPI" )) == NULL ) |
|
{ |
|
COM_FreeLibrary( gameui.hInstance ); |
|
MsgDev( D_NOTE, "UI_LoadProgs: can't init menu API\n" ); |
|
gameui.hInstance = NULL; |
|
return false; |
|
} |
|
|
|
|
|
gameui.use_text_api = false; |
|
|
|
if( ( GiveTextApi = (UITEXTAPI)COM_GetProcAddress( gameui.hInstance, "GiveTextAPI" ) ) ) |
|
{ |
|
MsgDev( D_NOTE, "UI_LoadProgs: extended Text API initialized\n" ); |
|
// make local copy of engfuncs to prevent overwrite it with user dll |
|
memcpy( &gpTextfuncs, &gTextfuncs, sizeof( gpTextfuncs )); |
|
if( GiveTextApi( &gpTextfuncs ) ) |
|
gameui.use_text_api = true; |
|
} |
|
|
|
pfnAddTouchButtonToList = (ADDTOUCHBUTTONTOLIST)COM_GetProcAddress( gameui.hInstance, "AddTouchButtonToList" ); |
|
if( pfnAddTouchButtonToList ) |
|
{ |
|
MsgDev( D_NOTE, "UI_LoadProgs: AddTouchButtonToList call found\n" ); |
|
} |
|
|
|
// make local copy of engfuncs to prevent overwrite it with user dll |
|
memcpy( &gpEngfuncs, &gEngfuncs, sizeof( gpEngfuncs )); |
|
|
|
gameui.mempool = Mem_AllocPool( "Menu Pool" ); |
|
|
|
if( !GetMenuAPI( &gameui.dllFuncs, &gpEngfuncs, gameui.globals )) |
|
{ |
|
COM_FreeLibrary( gameui.hInstance ); |
|
MsgDev( D_NOTE, "UI_LoadProgs: can't init menu API\n" ); |
|
Mem_FreePool( &gameui.mempool ); |
|
gameui.hInstance = NULL; |
|
return false; |
|
} |
|
|
|
Cvar_FullSet( "host_gameuiloaded", "1", FCVAR_READ_ONLY ); |
|
|
|
// setup gameinfo |
|
for( i = 0; i < SI.numgames; i++ ) |
|
{ |
|
gameui.modsInfo[i] = Mem_Alloc( gameui.mempool, sizeof( GAMEINFO )); |
|
UI_ConvertGameInfo( gameui.modsInfo[i], SI.games[i] ); |
|
} |
|
|
|
UI_ConvertGameInfo( &gameui.gameInfo, SI.GameInfo ); // current gameinfo |
|
|
|
// setup globals |
|
gameui.globals->developer = host.allow_console; |
|
|
|
// initialize game |
|
gameui.dllFuncs.pfnInit(); |
|
|
|
return true; |
|
}
|
|
|