summaryrefslogtreecommitdiff
path: root/source/cl_scrn.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/cl_scrn.c')
-rw-r--r--source/cl_scrn.c1189
1 files changed, 1189 insertions, 0 deletions
diff --git a/source/cl_scrn.c b/source/cl_scrn.c
new file mode 100644
index 0000000..17f5fd8
--- /dev/null
+++ b/source/cl_scrn.c
@@ -0,0 +1,1189 @@
+/*
+Copyright (C) 1997-2001 Id Software, Inc.
+
+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 2
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+// cl_scrn.c -- master for refresh, status bar, console, chat, notify, etc
+
+#include "cl_local.h"
+
+qboolean scr_initialized; // ready to draw
+
+vrect_t scr_vrect; // position of render window on screen
+
+glconfig_t scr_glconfig;
+
+
+cvar_t *scr_viewsize;
+cvar_t *scr_centertime;
+cvar_t *scr_showpause;
+cvar_t *scr_printspeed;
+
+cvar_t *scr_netgraph;
+cvar_t *scr_timegraph;
+cvar_t *scr_debuggraph;
+cvar_t *scr_graphheight;
+cvar_t *scr_graphscale;
+cvar_t *scr_graphshift;
+cvar_t *scr_demobar;
+cvar_t *scr_fontvar;
+cvar_t *scr_scale;
+
+cvar_t *crosshair;
+
+qhandle_t crosshair_pic;
+int crosshair_width, crosshair_height;
+
+qhandle_t scr_backtile;
+qhandle_t scr_pause;
+qhandle_t scr_net;
+qhandle_t scr_font;
+
+int scr_hudWidth;
+int scr_hudHeight;
+
+#define STAT_MINUS 10 // num frame for '-' stats digit
+
+static const char *sb_nums[2][11] = {
+ { "num_0", "num_1", "num_2", "num_3", "num_4", "num_5",
+ "num_6", "num_7", "num_8", "num_9", "num_minus" },
+ { "anum_0", "anum_1", "anum_2", "anum_3", "anum_4", "anum_5",
+ "anum_6", "anum_7", "anum_8", "anum_9", "anum_minus" }
+};
+
+static qhandle_t sb_pics[2][11];
+static qhandle_t sb_inventory;
+static qhandle_t sb_field;
+
+#define ICON_WIDTH 24
+#define ICON_HEIGHT 24
+#define CHAR_WIDTH 16
+#define ICON_SPACE 8
+
+void SCR_TimeRefresh_f (void);
+void SCR_Loading_f (void);
+
+
+/*
+===============================================================================
+
+BAR GRAPHS
+
+===============================================================================
+*/
+
+/*
+==============
+CL_AddNetgraph
+
+A new packet was just parsed
+==============
+*/
+void CL_AddNetgraph (void)
+{
+ int i;
+ int in;
+ int ping;
+
+ // if using the debuggraph for something else, don't
+ // add the net lines
+ if (scr_debuggraph->integer || scr_timegraph->integer)
+ return;
+
+ for (i=0 ; i<cls.netchan->dropped ; i++)
+ SCR_DebugGraph (30, 0x40);
+
+ //for (i=0 ; i<cl.surpressCount ; i++)
+ // SCR_DebugGraph (30, 0xdf);
+
+ // see what the latency was on this packet
+ in = cls.netchan->incoming_acknowledged & CMD_MASK;
+ ping = cls.realtime - cl.history[in].realtime;
+ ping /= 30;
+ if (ping > 30)
+ ping = 30;
+ SCR_DebugGraph (ping, 0xd0);
+}
+
+
+typedef struct
+{
+ float value;
+ int color;
+} graphsamp_t;
+
+static int current;
+static graphsamp_t values[1024];
+
+/*
+==============
+SCR_DebugGraph
+==============
+*/
+void SCR_DebugGraph (float value, int color)
+{
+ values[current&1023].value = value;
+ values[current&1023].color = color;
+ current++;
+}
+
+/*
+==============
+SCR_DrawDebugGraph
+==============
+*/
+void SCR_DrawDebugGraph (void)
+{
+ int a, x, y, w, i, h;
+ float v;
+ int color;
+
+ //
+ // draw the graph
+ //
+ w = scr_glconfig.vidWidth;
+
+ x = w-1;
+ y = scr_glconfig.vidHeight;
+ ref.DrawFill (x, y-scr_graphheight->value,
+ w, scr_graphheight->value, 8);
+
+ for (a=0 ; a<w ; a++)
+ {
+ i = (current-1-a+1024) & 1023;
+ v = values[i].value;
+ color = values[i].color;
+ v = v*scr_graphscale->value + scr_graphshift->value;
+
+ if (v < 0)
+ v += scr_graphheight->value * (1+(int)(-v/scr_graphheight->value));
+ h = (int)v % (int)scr_graphheight->value;
+ ref.DrawFill (x, y - h, 1, h, color);
+ x--;
+ }
+}
+
+static void SCR_DrawPercentBar( int percent ) {
+ char buffer[8];
+ int x, w;
+ int length;
+
+ scr_hudHeight -= TINYCHAR_HEIGHT;
+
+ w = scr_hudWidth * percent / 100;
+
+ ref.DrawFill( 0, scr_hudHeight, w, TINYCHAR_HEIGHT, 4 );
+ ref.DrawFill( w, scr_hudHeight, scr_hudWidth - w, TINYCHAR_HEIGHT, 0 );
+
+ length = Com_sprintf( buffer, sizeof( buffer ), "%d%%", percent );
+ x = ( scr_hudWidth - length * TINYCHAR_WIDTH ) / 2;
+ ref.DrawString( x, scr_hudHeight, 0, MAX_STRING_CHARS, buffer, scr_font );
+}
+
+/*
+================
+SCR_DrawDemoBar
+================
+*/
+static void SCR_DrawDemoBar( void ) {
+ int percent, bufferPercent;
+
+ if( !scr_demobar->integer ) {
+ return;
+ }
+
+ if( cls.demoplayback ) {
+ SCR_DrawPercentBar( cls.demofilePercent );
+ return;
+ }
+
+ if( sv_running->integer != ss_broadcast ) {
+ return;
+ }
+
+ if( !MVD_GetDemoPercent( &percent, &bufferPercent ) ) {
+ return;
+ }
+
+ if( scr_demobar->integer & 1 ) {
+ SCR_DrawPercentBar( percent );
+ }
+ if( scr_demobar->integer & 2 ) {
+ SCR_DrawPercentBar( bufferPercent );
+ }
+
+}
+
+/*
+===============================================================================
+
+CENTER PRINTING
+
+===============================================================================
+*/
+
+static char scr_centerstring[MAX_STRING_CHARS];
+static int scr_centertime_start; // for slow victory printing
+static int scr_center_lines;
+
+/*
+==============
+SCR_CenterPrint
+
+Called for important messages that should stay in the center of the screen
+for a few moments
+==============
+*/
+void SCR_CenterPrint( const char *str ) {
+ const char *s;
+
+ scr_centertime_start = cls.realtime;
+ if( !strcmp( scr_centerstring, str ) ) {
+ return;
+ }
+
+ Q_strncpyz( scr_centerstring, str, sizeof( scr_centerstring ) );
+
+ // count the number of lines for centering
+ scr_center_lines = 1;
+ s = str;
+ while( *s ) {
+ if( *s == '\n' )
+ scr_center_lines++;
+ s++;
+ }
+
+ // echo it to the console
+ Com_Printf( "%s\n", scr_centerstring );
+ Con_ClearNotify_f();
+}
+
+void SCR_DrawCenterString( void ) {
+ int y;
+ float alpha;
+
+ Cvar_ClampValue( scr_centertime, 0.3f, 10.0f );
+
+ alpha = SCR_FadeAlpha( scr_centertime_start, scr_centertime->value * 1000, 300 );
+ if( !alpha ) {
+ return;
+ }
+
+ ref.SetColor( DRAW_COLOR_ALPHA, ( byte * )&alpha );
+
+ y = scr_hudHeight / 4 - scr_center_lines * 8 / 2;
+
+ UIS_DrawStringEx( scr_hudWidth / 2, y, UI_CENTER|UI_MULTILINE,
+ MAX_STRING_CHARS, scr_centerstring, scr_font );
+
+ ref.SetColor( DRAW_COLOR_CLEAR, NULL );
+}
+
+//============================================================================
+
+/*
+=================
+SCR_CalcVrect
+
+Sets scr_vrect, the coordinates of the rendered window
+=================
+*/
+static void SCR_CalcVrect( void ) {
+ int size;
+
+ // bound viewsize
+ Cvar_ClampInteger( scr_viewsize, 40, 100 );
+ scr_viewsize->modified = qfalse;
+
+ size = scr_viewsize->integer;
+
+ scr_vrect.width = scr_hudWidth * size / 100;
+ scr_vrect.width &= ~7;
+
+ scr_vrect.height = scr_hudHeight * size / 100;
+ scr_vrect.height &= ~1;
+
+ scr_vrect.x = ( scr_hudWidth - scr_vrect.width ) / 2;
+ scr_vrect.y = ( scr_hudHeight - scr_vrect.height ) / 2;
+}
+
+/*
+=================
+SCR_SizeUp_f
+
+Keybinding command
+=================
+*/
+void SCR_SizeUp_f (void)
+{
+ Cvar_SetInteger("viewsize",scr_viewsize->integer+10);
+}
+
+
+/*
+=================
+SCR_SizeDown_f
+
+Keybinding command
+=================
+*/
+void SCR_SizeDown_f (void)
+{
+ Cvar_SetInteger ("viewsize",scr_viewsize->integer-10);
+}
+
+/*
+=================
+SCR_Sky_f
+
+Set a specific sky and rotation speed
+=================
+*/
+void SCR_Sky_f (void)
+{
+ float rotate;
+ vec3_t axis;
+
+ if (Cmd_Argc() < 2)
+ {
+ Com_Printf ("Usage: sky <basename> [rotate] [axis x y z]\n");
+ return;
+ }
+ if (Cmd_Argc() > 2)
+ rotate = atof(Cmd_Argv(2));
+ else
+ rotate = 0;
+ if (Cmd_Argc() == 6)
+ {
+ axis[0] = atof(Cmd_Argv(3));
+ axis[1] = atof(Cmd_Argv(4));
+ axis[2] = atof(Cmd_Argv(5));
+ }
+ else
+ {
+ axis[0] = 0;
+ axis[1] = 0;
+ axis[2] = 1;
+ }
+
+ ref.SetSky (Cmd_Argv(1), rotate, axis);
+}
+
+//============================================================================
+
+/*
+===============
+SCR_TouchPics
+
+Allows rendering code to cache all needed sbar graphics
+===============
+*/
+void SCR_TouchPics( void ) {
+ int i, j;
+ char buffer[16];
+
+ for( i = 0; i < 2; i++ )
+ for( j = 0; j < 11; j++ )
+ sb_pics[i][j] = ref.RegisterPic( sb_nums[i][j] );
+
+ sb_inventory = ref.RegisterPic( "inventory" );
+ sb_field = ref.RegisterPic( "field_3" );
+
+ if( crosshair->integer ) {
+ if( crosshair->integer < 0 ) {
+ Cvar_SetInteger( "crosshair", 0 );
+ }
+
+ Com_sprintf( buffer, sizeof( buffer ), "ch%i", crosshair->integer );
+ crosshair_pic = ref.RegisterPic( buffer );
+ ref.DrawGetPicSize( &crosshair_width, &crosshair_height,
+ crosshair_pic );
+ }
+}
+
+void SCR_ModeChanged( void ) {
+ ref.GetConfig( &scr_glconfig );
+ CL_AppActivate( cls.appactive );
+ UI_ModeChanged();
+}
+
+/*
+==================
+SCR_RegisterMedia
+==================
+*/
+void SCR_RegisterMedia( void ) {
+ ref.GetConfig( &scr_glconfig );
+
+ scr_backtile = ref.RegisterPic( "backtile" );
+ scr_pause = ref.RegisterPic( "pause" );
+ scr_net = ref.RegisterPic( "net" );
+ scr_font = ref.RegisterFont( scr_fontvar->string );
+}
+
+static void scr_fontvar_changed( cvar_t *self ) {
+ scr_font = ref.RegisterFont( self->string );
+}
+
+/*
+==================
+SCR_Init
+==================
+*/
+void SCR_Init (void)
+{
+ scr_viewsize = Cvar_Get ("viewsize", "100", CVAR_ARCHIVE);
+ scr_showpause = Cvar_Get ("scr_showpause", "1", 0);
+ scr_centertime = Cvar_Get ("scr_centertime", "2.5", 0);
+ scr_printspeed = Cvar_Get ("scr_printspeed", "8", 0);
+ scr_netgraph = Cvar_Get ("netgraph", "0", 0);
+ scr_timegraph = Cvar_Get ("timegraph", "0", 0);
+ scr_debuggraph = Cvar_Get ("debuggraph", "0", 0);
+ scr_graphheight = Cvar_Get ("graphheight", "32", 0);
+ scr_graphscale = Cvar_Get ("graphscale", "1", 0);
+ scr_graphshift = Cvar_Get ("graphshift", "0", 0);
+ scr_demobar = Cvar_Get( "scr_demobar", "1", CVAR_ARCHIVE );
+ scr_fontvar = Cvar_Get( "scr_font", "conchars", CVAR_ARCHIVE );
+ scr_fontvar->changed = scr_fontvar_changed;
+ scr_scale = Cvar_Get( "scr_scale", "1", CVAR_ARCHIVE );
+
+ SCR_InitDraw();
+
+//
+// register our commands
+//
+ Cmd_AddCommand ("timerefresh",SCR_TimeRefresh_f);
+ Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
+ Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
+ Cmd_AddCommand ("sky",SCR_Sky_f);
+
+ scr_glconfig.vidWidth = 320;
+ scr_glconfig.vidHeight = 240;
+
+ scr_initialized = qtrue;
+}
+
+
+
+
+/*
+==============
+SCR_DrawPause
+==============
+*/
+void SCR_DrawPause( void ) {
+ int x, y, w, h;
+
+ if( !sv_paused->integer ) {
+ return;
+ }
+
+ if( !scr_showpause->integer ) { // turn off for screenshots
+ return;
+ }
+
+ if( cls.key_dest & KEY_MENU ) {
+ return;
+ }
+
+ ref.DrawGetPicSize( &w, &h, scr_pause );
+ x = ( scr_glconfig.vidWidth - w ) / 2;
+ y = scr_glconfig.vidHeight / 2 + 8;
+ ref.DrawPic( x, y, scr_pause );
+}
+
+//=============================================================================
+
+/*
+================
+SCR_BeginLoadingPlaque
+================
+*/
+void SCR_BeginLoadingPlaque( void ) {
+ Con_Close();
+ UI_OpenMenu( UIMENU_NONE );
+ S_StopAllSounds();
+}
+
+/*
+================
+SCR_EndLoadingPlaque
+================
+*/
+void SCR_EndLoadingPlaque( void ) {
+ Con_ClearNotify_f();
+}
+
+
+/*
+================
+SCR_TimeRefresh_f
+================
+*/
+void SCR_TimeRefresh_f (void)
+{
+ int i;
+ int start, stop;
+ float time;
+
+ if ( cls.state != ca_active )
+ return;
+
+ start = Sys_Milliseconds ();
+
+ if (Cmd_Argc() == 2) {
+ // run without page flipping
+ ref.BeginFrame();
+ for (i=0 ; i<128 ; i++) {
+ cl.refdef.viewangles[1] = i/128.0*360.0;
+ ref.RenderFrame (&cl.refdef);
+ }
+ ref.EndFrame();
+ } else {
+ for (i=0 ; i<128 ; i++) {
+ cl.refdef.viewangles[1] = i/128.0*360.0;
+
+ ref.BeginFrame();
+ ref.RenderFrame (&cl.refdef);
+ ref.EndFrame();
+ }
+ }
+
+ stop = Sys_Milliseconds ();
+ time = (stop-start)/1000.0;
+ Com_Printf ("%f seconds (%f fps)\n", time, 128/time);
+}
+
+
+
+/*
+==============
+SCR_TileClear
+
+Clear any parts of the tiled background that were drawn on last frame
+==============
+*/
+void SCR_TileClear( void ) {
+ int top, bottom, left, right;
+
+ //if( con.currentHeight == 1 )
+ // return; // full screen console
+
+ if( scr_viewsize->integer == 100 )
+ return; // full screen rendering
+
+ if( cl.cinematictime > 0 )
+ return; // full screen cinematic
+
+ top = scr_vrect.y;
+ bottom = top + scr_vrect.height - 1;
+ left = scr_vrect.x;
+ right = left + scr_vrect.width - 1;
+
+
+ // clear above view screen
+ ref.DrawTileClear( 0, 0, scr_glconfig.vidWidth, top, scr_backtile );
+
+ // clear below view screen
+ ref.DrawTileClear( 0, bottom, scr_glconfig.vidWidth,
+ scr_glconfig.vidHeight - bottom, scr_backtile );
+
+ // clear left of view screen
+ ref.DrawTileClear( 0, top, left, scr_vrect.height, scr_backtile );
+
+ // clear right of view screen
+ ref.DrawTileClear( right, top, scr_glconfig.vidWidth - right,
+ scr_vrect.height, scr_backtile );
+
+}
+
+
+/*
+===============================================================================
+
+STAT PROGRAMS
+
+===============================================================================
+*/
+
+#define HUD_DrawString( x, y, string ) \
+ ref.DrawString( x, y, 0, MAX_STRING_CHARS, string, scr_font )
+
+#define HUD_DrawAltString( x, y, string ) \
+ ref.DrawString( x, y, UI_ALTCOLOR, MAX_STRING_CHARS, string, scr_font )
+
+#define HUD_DrawCenterString( x, y, string ) \
+ UIS_DrawStringEx( x, y, UI_CENTER|UI_MULTILINE, MAX_STRING_CHARS, string, scr_font )
+
+#define HUD_DrawAltCenterString( x, y, string ) \
+ UIS_DrawStringEx( x, y, UI_CENTER|UI_MULTILINE|UI_ALTCOLOR, MAX_STRING_CHARS, string, scr_font )
+
+
+
+/*
+==============
+HUD_DrawNumber
+==============
+*/
+void HUD_DrawNumber( int x, int y, int color, int width, int value ) {
+ char num[16], *ptr;
+ int l;
+ int frame;
+
+ if( width < 1 )
+ return;
+
+ // draw number string
+ if( width > 5 )
+ width = 5;
+
+ color &= 1;
+
+ Com_sprintf( num, sizeof( num ), "%i", value );
+ l = strlen( num );
+ if( l > width )
+ l = width;
+ x += 2 + CHAR_WIDTH * ( width - l );
+
+ ptr = num;
+ while( *ptr && l ) {
+ if( *ptr == '-' )
+ frame = STAT_MINUS;
+ else
+ frame = *ptr - '0';
+
+ ref.DrawPic( x, y, sb_pics[color][frame] );
+ x += CHAR_WIDTH;
+ ptr++;
+ l--;
+ }
+}
+
+/*
+================
+CL_DrawInventory
+================
+*/
+#define DISPLAY_ITEMS 17
+
+void SCR_DrawInventory( void ) {
+ int i;
+ int num, selected_num, item;
+ int index[MAX_ITEMS];
+ char string[MAX_STRING_CHARS];
+ int x, y;
+ char *bind;
+ int selected;
+ int top;
+
+ selected = cl.frame.ps.stats[STAT_SELECTED_ITEM];
+
+ num = 0;
+ selected_num = 0;
+ for( i = 0; i < MAX_ITEMS; i++ ) {
+ if( i == selected ) {
+ selected_num = num;
+ }
+ if( cl.inventory[i] ) {
+ index[num++] = i;
+ }
+ }
+
+ // determine scroll point
+ top = selected_num - DISPLAY_ITEMS / 2;
+ clamp( top, 0, num - DISPLAY_ITEMS );
+
+ x = ( scr_hudWidth - 256 ) / 2;
+ y = ( scr_hudHeight - 240 ) / 2;
+
+ ref.DrawPic( x, y + 8, sb_inventory );
+ y += 24;
+ x += 24;
+
+ HUD_DrawString( x, y, "hotkey ### item" );
+ y += TINYCHAR_HEIGHT;
+
+ HUD_DrawString( x, y, "------ --- ----" );
+ y += TINYCHAR_HEIGHT;
+
+ for( i = top; i < num && i < top + DISPLAY_ITEMS; i++ ) {
+ item = index[i];
+ // search for a binding
+ Com_sprintf( string, sizeof( string ), "use %s",
+ cl.configstrings[CS_ITEMS + item] );
+ bind = Key_GetBinding( string );
+
+ Com_sprintf( string, sizeof( string ), "%6s %3i %s",
+ bind, cl.inventory[item], cl.configstrings[CS_ITEMS + item] );
+
+ if( item != selected ) {
+ HUD_DrawAltString( x, y, string );
+ } else { // draw a blinky cursor by the selected item
+ HUD_DrawString( x, y, string );
+ if( ( cls.realtime >> 8 ) & 1 ) {
+ ref.DrawChar( x - TINYCHAR_WIDTH, y, 0, 15, scr_font );
+ }
+
+ }
+
+ y += TINYCHAR_HEIGHT;
+ }
+
+
+}
+
+/*
+================
+SCR_ExecuteLayoutString
+
+================
+*/
+void SCR_ExecuteLayoutString( const char *s ) {
+ char buffer[80];
+ int x, y;
+ int value;
+ char *token;
+ int width;
+ int index;
+ clientinfo_t *ci;
+
+ if( !s[0] )
+ return;
+
+ x = 0;
+ y = 0;
+ width = 3;
+
+ while( s ) {
+ token = COM_Parse( &s );
+ if( token[2] == 0 ) {
+ if( token[0] == 'x' ) {
+ if( token[1] == 'l' ) {
+ token = COM_Parse( &s );
+ x = atoi( token );
+ continue;
+ }
+
+ if( token[1] == 'r' ) {
+ token = COM_Parse( &s );
+ x = scr_hudWidth + atoi( token );
+ continue;
+ }
+
+ if( token[1] == 'v' ) {
+ token = COM_Parse( &s );
+ x = scr_hudWidth / 2 - 160 + atoi( token );
+ continue;
+ }
+ }
+
+ if( token[0] == 'y' ) {
+ if( token[1] == 't' ) {
+ token = COM_Parse( &s );
+ y = atoi( token );
+ continue;
+ }
+
+ if( token[1] == 'b' ) {
+ token = COM_Parse( &s );
+ y = scr_hudHeight + atoi( token );
+ continue;
+ }
+
+ if( token[1] == 'v' ) {
+ token = COM_Parse( &s );
+ y = scr_hudHeight / 2 - 120 + atoi( token );
+ continue;
+ }
+ }
+ }
+
+ if( !strcmp( token, "pic" ) ) {
+ // draw a pic from a stat number
+ token = COM_Parse( &s );
+ value = atoi( token );
+ if( value < 0 || value >= MAX_STATS ) {
+ Com_Error( ERR_DROP,
+ "SCR_ExecuteLayoutString: invalid pic index" );
+ }
+ value = cl.frame.ps.stats[value];
+ if( value < 0 || value >= MAX_IMAGES ) {
+ Com_Error( ERR_DROP,
+ "SCR_ExecuteLayoutString: invalid pic index" );
+ }
+ token = cl.configstrings[CS_IMAGES + value];
+ if( token[0] ) {
+ UIS_DrawPicByName( x, y, token );
+ }
+ continue;
+ }
+
+ if( !strcmp( token, "client" ) ) {
+ // draw a deathmatch client block
+ int score, ping, time;
+
+ token = COM_Parse( &s );
+ x = scr_hudWidth / 2 - 160 + atoi( token );
+ token = COM_Parse( &s );
+ y = scr_hudHeight / 2 - 120 + atoi( token );
+
+ token = COM_Parse( &s );
+ value = atoi( token );
+ if( value < 0 || value >= MAX_CLIENTS ) {
+ Com_Error( ERR_DROP,
+ "SCR_ExecuteLayoutString: invalid client index" );
+ }
+ ci = &cl.clientinfo[value];
+
+ token = COM_Parse( &s );
+ score = atoi( token );
+
+ token = COM_Parse( &s );
+ ping = atoi( token );
+
+ token = COM_Parse( &s );
+ time = atoi( token );
+
+ HUD_DrawString( x + 32, y, ci->name );
+ Com_sprintf( buffer, sizeof( buffer ), "Score: %i", score );
+ HUD_DrawString( x + 32, y + TINYCHAR_HEIGHT, buffer );
+ Com_sprintf( buffer, sizeof( buffer ), "Ping: %i", ping );
+ HUD_DrawString( x + 32, y + 2 * TINYCHAR_HEIGHT, buffer );
+ Com_sprintf( buffer, sizeof( buffer ), "Time: %i", time );
+ HUD_DrawString( x + 32, y + 3 * TINYCHAR_HEIGHT, buffer );
+
+ if( !ci->icon ) {
+ ci = &cl.baseclientinfo;
+ }
+ ref.DrawPic( x, y, ci->icon );
+ continue;
+ }
+
+ if( !strcmp( token, "ctf" ) ) {
+ // draw a ctf client block
+ int score, ping;
+
+ token = COM_Parse( &s );
+ x = scr_hudWidth / 2 - 160 + atoi( token );
+ token = COM_Parse( &s );
+ y = scr_hudHeight / 2 - 120 + atoi( token );
+
+ token = COM_Parse( &s );
+ value = atoi( token );
+ if( value < 0 || value >= MAX_CLIENTS ) {
+ Com_Error( ERR_DROP,
+ "SCR_ExecuteLayoutString: invalid client index" );
+ }
+ ci = &cl.clientinfo[value];
+
+ token = COM_Parse( &s );
+ score = atoi( token );
+
+ token = COM_Parse( &s );
+ ping = atoi( token );
+ if( ping > 999 )
+ ping = 999;
+
+ Com_sprintf( buffer, sizeof( buffer ), "%3d %3d %-12.12s",
+ score, ping, ci->name );
+ if( value == cl.frame.clientNum ) {
+ HUD_DrawAltString( x, y, buffer );
+ } else {
+ HUD_DrawString( x, y, buffer );
+ }
+ continue;
+ }
+
+ if( !strcmp( token, "picn" ) ) {
+ // draw a pic from a name
+ token = COM_Parse( &s );
+ UIS_DrawPicByName( x, y, token );
+ continue;
+ }
+
+ if( !strcmp( token, "num" ) ) {
+ // draw a number
+ token = COM_Parse( &s );
+ width = atoi( token );
+ token = COM_Parse( &s );
+ value = atoi( token );
+ if( value < 0 || value >= MAX_STATS ) {
+ Com_Error( ERR_DROP,
+ "SCR_ExecuteLayoutString: invalid stat index" );
+ }
+ value = cl.frame.ps.stats[value];
+ HUD_DrawNumber( x, y, 0, width, value );
+ continue;
+ }
+
+ if( !strcmp( token, "hnum" ) ) {
+ // health number
+ int color;
+
+ width = 3;
+ value = cl.frame.ps.stats[STAT_HEALTH];
+ if( value > 25 )
+ color = 0; // green
+ else if( value > 0 )
+ color = ( cl.frame.number >> 2 ) & 1; // flash
+ else
+ color = 1;
+
+ if( cl.frame.ps.stats[STAT_FLASHES] & 1 )
+ ref.DrawPic( x, y, sb_field );
+
+ HUD_DrawNumber( x, y, color, width, value );
+ continue;
+ }
+
+ if( !strcmp( token, "anum" ) ) {
+ // ammo number
+ int color;
+
+ width = 3;
+ value = cl.frame.ps.stats[STAT_AMMO];
+ if( value > 5 )
+ color = 0; // green
+ else if( value >= 0 )
+ color = ( cl.frame.number >> 2 ) & 1; // flash
+ else
+ continue; // negative number = don't show
+
+ if( cl.frame.ps.stats[STAT_FLASHES] & 4 )
+ ref.DrawPic( x, y, sb_field );
+
+ HUD_DrawNumber( x, y, color, width, value );
+ continue;
+ }
+
+ if( !strcmp( token, "rnum" ) ) {
+ // armor number
+ int color;
+
+ width = 3;
+ value = cl.frame.ps.stats[STAT_ARMOR];
+ if( value < 1 )
+ continue;
+
+ color = 0; // green
+
+ if( cl.frame.ps.stats[STAT_FLASHES] & 2 )
+ ref.DrawPic( x, y, sb_field );
+
+ HUD_DrawNumber( x, y, color, width, value );
+ continue;
+ }
+
+ if( !strcmp( token, "stat_string" ) ) {
+ token = COM_Parse( &s );
+ index = atoi( token );
+ if( index < 0 || index >= MAX_STATS ) {
+ Com_Error( ERR_DROP, "SCR_ExecuteLayoutString: "
+ "invalid stat_string index" );
+ }
+ index = cl.frame.ps.stats[index];
+ if( index < 0 || index >= MAX_CONFIGSTRINGS ) {
+ Com_Error( ERR_DROP, "SCR_ExecuteLayoutString: "
+ "invalid stat_string index" );
+ }
+ HUD_DrawString( x, y, cl.configstrings[index] );
+ continue;
+ }
+
+ if( !strcmp( token, "cstring" ) ) {
+ token = COM_Parse( &s );
+ HUD_DrawCenterString( x + 320 / 2, y, token );
+ continue;
+ }
+
+ if( !strcmp( token, "cstring2" ) ) {
+ token = COM_Parse( &s );
+ HUD_DrawAltCenterString( x + 320 / 2, y, token );
+ continue;
+ }
+
+ if( !strcmp( token, "string" ) ) {
+ token = COM_Parse( &s );
+ HUD_DrawString( x, y, token );
+ continue;
+ }
+
+ if( !strcmp( token, "string2" ) ) {
+ token = COM_Parse( &s );
+ HUD_DrawAltString( x, y, token );
+ continue;
+ }
+
+ if( !strcmp( token, "if" ) ) {
+ token = COM_Parse( &s );
+ value = atoi( token );
+ if( value < 0 || value >= MAX_STATS ) {
+ Com_Error( ERR_DROP, "SCR_ExecuteLayoutString: "
+ "invalid stat index" );
+ }
+ value = cl.frame.ps.stats[value];
+ if( !value ) { // skip to endif
+ while( strcmp( token, "endif" ) ) {
+ token = COM_Parse( &s );
+ if( !s ) {
+ break;
+ }
+ }
+ }
+
+ continue;
+ }
+
+
+ }
+}
+
+static void SCR_DrawActiveFrame( void ) {
+ float scale;
+
+ scr_hudHeight = scr_glconfig.vidHeight;
+ scr_hudWidth = scr_glconfig.vidWidth;
+
+ SCR_DrawDemoBar();
+
+ SCR_CalcVrect();
+
+ /* clear any dirty part of the background */
+ SCR_TileClear();
+
+ /* draw 3D game view */
+ V_RenderView();
+
+ Cvar_ClampValue( scr_scale, 1, 9 );
+
+ scale = 1.0f / scr_scale->value;
+ ref.SetScale( &scale );
+
+ scr_hudHeight *= scale;
+ scr_hudWidth *= scale;
+
+ /* draw all 2D elements */
+ SCR_Draw2D();
+
+ ref.SetScale( NULL );
+}
+
+//=======================================================
+
+/*
+==================
+SCR_UpdateScreen
+
+This is called every frame, and can also be called explicitly to flush
+text to the screen.
+==================
+*/
+void SCR_UpdateScreen( void ) {
+ static int recursive;
+
+ if( !scr_initialized )
+ return; // not initialized yet
+
+ if( recursive > 1 ) {
+ Com_Error( ERR_FATAL, "SCR_UpdateScreen: recursively called" );
+ }
+
+ recursive++;
+
+ ref.BeginFrame();
+
+ /* if a cinematic is supposed to be running, handle menus
+ * and console specially
+ */
+ if( cl.cinematictime > 0 ) {
+ if( cls.key_dest & (KEY_CONSOLE|KEY_MENU) ) {
+ if( cl.cinematicpalette_active ) {
+ ref.CinematicSetPalette( NULL );
+ cl.cinematicpalette_active = qfalse;
+ }
+ UI_Draw( cls.realtime );
+ Con_DrawConsole();
+ } else {
+ SCR_DrawCinematic();
+ }
+ return;
+ }
+
+ /* make sure the game palette is active */
+ if( cl.cinematicpalette_active ) {
+ ref.CinematicSetPalette( NULL );
+ cl.cinematicpalette_active = qfalse;
+ }
+
+ switch( cls.state ) {
+ case ca_disconnected:
+ /* make sure at least fullscreen console or main menu is up */
+ if( !( cls.key_dest & (KEY_MENU|KEY_CONSOLE) ) ) {
+ Key_SetDest( cls.key_dest | KEY_CONSOLE );
+ Con_RunConsole();
+ }
+
+ /* draw main menu */
+ UI_Draw( cls.realtime );
+ break;
+
+ case ca_challenging:
+ case ca_connecting:
+ case ca_connected:
+ case ca_loading:
+ case ca_precached:
+ /* make sure main menu is down */
+ if( cls.key_dest & KEY_MENU ) {
+ UI_OpenMenu( UIMENU_NONE );
+ }
+
+ /* draw loading screen */
+ UI_DrawLoading( cls.realtime );
+ break;
+
+ case ca_active:
+ if( UI_IsTransparent() ) {
+ /* do 3D refresh drawing */
+ SCR_DrawActiveFrame();
+ }
+
+ /* draw ingame menu */
+ UI_Draw( cls.realtime );
+ break;
+
+ default:
+ Com_Error( ERR_FATAL, "SCR_DrawScreenFrame: bad cls.state" );
+ break;
+ }
+
+ Con_DrawConsole();
+
+ if( scr_timegraph->integer )
+ SCR_DebugGraph( cls.frametime*300, 0 );
+
+ if( scr_debuggraph->integer || scr_timegraph->integer ||
+ scr_netgraph->integer )
+ {
+ SCR_DrawDebugGraph();
+ }
+
+ ref.EndFrame();
+
+ recursive--;
+}
+
+