📄 ui_main.c
字号:
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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 2 of the License,
or (at your option) any later version.
Quake III Arena source code 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.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
/*
=======================================================================
USER INTERFACE MAIN
=======================================================================
*/
// use this to get a demo build without an explicit demo build, i.e. to get the demo ui files to build
//#define PRE_RELEASE_TADEMO
#include "ui_local.h"
uiInfo_t uiInfo;
static const char *MonthAbbrev[] = {
"Jan","Feb","Mar",
"Apr","May","Jun",
"Jul","Aug","Sep",
"Oct","Nov","Dec"
};
static const char *skillLevels[] = {
"I Can Win",
"Bring It On",
"Hurt Me Plenty",
"Hardcore",
"Nightmare"
};
static const int numSkillLevels = sizeof(skillLevels) / sizeof(const char*);
static const char *netSources[] = {
"Local",
"Mplayer",
"Internet",
"Favorites"
};
static const int numNetSources = sizeof(netSources) / sizeof(const char*);
static const serverFilter_t serverFilters[] = {
{"All", "" },
{"Quake 3 Arena", "" },
{"Team Arena", "missionpack" },
{"Rocket Arena", "arena" },
{"Alliance", "alliance20" },
{"Weapons Factory Arena", "wfa" },
{"OSP", "osp" },
};
static const char *teamArenaGameTypes[] = {
"FFA",
"TOURNAMENT",
"SP",
"TEAM DM",
"CTF",
"1FCTF",
"OVERLOAD",
"HARVESTER",
"TEAMTOURNAMENT"
};
static int const numTeamArenaGameTypes = sizeof(teamArenaGameTypes) / sizeof(const char*);
static const char *teamArenaGameNames[] = {
"Free For All",
"Tournament",
"Single Player",
"Team Deathmatch",
"Capture the Flag",
"One Flag CTF",
"Overload",
"Harvester",
"Team Tournament",
};
static int const numTeamArenaGameNames = sizeof(teamArenaGameNames) / sizeof(const char*);
static const int numServerFilters = sizeof(serverFilters) / sizeof(serverFilter_t);
static const char *sortKeys[] = {
"Server Name",
"Map Name",
"Open Player Spots",
"Game Type",
"Ping Time"
};
static const int numSortKeys = sizeof(sortKeys) / sizeof(const char*);
static char* netnames[] = {
"???",
"UDP",
"IPX",
NULL
};
#ifndef MISSIONPACK // bk001206
static char quake3worldMessage[] = "Visit www.quake3world.com - News, Community, Events, Files";
#endif
static int gamecodetoui[] = {4,2,3,0,5,1,6};
static int uitogamecode[] = {4,6,2,3,1,5,7};
static void UI_StartServerRefresh(qboolean full);
static void UI_StopServerRefresh( void );
static void UI_DoServerRefresh( void );
static void UI_FeederSelection(float feederID, int index);
static void UI_BuildServerDisplayList(qboolean force);
static void UI_BuildServerStatus(qboolean force);
static void UI_BuildFindPlayerList(qboolean force);
static int QDECL UI_ServersQsortCompare( const void *arg1, const void *arg2 );
static int UI_MapCountByGameType(qboolean singlePlayer);
static int UI_HeadCountByTeam( void );
static void UI_ParseGameInfo(const char *teamFile);
static void UI_ParseTeamInfo(const char *teamFile);
static const char *UI_SelectedMap(int index, int *actual);
static const char *UI_SelectedHead(int index, int *actual);
static int UI_GetIndexFromSelection(int actual);
int ProcessNewUI( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6 );
/*
================
vmMain
This is the only way control passes into the module.
This must be the very first function compiled into the .qvm file
================
*/
vmCvar_t ui_new;
vmCvar_t ui_debug;
vmCvar_t ui_initialized;
vmCvar_t ui_teamArenaFirstRun;
void _UI_Init( qboolean );
void _UI_Shutdown( void );
void _UI_KeyEvent( int key, qboolean down );
void _UI_MouseEvent( int dx, int dy );
void _UI_Refresh( int realtime );
qboolean _UI_IsFullscreen( void );
int vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11 ) {
switch ( command ) {
case UI_GETAPIVERSION:
return UI_API_VERSION;
case UI_INIT:
_UI_Init(arg0);
return 0;
case UI_SHUTDOWN:
_UI_Shutdown();
return 0;
case UI_KEY_EVENT:
_UI_KeyEvent( arg0, arg1 );
return 0;
case UI_MOUSE_EVENT:
_UI_MouseEvent( arg0, arg1 );
return 0;
case UI_REFRESH:
_UI_Refresh( arg0 );
return 0;
case UI_IS_FULLSCREEN:
return _UI_IsFullscreen();
case UI_SET_ACTIVE_MENU:
_UI_SetActiveMenu( arg0 );
return 0;
case UI_CONSOLE_COMMAND:
return UI_ConsoleCommand(arg0);
case UI_DRAW_CONNECT_SCREEN:
UI_DrawConnectScreen( arg0 );
return 0;
case UI_HASUNIQUECDKEY: // mod authors need to observe this
return qtrue; // bk010117 - change this to qfalse for mods!
}
return -1;
}
void AssetCache() {
int n;
//if (Assets.textFont == NULL) {
//}
//Assets.background = trap_R_RegisterShaderNoMip( ASSET_BACKGROUND );
//Com_Printf("Menu Size: %i bytes\n", sizeof(Menus));
uiInfo.uiDC.Assets.gradientBar = trap_R_RegisterShaderNoMip( ASSET_GRADIENTBAR );
uiInfo.uiDC.Assets.fxBasePic = trap_R_RegisterShaderNoMip( ART_FX_BASE );
uiInfo.uiDC.Assets.fxPic[0] = trap_R_RegisterShaderNoMip( ART_FX_RED );
uiInfo.uiDC.Assets.fxPic[1] = trap_R_RegisterShaderNoMip( ART_FX_YELLOW );
uiInfo.uiDC.Assets.fxPic[2] = trap_R_RegisterShaderNoMip( ART_FX_GREEN );
uiInfo.uiDC.Assets.fxPic[3] = trap_R_RegisterShaderNoMip( ART_FX_TEAL );
uiInfo.uiDC.Assets.fxPic[4] = trap_R_RegisterShaderNoMip( ART_FX_BLUE );
uiInfo.uiDC.Assets.fxPic[5] = trap_R_RegisterShaderNoMip( ART_FX_CYAN );
uiInfo.uiDC.Assets.fxPic[6] = trap_R_RegisterShaderNoMip( ART_FX_WHITE );
uiInfo.uiDC.Assets.scrollBar = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR );
uiInfo.uiDC.Assets.scrollBarArrowDown = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWDOWN );
uiInfo.uiDC.Assets.scrollBarArrowUp = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWUP );
uiInfo.uiDC.Assets.scrollBarArrowLeft = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWLEFT );
uiInfo.uiDC.Assets.scrollBarArrowRight = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWRIGHT );
uiInfo.uiDC.Assets.scrollBarThumb = trap_R_RegisterShaderNoMip( ASSET_SCROLL_THUMB );
uiInfo.uiDC.Assets.sliderBar = trap_R_RegisterShaderNoMip( ASSET_SLIDER_BAR );
uiInfo.uiDC.Assets.sliderThumb = trap_R_RegisterShaderNoMip( ASSET_SLIDER_THUMB );
for( n = 0; n < NUM_CROSSHAIRS; n++ ) {
uiInfo.uiDC.Assets.crosshairShader[n] = trap_R_RegisterShaderNoMip( va("gfx/2d/crosshair%c", 'a' + n ) );
}
uiInfo.newHighScoreSound = trap_S_RegisterSound("sound/feedback/voc_newhighscore.wav", qfalse);
}
void _UI_DrawSides(float x, float y, float w, float h, float size) {
UI_AdjustFrom640( &x, &y, &w, &h );
size *= uiInfo.uiDC.xscale;
trap_R_DrawStretchPic( x, y, size, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
trap_R_DrawStretchPic( x + w - size, y, size, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
}
void _UI_DrawTopBottom(float x, float y, float w, float h, float size) {
UI_AdjustFrom640( &x, &y, &w, &h );
size *= uiInfo.uiDC.yscale;
trap_R_DrawStretchPic( x, y, w, size, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
trap_R_DrawStretchPic( x, y + h - size, w, size, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
}
/*
================
UI_DrawRect
Coordinates are 640*480 virtual values
=================
*/
void _UI_DrawRect( float x, float y, float width, float height, float size, const float *color ) {
trap_R_SetColor( color );
_UI_DrawTopBottom(x, y, width, height, size);
_UI_DrawSides(x, y, width, height, size);
trap_R_SetColor( NULL );
}
int Text_Width(const char *text, float scale, int limit) {
int count,len;
float out;
glyphInfo_t *glyph;
float useScale;
const char *s = text;
fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
if (scale <= ui_smallFont.value) {
font = &uiInfo.uiDC.Assets.smallFont;
} else if (scale >= ui_bigFont.value) {
font = &uiInfo.uiDC.Assets.bigFont;
}
useScale = scale * font->glyphScale;
out = 0;
if (text) {
len = strlen(text);
if (limit > 0 && len > limit) {
len = limit;
}
count = 0;
while (s && *s && count < len) {
if ( Q_IsColorString(s) ) {
s += 2;
continue;
} else {
glyph = &font->glyphs[(int)*s];
out += glyph->xSkip;
s++;
count++;
}
}
}
return out * useScale;
}
int Text_Height(const char *text, float scale, int limit) {
int len, count;
float max;
glyphInfo_t *glyph;
float useScale;
const char *s = text; // bk001206 - unsigned
fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
if (scale <= ui_smallFont.value) {
font = &uiInfo.uiDC.Assets.smallFont;
} else if (scale >= ui_bigFont.value) {
font = &uiInfo.uiDC.Assets.bigFont;
}
useScale = scale * font->glyphScale;
max = 0;
if (text) {
len = strlen(text);
if (limit > 0 && len > limit) {
len = limit;
}
count = 0;
while (s && *s && count < len) {
if ( Q_IsColorString(s) ) {
s += 2;
continue;
} else {
glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
if (max < glyph->height) {
max = glyph->height;
}
s++;
count++;
}
}
}
return max * useScale;
}
void Text_PaintChar(float x, float y, float width, float height, float scale, float s, float t, float s2, float t2, qhandle_t hShader) {
float w, h;
w = width * scale;
h = height * scale;
UI_AdjustFrom640( &x, &y, &w, &h );
trap_R_DrawStretchPic( x, y, w, h, s, t, s2, t2, hShader );
}
void Text_Paint(float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style) {
int len, count;
vec4_t newColor;
glyphInfo_t *glyph;
float useScale;
fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
if (scale <= ui_smallFont.value) {
font = &uiInfo.uiDC.Assets.smallFont;
} else if (scale >= ui_bigFont.value) {
font = &uiInfo.uiDC.Assets.bigFont;
}
useScale = scale * font->glyphScale;
if (text) {
const char *s = text; // bk001206 - unsigned
trap_R_SetColor( color );
memcpy(&newColor[0], &color[0], sizeof(vec4_t));
len = strlen(text);
if (limit > 0 && len > limit) {
len = limit;
}
count = 0;
while (s && *s && count < len) {
glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
//int yadj = Assets.textFont.glyphs[text[i]].bottom + Assets.textFont.glyphs[text[i]].top;
//float yadj = scale * (Assets.textFont.glyphs[text[i]].imageHeight - Assets.textFont.glyphs[text[i]].height);
if ( Q_IsColorString( s ) ) {
memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
newColor[3] = color[3];
trap_R_SetColor( newColor );
s += 2;
continue;
} else {
float yadj = useScale * glyph->top;
if (style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE) {
int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2;
colorBlack[3] = newColor[3];
trap_R_SetColor( colorBlack );
Text_PaintChar(x + ofs, y - yadj + ofs,
glyph->imageWidth,
glyph->imageHeight,
useScale,
glyph->s,
glyph->t,
glyph->s2,
glyph->t2,
glyph->glyph);
trap_R_SetColor( newColor );
colorBlack[3] = 1.0;
}
Text_PaintChar(x, y - yadj,
glyph->imageWidth,
glyph->imageHeight,
useScale,
glyph->s,
glyph->t,
glyph->s2,
glyph->t2,
glyph->glyph);
x += (glyph->xSkip * useScale) + adjust;
s++;
count++;
}
}
trap_R_SetColor( NULL );
}
}
void Text_PaintWithCursor(float x, float y, float scale, vec4_t color, const char *text, int cursorPos, char cursor, int limit, int style) {
int len, count;
vec4_t newColor;
glyphInfo_t *glyph, *glyph2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -