1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 */
20 // cl_scrn.c -- master for refresh, status bar, console, chat, notify, etc
21 
22 /*
23 
24   full screen console
25   put up loading plaque
26   blanked background with loading plaque
27   blanked background with menu
28   full screen image for quit and victory
29 
30   end of unit intermissions
31 
32   */
33 
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37 
38 #include "client.h"
39 #include "qmenu.h"
40 
41 float		scr_con_current;	// aproaches scr_conlines at scr_conspeed
42 float		scr_conlines;		// 0.0 to 1.0 lines of console to display
43 
44 qboolean	scr_initialized;		// ready to draw
45 
46 int			scr_draw_loading;
47 
48 vrect_t		scr_vrect;		// position of render window on screen
49 
50 cvar_t		*scr_conspeed;
51 cvar_t		*scr_centertime;
52 cvar_t		*scr_showturtle;
53 cvar_t		*scr_showpause;
54 cvar_t		*scr_printspeed;
55 
56 cvar_t		*scr_netgraph;
57 cvar_t		*scr_timegraph;
58 cvar_t		*scr_debuggraph;
59 cvar_t		*scr_graphheight;
60 cvar_t		*scr_graphscale;
61 cvar_t		*scr_graphshift;
62 cvar_t      *scr_timerefcount; // for timerefresh command
63 
64 cvar_t		*scr_consize;
65 
66 cvar_t		*cl_drawfps;
67 cvar_t		*cl_drawtimer;
68 cvar_t		*cl_drawbandwidth;
69 cvar_t		*cl_drawframesover;
70 
71 cvar_t		*cl_drawtime;
72 
73 char		crosshair_pic[MAX_QPATH];
74 int		crosshair_width, crosshair_height;
75 
76 void SCR_TimeRefresh_f (void);
77 void SCR_Loading_f (void);
78 
79 extern void R_VCFreeFrame(void);
80 extern cvar_t *rs_hasflag;
81 extern cvar_t *rs_team;
82 
83 /*
84  * map performance counters
85  *
86  * Used to measure the complexity of map areas.
87  * Modified for display in performance counter array
88  * Replace general "r_speed" cvar.
89  *
90  * Note: c_visible_textures seems to be always 0 and
91  *   c_visible_lightmaps is not used
92  */
93 // extern cvar_t *r_speeds;
94 cvar_t *rspeed_wpolys;
95 cvar_t *rspeed_epolys;
96 cvar_t *rspeed_flares;
97 cvar_t *rspeed_grasses;
98 cvar_t *rspeed_beams;
99 cvar_t *rspeed_vbobatches;
100 cvar_t *rspeed_particles;
101 
102 extern int c_brush_polys;  /* "wpoly"   polygons from brushes */
103 extern int c_alias_polys;  /* "epoly"   polygons from .md2 meshes */
104 extern int c_flares;       /* "flares"  lens flares */
105 extern int c_grasses;      /* "grasses" vegetation instances */
106 extern int c_beams;        /* "beams"   light beams (?) */
107 extern int c_vbo_batches;  /* "vbobatches" batched draw commands */
108 
109 /*
110 ===============================================================================
111 
112 BAR GRAPHS
113 
114 ===============================================================================
115 */
116 
117 /*
118 ==============
119 CL_AddNetgraph
120 
121 A new packet was just parsed
122 ==============
123 */
CL_AddNetgraph(void)124 void CL_AddNetgraph (void)
125 {
126 	int		i;
127 	int		in;
128 	int		ping;
129 
130 	// if using the debuggraph for something else, don't
131 	// add the net lines
132 	if (scr_debuggraph->value || scr_timegraph->value)
133 		return;
134 
135 	for (i=0 ; i<cls.netchan.dropped ; i++)
136 		SCR_DebugGraph (30, RGBA8(167,59,49,255));
137 
138 	for (i=0 ; i<cl.surpressCount ; i++)
139 		SCR_DebugGraph (30, RGBA8(255,191,15,255));
140 
141 	// see what the latency was on this packet
142 	in = cls.netchan.incoming_acknowledged & (CMD_BACKUP-1);
143 	ping = cls.realtime - cl.cmd_time[in];
144 	ping /= 30;
145 	if (ping > 30)
146 		ping = 30;
147 	SCR_DebugGraph (ping, RGBA(0,1,0,1));
148 }
149 
150 
151 typedef struct
152 {
153 	float	value;
154 	float	color[4];
155 } graphsamp_t;
156 
157 #define	DEBUGGRAPH_VALUES	4096
158 static	int			current;
159 static	graphsamp_t	values[DEBUGGRAPH_VALUES];
160 
161 /*
162 ==============
163 SCR_DebugGraph
164 ==============
165 */
SCR_DebugGraph(float value,const float color[])166 void SCR_DebugGraph (float value, const float color[])
167 {
168 	int i;
169 	int limit;
170 	limit = scr_vrect.width;
171 	if (limit > DEBUGGRAPH_VALUES)
172 		limit = DEBUGGRAPH_VALUES;
173 	values[current%limit].value = value;
174 	for (i = 0; i < 4; i++)
175 		values[current%limit].color[i] = color[i];
176 	current++;
177 }
178 
179 /*
180 ==============
181 SCR_DrawDebugGraph
182 ==============
183 */
SCR_DrawDebugGraph(void)184 void SCR_DrawDebugGraph (void)
185 {
186 	int			a, x, y, w, i, h;
187 	float		v;
188 	const float	*color;
189 
190 	//
191 	// draw the graph
192 	//
193 
194 	w = scr_vrect.width;
195 	if (w > DEBUGGRAPH_VALUES)
196 		w = DEBUGGRAPH_VALUES;
197 
198 	x = scr_vrect.x;
199 	y = scr_vrect.y+scr_vrect.height;
200 	Draw_Fill (x, y-scr_graphheight->value,
201 		w, scr_graphheight->value, RGBA8(123,123,123,255));
202 
203 	for (a=0 ; a<w ; a++)
204 	{
205 		i = (current-1-a+w) % w;
206 		v = values[i].value;
207 		color = values[i].color;
208 		v = v*scr_graphscale->value + scr_graphshift->value;
209 
210 		if (v < 0)
211 			v += scr_graphheight->value * (1+(int)(-v/scr_graphheight->value));
212 		h = (int)v % scr_graphheight->integer;
213 		Draw_Fill (x+w-1-a, y - h, 1, h, color);
214 	}
215 }
216 
217 /*
218 ===============================================================================
219 
220 CENTER PRINTING
221 
222 ===============================================================================
223 */
224 
225 char		scr_centerstring[1024];
226 float		scr_centertime_start;	// for slow victory printing
227 float		scr_centertime_off;
228 int			scr_center_lines;
229 int			scr_erase_center;
230 
231 /*
232 ==============
233 SCR_CenterPrint
234 
235 Called for important messages that should stay in the center of the screen
236 for a few moments
237 ==============
238 */
SCR_CenterPrint(char * str)239 void SCR_CenterPrint (char *str)
240 {
241 	char	*s;
242 
243 	if(!cl_centerprint->value)
244 		return;
245 
246 	strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
247 	scr_centertime_off = scr_centertime->value;
248 	scr_centertime_start = cl.time;
249 
250 	// count the number of lines for centering
251 	scr_center_lines = 1;
252 	s = str;
253 	while (*s)
254 	{
255 		if (*s == '\n')
256 			scr_center_lines++;
257 		s++;
258 	}
259 }
260 
261 
SCR_DrawCenterString(void)262 void SCR_DrawCenterString (void)
263 {
264 	FNT_font_t		font;
265 	struct FNT_window_s	box;
266 	float			colors[ 8 ] = { 1, 1, 1, 1, 0.25, 1, 0.25, 1 };
267 
268 	if ( scr_centertime_off <= scr_centertime->value / 5.0 ) {
269 		colors[ 3 ] = colors[ 7 ] = scr_centertime_off * 5.0 / scr_centertime->value;
270 	}
271 
272 	box.x = 0;
273 	if ( scr_center_lines <= 4 ) {
274 		box.y = viddef.height * 0.35;
275 	} else {
276 		box.y = 48;
277 	}
278 	box.height = viddef.height - box.y;
279 	box.width = viddef.width;
280 
281 	font = FNT_AutoGet( CL_centerFont );
282 	FNT_BoundedPrint( font , scr_centerstring , FNT_CMODE_TWO , FNT_ALIGN_CENTER , &box , colors );
283 }
284 
SCR_CheckDrawCenterString(void)285 void SCR_CheckDrawCenterString (void)
286 {
287 	scr_centertime_off -= cls.frametime;
288 
289 	if (scr_centertime_off <= 0)
290 		return;
291 
292 	SCR_DrawCenterString ();
293 }
294 
295 /*
296 ===============================================================================
297 
298 IRC PRINTING
299 
300   we'll have 5 lines stored.
301   once full, start bumping lines, as in copying line 1 into line 0, and so forth
302 
303 ===============================================================================
304 */
305 
306 extern vec4_t		Color_Table[8];
307 
308 #define SCR_IRC_LINES	5
309 #define SCR_IRC_LENGTH	1024
310 #define SCR_IRC_INDENT	8
311 
312 #define SCR_IRC_DISPLAY_HIDE 0		// During line bumping
313 #define SCR_IRC_DISPLAY_PARTIAL 1	// When a new line is being added
314 #define SCR_IRC_DISPLAY_FULL 2		// No problemo
315 
316 char			scr_IRCstring_contents[ SCR_IRC_LINES ][ SCR_IRC_LENGTH ];
317 char *			scr_IRCstring[ SCR_IRC_LINES ];
318 float			scr_IRCtime_start;	// for slow victory printing
319 float			scr_IRCtime_off;
320 int			scr_IRC_lines = -1;
321 int			scr_IRC_display = SCR_IRC_DISPLAY_FULL;
322 
323 /*
324 ==============
325 SCR_IRCPrint
326 
327 Called for IRC messages
328 ==============
329 */
330 
331 
IRC_SetNextLine(int len,const char * buffer)332 void IRC_SetNextLine( int len , const char *buffer )
333 {
334 	char * to_set;
335 	int i;
336 
337 	// Access the correct line buffer
338 	scr_IRC_display = SCR_IRC_DISPLAY_HIDE;
339 	if ( scr_IRC_lines < SCR_IRC_LINES - 1 ) {
340 		scr_IRC_lines ++;
341 		to_set = scr_IRCstring_contents[ scr_IRC_lines ];
342 	} else {
343 		to_set = scr_IRCstring[ 0 ];
344 		for ( i = 0 ; i < SCR_IRC_LINES - 1 ; i ++ )
345 			scr_IRCstring[ i ] = scr_IRCstring[ i + 1 ];
346 	}
347 	scr_IRCstring[ scr_IRC_lines ] = to_set;
348 	scr_IRC_display = SCR_IRC_DISPLAY_PARTIAL;
349 
350 	// Copy string
351 	Q_strncpyz2( to_set , buffer , SCR_IRC_LENGTH );
352 
353 	// Restore IRC display and update time-related variables
354 	scr_IRCtime_off = 15;
355 	scr_IRCtime_start = cl.time;
356 	scr_IRC_display = SCR_IRC_DISPLAY_FULL;
357 }
358 
359 
SCR_IRCPrintf(char * fmt,...)360 void SCR_IRCPrintf (char *fmt, ...)
361 {
362 	va_list		argptr;
363 	char		msg[1024];
364 	int		len;
365 
366 	va_start (argptr,fmt);
367 	len = vsnprintf(msg, sizeof(msg), fmt, argptr);
368 	va_end (argptr);
369 
370 	if ( len >= sizeof(msg) )
371 		len = sizeof( msg ) - 1;
372 
373 	IRC_SetNextLine( len , msg );
374 }
375 
376 
SCR_CheckDrawIRCString(void)377 void SCR_CheckDrawIRCString (void)
378 {
379 	FNT_font_t		font;
380 	struct FNT_window_s	box;
381 	int			i , last_line;
382 	static float		color[ 4 ] = { 1 , 1 , 1 , 1 };
383 
384 	scr_IRCtime_off -= cls.frametime;
385 	if (scr_IRCtime_off <= 0 || scr_IRC_display == SCR_IRC_DISPLAY_HIDE)
386 		return;
387 
388 	last_line = ( scr_IRC_display == SCR_IRC_DISPLAY_FULL ) ? scr_IRC_lines : ( scr_IRC_lines - 1 );
389 	if ( last_line == -1 )
390 		return;
391 
392 	font = FNT_AutoGet( CL_gameFont );
393 
394 	box.x = 0;
395 	box.y = font->size * 5;
396 	for ( i = 0 ; i <= last_line ; i++ ) {
397 		box.width = viddef.width;
398 		box.height = font->size * 15 - box.y;
399 
400 		FNT_WrappedPrint( font , scr_IRCstring[ i ] , FNT_CMODE_QUAKE , FNT_ALIGN_LEFT ,
401 			SCR_IRC_INDENT , &box , color );
402 
403 		box.y += box.height;
404 		if ( box.y >= font->size * 15 ) {
405 			break;
406 		}
407 	}
408 }
409 
410 //=============================================================================
411 
412 /*
413 =================
414 SCR_CalcVrect
415 
416 Sets scr_vrect, the coordinates of the rendered window
417 =================
418 */
SCR_CalcVrect(void)419 static void SCR_CalcVrect (void)
420 {
421 
422 	scr_vrect.width = viddef.width;
423 	scr_vrect.height = viddef.height;
424 
425 	// calculate left and top margins-- for now always 0
426 	scr_vrect.x = (viddef.width - scr_vrect.width)/2;
427 	scr_vrect.y = (viddef.height - scr_vrect.height)/2;
428 }
429 
430 /*
431 =================
432 SCR_Sky_f
433 
434 Set a specific sky and rotation speed
435 =================
436 */
SCR_Sky_f(void)437 void SCR_Sky_f (void)
438 {
439 	float	rotate;
440 	vec3_t	axis;
441 
442 	if (Cmd_Argc() < 2)
443 	{
444 		Com_Printf ("Usage: sky <basename> <rotate> <axis x y z>\n");
445 		return;
446 	}
447 	if (Cmd_Argc() > 2)
448 		rotate = atof(Cmd_Argv(2));
449 	else
450 		rotate = 0;
451 	if (Cmd_Argc() == 6)
452 	{
453 		axis[0] = atof(Cmd_Argv(3));
454 		axis[1] = atof(Cmd_Argv(4));
455 		axis[2] = atof(Cmd_Argv(5));
456 	}
457 	else
458 	{
459 		axis[0] = 0;
460 		axis[1] = 0;
461 		axis[2] = 1;
462 	}
463 
464 	R_SetSky (Cmd_Argv(1), rotate, axis);
465 }
466 
467 //============================================================================
468 
469 /*
470 ==================
471 SCR_Init
472 ==================
473 */
SCR_Init(void)474 void SCR_Init (void)
475 {
476 	scr_conspeed = Cvar_Get ("scr_conspeed", "3", CVAR_ARCHIVE);
477 	scr_consize = Cvar_Get ("scr_consize", "0.5", CVAR_ARCHIVE);
478 	scr_showturtle = Cvar_Get ("scr_showturtle", "0", 0);
479 	// default back to 1 if we ever actually make a pause icon:
480 	scr_showpause = Cvar_Get ("scr_showpause", "0", 0);
481 	scr_centertime = Cvar_Get ("scr_centertime", "2.5", CVAR_ARCHIVE);
482 	scr_printspeed = Cvar_Get ("scr_printspeed", "8", CVAR_ARCHIVE);
483 	scr_netgraph = Cvar_Get ("netgraph", "0", 0);
484 	scr_timegraph = Cvar_Get ("timegraph", "0", 0);
485 	scr_debuggraph = Cvar_Get ("debuggraph", "0", 0);
486 	scr_graphheight = Cvar_Get ("graphheight", "32", 0);
487 	scr_graphscale = Cvar_Get ("graphscale", "1", 0);
488 	scr_graphshift = Cvar_Get ("graphshift", "0", 0);
489 	// configurable number of frames for timerefresh command
490 	scr_timerefcount = Cvar_Get("scr_timerefcount", "128", 0 );
491 
492 	cl_drawfps = Cvar_Get ("cl_drawfps", "0", CVAR_ARCHIVE);
493 	cl_drawtimer = Cvar_Get("cl_drawtimer", "0", CVAR_ARCHIVE);
494 	cl_drawbandwidth = Cvar_Get ("cl_drawbandwidth", "0", CVAR_ARCHIVE);
495 	cl_drawframesover = Cvar_Get ("cl_drawframesover", "0", CVAR_ARCHIVE);
496 
497 	rspeed_wpolys   = Cvar_Get("rspeed_wpolys",  "0", 0);
498 	rspeed_epolys   = Cvar_Get("rspeed_epolys",  "0", 0);
499 	rspeed_flares   = Cvar_Get("rspeed_flares",  "0", 0);
500 	rspeed_grasses  = Cvar_Get("rspeed_grasses", "0", 0);
501 	rspeed_beams    = Cvar_Get("rspeed_beams",   "0", 0);
502 	rspeed_vbobatches = Cvar_Get("rspeed_vbobatches", "0", 0);
503 	rspeed_particles = Cvar_Get("rspeed_particles", "0", 0);
504 
505 	memset (perftests, 0, sizeof(perftests));
506 
507 //
508 // register our commands
509 //
510 	Cmd_AddCommand ("timerefresh",SCR_TimeRefresh_f);
511 	Cmd_AddCommand ("loading",SCR_Loading_f);
512 	Cmd_AddCommand ("sky",SCR_Sky_f);
513 
514 	scr_initialized = true;
515 }
516 
517 
518 /*
519 ==============
520 SCR_DrawNet
521 ==============
522 */
SCR_DrawNet(void)523 void SCR_DrawNet (void)
524 {
525 	if (cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged
526 		< CMD_BACKUP-1)
527 		return;
528 
529 	Draw_Pic (scr_vrect.x+64, scr_vrect.y, "net");
530 }
531 
SCR_DrawAlertMessagePicture(char * name,qboolean center)532 void SCR_DrawAlertMessagePicture (char *name, qboolean center)
533 {
534 	float ratio;
535 	int scale;
536 	int w, h;
537 
538 	scale = viddef.width/MENU_STATIC_WIDTH;
539 
540 	Draw_GetPicSize (&w, &h, name );
541 	if (w)
542 	{
543 		ratio = 35.0/(float)h;
544 		h = 35;
545 		w *= ratio;
546 	}
547 	else
548 		return;
549 
550 	if(center)
551 		Draw_StretchPic (
552 			viddef.width / 2 - w*scale/2,
553 			viddef.height/ 2 - h*scale/2,
554 			scale*w, scale*h, name);
555 	else
556 		Draw_StretchPic (
557 			viddef.width / 2 - w*scale/2,
558 			scale * 100,
559 			scale*w, scale*h, name);
560 }
561 
SCR_DrawPause(void)562 void SCR_DrawPause (void)
563 {
564 
565 	if (!scr_showpause->value)		// turn off for screenshots
566 		return;
567 
568 	if (!cl_paused->value)
569 		return;
570 
571 	if (cls.key_dest == key_menu)
572 		return;
573 
574 	SCR_DrawAlertMessagePicture("pause", true);
575 }
576 
577 /*
578 ==============
579 SCR_DrawLoading
580 ==============
581 */
582 
583 
SCR_DrawRotatingIcon(void)584 void SCR_DrawRotatingIcon( void )
585 {
586 	extern float CalcFov( float fov_x, float w, float h );
587 	refdef_t refdef;
588 	static float yaw;
589 	entity_t entity;
590 
591 	memset( &refdef, 0, sizeof( refdef ) );
592 
593 	refdef.width = viddef.width;
594 	refdef.height = viddef.height;
595 	refdef.x = 0;
596 	refdef.y = 0;
597 	refdef.fov_x = 90;
598 	refdef.fov_y = CalcFov( refdef.fov_x, refdef.width, refdef.height );
599 	refdef.time = cls.realtime*0.001;
600 
601 	memset( &entity, 0, sizeof( entity ) );
602 
603 	yaw += cls.frametime*50;
604 	if (yaw > 360)
605 		yaw = 0;
606 
607 	entity.model = R_RegisterModel( "models/objects/icon/tris.md2" );
608 
609 	entity.flags = RF_FULLBRIGHT | RF_MENUMODEL;
610 	entity.origin[0] = 80;
611 	entity.origin[1] = 30;
612 	entity.origin[2] = -5;
613 
614 	VectorCopy( entity.origin, entity.oldorigin );
615 
616 	entity.frame = 0;
617 	entity.oldframe = 0;
618 	entity.backlerp = 0.0;
619 	entity.angles[1] = (int)yaw;
620 
621 	refdef.areabits = 0;
622 	refdef.num_entities = 1;
623 
624 	refdef.entities = &entity;
625 	refdef.lightstyles = 0;
626 	refdef.rdflags = RDF_NOWORLDMODEL;
627 
628 	refdef.height += 4;
629 
630 	R_RenderFrame( &refdef );
631 
632 	free(entity.model);
633 }
634 
SCR_DrawLoadingBar(int percent,int scale)635 void SCR_DrawLoadingBar (int percent, int scale)
636 {
637 	float hudscale;
638 
639 	hudscale = (float)(viddef.height)/600;
640 	if(hudscale < 1)
641 		hudscale = 1;
642 
643 	if (R_RegisterPic("bar_background") && R_RegisterPic("bar_loading"))
644 	{
645 		Draw_StretchPic (
646 			viddef.width/2-scale*15 + 1*hudscale,viddef.height/2 + scale*5.4,
647 			scale*30-2*hudscale, scale*10, "bar_background");
648 		Draw_StretchPic (
649 			viddef.width/2-scale*15 + 1*hudscale,viddef.height/2 + scale*6.2,
650 			(scale*30-2*hudscale)*percent/100, scale*2, "bar_loading");
651 	}
652 	else
653 	{
654 		Draw_Fill (
655 			viddef.width/2-scale*15 + 1,viddef.height/2 + scale*5+1,
656 			scale*30-2, scale*2-2, RGBA8(47,47,47,255));
657 		Draw_Fill (
658 			viddef.width/2-scale*15 + 1,viddef.height/2 + scale*5+1,
659 			(scale*30-2)*percent/100, scale*2-2, RGBA8(107,107,107,255));
660 	}
661 }
662 
663 
664 
SCR_DrawLoading(void)665 void SCR_DrawLoading (void)
666 {
667 	FNT_font_t		font;
668 	struct FNT_window_s	box;
669 	char			mapfile[32];
670 	qboolean		isMap = false;
671 	float			hudscale;
672 
673 	if (!scr_draw_loading)
674 		return;
675 	scr_draw_loading = false;
676 	font = FNT_AutoGet( CL_gameFont );
677 
678 	hudscale = (float)(viddef.height)/600;
679 	if(hudscale < 1)
680 		hudscale = 1;
681 
682 	//loading a map...
683 	if (loadingMessage && cl.configstrings[CS_MODELS+1][0])
684 	{
685 		strcpy (mapfile, cl.configstrings[CS_MODELS+1] + 5);	// skip "maps/"
686 		mapfile[strlen(mapfile)-4] = 0;		// cut off ".bsp"
687 
688 		if(map_pic_loaded)
689 			Draw_StretchPic (0, 0, viddef.width, viddef.height, va("/levelshots/%s.pcx", mapfile));
690 		else
691 			Draw_Fill (0, 0, viddef.width, viddef.height, RGBA(0,0,0,1));
692 
693 		isMap = true;
694 
695 	}
696 	else
697 		Draw_Fill (0, 0, viddef.width, viddef.height, RGBA(0,0,0,1));
698 
699 #if 0
700 	// no m_background pic, but a pic here over-writes the levelshot
701 	Draw_StretchPic (0, 0, viddef.width, viddef.height, "m_background");
702 #endif
703 
704 	//loading message stuff...
705 	if (isMap)
706 	{
707 		char loadMessage[ MAX_QPATH * 6 ];
708 		int i;
709 
710 		Com_sprintf( loadMessage , sizeof( loadMessage ) , "Loading Map [%s]\n^3%s" , mapfile , cl.configstrings[CS_NAME] );
711 
712 		box.x = 0;
713 		box.y = viddef.height / 2 - font->size * 5;
714 		box.width = viddef.width;
715 		box.height = 0;
716 		FNT_BoundedPrint( font , loadMessage , FNT_CMODE_QUAKE , FNT_ALIGN_CENTER , &box , FNT_colors[ 7 ] );
717 
718 		box.y += font->size * 4;
719 		for ( i = 0 ; i < 5 ; i ++ ) {
720 			box.x = viddef.width / 2 - font->size * 15;
721 			box.width = box.height = 0;
722 			FNT_BoundedPrint( font , loadingMessages[i][0] , FNT_CMODE_QUAKE , FNT_ALIGN_LEFT , &box , FNT_colors[ 7 ] );
723 
724 			box.x += box.width + font->size;
725 			box.width = viddef.width / 2 + font->size * 15 - box.x;
726 			box.height = 0;
727 			FNT_BoundedPrint( font , loadingMessages[i][1] , FNT_CMODE_QUAKE , FNT_ALIGN_RIGHT , &box , FNT_colors[ 7 ] );
728 
729 			box.y += font->size;
730 		}
731 
732 		//check for instance of icons we would like to show in loading process, ala q3
733 		if(rocketlauncher) {
734 			Draw_ScaledPic((int)(viddef.width/3), (int)(viddef.height/3.2), hudscale, "w_rlauncher");
735 			if(!rocketlauncher_drawn){
736 				rocketlauncher_drawn = 40*hudscale;
737 			}
738 		}
739 		if(chaingun) {
740 			Draw_ScaledPic((int)(viddef.width/3) + rocketlauncher_drawn, (int)(viddef.height/3.2), hudscale, "w_sshotgun");
741 			if(!chaingun_drawn) {
742 				chaingun_drawn = 40*hudscale;
743 			}
744 		}
745 		if(smartgun) {
746 			Draw_ScaledPic((int)(viddef.width/3) + rocketlauncher_drawn+chaingun_drawn, (int)(viddef.height/3.2), hudscale, "w_shotgun");
747 			if(!smartgun_drawn) {
748 				smartgun_drawn = 40*hudscale;
749 			}
750 		}
751 		if(beamgun) {
752 			Draw_ScaledPic((int)(viddef.width/3) + rocketlauncher_drawn+chaingun_drawn+smartgun_drawn, (int)(viddef.height/3.2), hudscale, "w_railgun");
753 			if(!beamgun_drawn) {
754 				beamgun_drawn = 40*hudscale;
755 			}
756 		}
757 		if(flamethrower) {
758 			Draw_ScaledPic((int)(viddef.width/3) + rocketlauncher_drawn+chaingun_drawn+smartgun_drawn+beamgun_drawn
759 				, (int)(viddef.height/3.2), hudscale, "w_chaingun");
760 			if(!flamethrower_drawn) {
761 				flamethrower_drawn = 40*hudscale;
762 			}
763 		}
764 		if(disruptor) {
765 			Draw_ScaledPic((int)(viddef.width/3) + rocketlauncher_drawn+chaingun_drawn+smartgun_drawn+beamgun_drawn+flamethrower_drawn
766 				, (int)(viddef.height/3.2), hudscale, "w_hyperblaster");
767 			if(!disruptor_drawn) {
768 				disruptor_drawn = 40*hudscale;
769 			}
770 		}
771 		if(vaporizer) {
772 			Draw_ScaledPic((int)(viddef.width/3) + rocketlauncher_drawn+chaingun_drawn+smartgun_drawn+beamgun_drawn+flamethrower_drawn+disruptor_drawn
773 				, (int)(viddef.height/3.2), hudscale, "w_bfg");
774 			if(!vaporizer_drawn) {
775 				vaporizer_drawn = 40*hudscale;
776 			}
777 		}
778 		if(quad) {
779 			Draw_ScaledPic((int)(viddef.width/3) + rocketlauncher_drawn+chaingun_drawn+smartgun_drawn+beamgun_drawn+flamethrower_drawn+disruptor_drawn+vaporizer_drawn
780 				, (int)(viddef.height/3.2), hudscale, "p_quad");
781 			if(!quad_drawn) {
782 				quad_drawn = 40*hudscale;
783 			}
784 		}
785 		if(haste) {
786 			Draw_ScaledPic((int)(viddef.width/3) + rocketlauncher_drawn+chaingun_drawn+smartgun_drawn+beamgun_drawn+flamethrower_drawn+disruptor_drawn+vaporizer_drawn+quad_drawn
787 				, (int)(viddef.height/3.2), hudscale, "p_haste");
788 			if(!haste_drawn) {
789 				haste_drawn = 40*hudscale;
790 			}
791 		}
792 		if(sproing) {
793 			Draw_ScaledPic((int)(viddef.width/3) + rocketlauncher_drawn+chaingun_drawn+smartgun_drawn+beamgun_drawn+flamethrower_drawn+disruptor_drawn+vaporizer_drawn+quad_drawn+haste_drawn
794 				, (int)(viddef.height/3.2), hudscale, "p_sproing");
795 			if(!sproing_drawn) {
796 				sproing_drawn = 40*hudscale;
797 			}
798 		}
799 		if(inv) {
800 			Draw_ScaledPic((int)(viddef.width/3) + rocketlauncher_drawn+chaingun_drawn+smartgun_drawn+beamgun_drawn+flamethrower_drawn+disruptor_drawn+vaporizer_drawn+quad_drawn+haste_drawn+sproing_drawn
801 				, (int)(viddef.height/3.2), hudscale, "p_invulnerability");
802 			if(!inv_drawn) {
803 				inv_drawn = 40*hudscale;
804 			}
805 		}
806 		if(adren) {
807 			Draw_ScaledPic((int)(viddef.width/3) + rocketlauncher_drawn+chaingun_drawn+smartgun_drawn+beamgun_drawn+flamethrower_drawn+disruptor_drawn+vaporizer_drawn+quad_drawn+haste_drawn+sproing_drawn+inv_drawn
808 				, (int)(viddef.height/3.2), hudscale, "p_adrenaline");
809 		}
810 	}
811 	else
812 	{
813 		box.x = 0;
814 		box.y = ( viddef.height - font->size ) / 2;
815 		box.width = viddef.width;
816 		box.height = 0;
817 
818 		FNT_BoundedPrint( font , "Awaiting Connection ..." , FNT_CMODE_NONE , FNT_ALIGN_CENTER , &box , FNT_colors[ 7 ] );
819 	}
820 
821 	// Add Download info stuff...
822 	if (cls.download && ( (int)ftell( cls.download ) / 1024 ) != 0 )
823 	{
824 		if ( cls.key_dest != key_console ) //drop the console because of CURL's readout
825 		{
826 			CON_ToggleConsole();
827 		}
828 	}
829 	else if (isMap) //loading bar...
830 	{
831 		//to do - fix
832 		//SCR_DrawRotatingIcon();
833 
834 		SCR_DrawLoadingBar(loadingPercent, font->size);
835 
836 		box.x = 0;
837 		box.y = 2 + viddef.height / 2 + font->size * 6.3;
838 		box.width = viddef.width;
839 		box.height = 0;
840 
841 		FNT_BoundedPrint( font , va("%3d%%", (int)loadingPercent) , FNT_CMODE_NONE , FNT_ALIGN_CENTER , &box , FNT_colors[ 7 ] );
842 	}
843 }
844 
845 //=============================================================================
846 
847 /*
848 ==================
849 SCR_RunConsole
850 
851 Scroll it up or down
852 ==================
853 */
SCR_RunConsole(void)854 void SCR_RunConsole (void)
855 {
856 // decide on the height of the console
857 	if (cls.key_dest == key_console)
858 		scr_conlines = scr_consize->value;
859 	else
860 		scr_conlines = 0;				// none visible
861 
862 	if (scr_conlines < scr_con_current)
863 	{
864 		scr_con_current -= scr_conspeed->value*cls.frametime;
865 		if (scr_conlines > scr_con_current)
866 			scr_con_current = scr_conlines;
867 
868 	}
869 	else if (scr_conlines > scr_con_current)
870 	{
871 		scr_con_current += scr_conspeed->value*cls.frametime;
872 		if (scr_conlines < scr_con_current)
873 			scr_con_current = scr_conlines;
874 	}
875 
876 }
877 
878 /*
879 ==================
880 SCR_DrawConsole
881 ==================
882 */
883 float sendBubbleNow;
SCR_DrawConsole(void)884 void SCR_DrawConsole (void)
885 {
886 	if (cls.state == ca_disconnected || cls.state == ca_connecting)
887 	{	// forced full screen console
888 		CON_DrawConsole( scr_consize->value );
889 		return;
890 	}
891 
892 	if (cls.state != ca_active || !cl.refresh_prepped)
893 	{	// connected, but can't render
894 		CON_DrawConsole( scr_consize->value );
895 		Draw_Fill (0, viddef.height/2, viddef.width, viddef.height/2, RGBA(0,0,0,1));
896 		return;
897 	}
898 
899 	if (scr_con_current)
900 	{
901 		CON_DrawConsole( scr_con_current );
902 	}
903 	else
904 	{
905 		if (cls.key_dest == key_game || cls.key_dest == key_message)
906 			CON_DrawNotify ();	// only draw notify in game
907 	}
908 
909 	//draw chat bubble
910 	if(cls.key_dest == key_message || scr_con_current) {
911 		//only send this every couple of seconds no need to flood
912 		sendBubbleNow += cls.frametime;
913 		if(sendBubbleNow >= 1) {
914 			Cbuf_AddText("chatbubble\n");
915 			Cbuf_Execute ();
916 			sendBubbleNow = 0;
917 		}
918 	}
919 }
920 
921 //=============================================================================
922 
923 /*
924 ================
925 SCR_BeginLoadingPlaque
926 ================
927 */
needLoadingPlaque(void)928 qboolean needLoadingPlaque (void)
929 {
930 	if (!cls.disable_screen || !scr_draw_loading)
931 		return true;
932 	return false;
933 }
SCR_BeginLoadingPlaque(void)934 void SCR_BeginLoadingPlaque (void)
935 {
936 	S_StopAllSounds ();
937 	cl.sound_prepped = false;		// don't play ambients
938 
939 	scr_draw_loading = 1;
940 
941 	SCR_UpdateScreen ();
942 	cls.disable_screen = Sys_Milliseconds ();
943 	cls.disable_servercount = cl.servercount;
944 
945 }
946 
947 /*
948 ================
949 SCR_EndLoadingPlaque
950 ================
951 */
SCR_EndLoadingPlaque(void)952 void SCR_EndLoadingPlaque (void)
953 {
954 	cls.disable_screen = 0;
955 	scr_draw_loading = 0;
956 	CON_ClearNotify( );
957 
958 	Cvar_Set ("paused", "0");
959 }
960 
961 /*
962 ================
963 SCR_Loading_f
964 ================
965 */
SCR_Loading_f(void)966 void SCR_Loading_f (void)
967 {
968 	SCR_BeginLoadingPlaque ();
969 }
970 
entitycmpfnc(const entity_t * a,const entity_t * b)971 int entitycmpfnc( const entity_t *a, const entity_t *b )
972 {
973 	/*
974 	** all other models are sorted by model then skin
975 	*/
976 	if ( a->model == b->model )
977 	{
978 		return ( ( ptrdiff_t ) a->skin - ( ptrdiff_t ) b->skin );
979 	}
980 	else
981 	{
982 		return ( ( ptrdiff_t ) a->model - ( ptrdiff_t ) b->model );
983 	}
984 }
985 
986 /**
987  * @brief  Rendering performance test.
988  *
989  * Target of 'timerefresh' command. When invoked with an argument, end of
990  * frame flush and page flipping are not done. Modified 2011-02 with
991  * additional info in result. Use 'viewpos' (also modified) command
992  * for repeatable, consistent positioning.
993  *
994  * Modified 2012-12
995  */
SCR_TimeRefresh_f(void)996 void SCR_TimeRefresh_f( void )
997 {
998 	int   t_start, t_stop;
999 	float d_time;
1000 	float frames_per_sec;
1001 	float msec_per_frame;
1002 	float save_yaw;
1003 	int   frame_count;
1004 	float num_frames;
1005 	float yaw_increment;
1006 	float frame_yaw;
1007 	char  *cmd_arg;
1008 
1009 	if ( cls.state != ca_active )
1010 		return;
1011 
1012 	save_yaw    = cl.refdef.viewangles[YAW];
1013 	num_frames  = scr_timerefcount->value;
1014 	frame_count = scr_timerefcount->integer;
1015 	if ( frame_count < 1 || frame_count > 1440 )
1016 	{ // silently protect against unreasonable setting
1017 		num_frames = 128.0f;
1018 		frame_count = 128;
1019 	}
1020 	cmd_arg = Cmd_Argv(1);
1021 
1022 	switch ( *cmd_arg )
1023 	{
1024 	case '1': // rotate
1025 		yaw_increment = 360.0f / num_frames;
1026 		break;
1027 
1028 	case '2': // no rotate
1029 		yaw_increment = 0.0f;
1030 		break;
1031 
1032 	default:
1033 		Com_Printf("usage: timerefresh <arg>, 1=rotate,2=fixed\n");
1034 		return;
1035 	}
1036 
1037 	// show position
1038 	Com_Printf ("x:%#1.0f y:%#1.0f z:%#1.0f yaw:%#1.0f pitch:%#1.0f\n",
1039 		cl.refdef.vieworg[0], cl.refdef.vieworg[1], cl.refdef.vieworg[2],
1040 		cl.refdef.viewangles[YAW], cl.refdef.viewangles[PITCH] );
1041 
1042 	// test loop
1043 	frame_yaw = save_yaw;
1044 	t_start = Sys_Milliseconds();
1045 	while ( frame_count-- )
1046 	{
1047 		cl.refdef.viewangles[YAW] = frame_yaw;
1048 		R_BeginFrame( 0 );
1049 		R_RenderFrame( &cl.refdef );
1050 		R_EndFrame();
1051 		frame_yaw += yaw_increment;
1052 	}
1053 	t_stop = Sys_Milliseconds();
1054 
1055 	// restore original yaw (not included in test frame count)
1056 	cl.refdef.viewangles[YAW] = save_yaw;
1057 	R_BeginFrame( 0 );
1058 	R_RenderFrame( &cl.refdef );
1059 	R_EndFrame();
1060 
1061 	// report
1062 	d_time = (float)(t_stop - t_start);
1063 	d_time += 0.5f;
1064 	msec_per_frame = d_time / num_frames;
1065 	d_time /= 1000.0f;
1066 	frames_per_sec = num_frames / d_time;
1067 
1068 	Com_Printf( "%1.0f frames, %1.3f sec, %1.3f msec/frame, %1.1f FPS\n",
1069 			num_frames, d_time, msec_per_frame, frames_per_sec );
1070 
1071 }
1072 
1073 //===============================================================
1074 
1075 #define STAT_MINUS		10	// num frame for '-' stats digit
1076 char		*sb_nums[2][11] =
1077 {
1078 	{"num_0", "num_1", "num_2", "num_3", "num_4", "num_5",
1079 	"num_6", "num_7", "num_8", "num_9", "num_minus"},
1080 	{"anum_0", "anum_1", "anum_2", "anum_3", "anum_4", "anum_5",
1081 	"anum_6", "anum_7", "anum_8", "anum_9", "anum_minus"}
1082 };
1083 
1084 #define	ICON_WIDTH	24
1085 #define	ICON_HEIGHT	24
1086 #define	CHAR_WIDTH	16
1087 #define	ICON_SPACE	8
1088 
1089 
1090 
1091 /*
1092 ================
1093 SizeHUDString
1094 
1095 Allow embedded \n in the string
1096 ================
1097 */
SizeHUDString(char * string,int * w,int * h)1098 void SizeHUDString (char *string, int *w, int *h)
1099 {
1100 	int		lines, width, current;
1101 	int		charscale;
1102 
1103 	charscale = (float)(viddef.height)*8/600;
1104 	if(charscale < 8)
1105 		charscale = 8;
1106 
1107 	lines = 1;
1108 	width = 0;
1109 
1110 	current = 0;
1111 	while (*string)
1112 	{
1113 		if (*string == '\n')
1114 		{
1115 			lines++;
1116 			current = 0;
1117 		}
1118 		else
1119 		{
1120 			current++;
1121 			if (current > width)
1122 				width = current;
1123 		}
1124 		string++;
1125 	}
1126 
1127 	*w = width * charscale;
1128 	*h = lines * charscale;
1129 }
1130 
1131 /*
1132 ==============
1133 SCR_DrawField
1134 ==============
1135 */
SCR_DrawField(int x,int y,int color,int width,int value,float scale)1136 void SCR_DrawField (int x, int y, int color, int width, int value, float scale)
1137 {
1138 	char	num[16], *ptr;
1139 	int		l;
1140 	int		frame;
1141 
1142 	if (width < 1)
1143 		return;
1144 
1145 	// draw number string
1146 	if (width > 5)
1147 		width = 5;
1148 
1149 	Com_sprintf (num, sizeof(num), "%i", value);
1150 	l = strlen(num);
1151 	if (l > width)
1152 		l = width;
1153 	x += 2 + CHAR_WIDTH*(width - l)*scale;
1154 
1155 	ptr = num;
1156 	while (*ptr && l)
1157 	{
1158 		if (*ptr == '-')
1159 			frame = STAT_MINUS;
1160 		else
1161 			frame = *ptr -'0';
1162 
1163 		Draw_ScaledPic (x,y,scale/1.8,sb_nums[color][frame]);
1164 		x += CHAR_WIDTH*scale;
1165 		ptr++;
1166 		l--;
1167 	}
1168 }
1169 
1170 
1171 /*
1172 ===============
1173 SCR_TouchPics
1174 
1175 Allows rendering code to cache all needed sbar graphics
1176 ===============
1177 */
SCR_TouchPics(void)1178 void SCR_TouchPics (void)
1179 {
1180 	int		i, j;
1181 
1182 	for (i=0 ; i<2 ; i++)
1183 		for (j=0 ; j<11 ; j++)
1184 			R_RegisterPic (sb_nums[i][j]);
1185 
1186 	if (strcmp(crosshair->string, "none"))
1187 	{
1188 
1189 		Com_sprintf (crosshair_pic, sizeof(crosshair_pic), "%s", crosshair->string);
1190 		Draw_GetPicSize (&crosshair_width, &crosshair_height, crosshair_pic);
1191 		if (!crosshair_width)
1192 			crosshair_pic[0] = 0;
1193 	}
1194 }
1195 
1196 /*
1197 ================
1198 SCR_ExecuteLayoutString
1199 
1200 ================
1201 */
SCR_ExecuteLayoutString(char * s)1202 void SCR_ExecuteLayoutString (char *s)
1203 {
1204 	FNT_font_t		font;
1205 	struct FNT_window_s	box;
1206 	int			x, y, ny=0; //ny is coordinates used for new sb layout client tags only
1207 	int			value;
1208 	char *			token;
1209 	int			numwidth = 3; //amount of digits of number being drawn
1210 	int			index;
1211 	clientinfo_t *		ci;
1212 	int			charscale;
1213 	float			scale;
1214 	qboolean		newSBlayout = false;
1215 	int				left, top, right, bottom, width, height, midx, midy;
1216 
1217 	if (cls.state != ca_active || !cl.refresh_prepped)
1218 		return;
1219 
1220 	if (!s[0])
1221 		return;
1222 
1223 	font = FNT_AutoGet( CL_gameFont );
1224 	charscale = font->size;
1225 	scale = charscale * 0.125;
1226 
1227 	width = cl.refdef.width;
1228 	height = cl.refdef.height;
1229 
1230 	x = left = cl.refdef.x;
1231 	y = ny = top = cl.refdef.y;
1232 	right = left+width;
1233 	bottom = top+height;
1234 	midx = left+width/2;
1235 	midy = top+height/2;
1236 
1237 	if (width < 1024 || height < 768)
1238 	{
1239 		// Below 1024x768, start scaling things down to make sure everything
1240 		// fits. We scale x and y by the same amount to keep things square,
1241 		// but we figure out the ratios separately and use the ratio which
1242 		// results in the smallest scale.
1243 		float xscale, yscale;
1244 		xscale = (float)width/1024.0f;
1245 		yscale = (float)height/768.0f;
1246 		if (xscale < yscale)
1247 			scale *= xscale;
1248 		else
1249 			scale *= yscale;
1250 	}
1251 
1252 	while (s)
1253 	{
1254 		token = COM_Parse (&s);
1255 		if (!strcmp(token, "xl"))
1256 		{
1257 			token = COM_Parse (&s);
1258 			x = left + atoi(token)*scale;
1259 			continue;
1260 		}
1261 		if (!strcmp(token, "xr"))
1262 		{
1263 			token = COM_Parse (&s);
1264 			x = right + atoi(token)*scale;
1265 			continue;
1266 		}
1267 		if (!strcmp(token, "xv"))
1268 		{
1269 			token = COM_Parse (&s);
1270 			x = midx + (atoi(token) - 160)*scale;
1271 			continue;
1272 		}
1273 
1274 		if (!strcmp(token, "yt"))
1275 		{
1276 			token = COM_Parse (&s);
1277 			y = top + atoi(token)*scale;
1278 			continue;
1279 		}
1280 		if (!strcmp(token, "yb"))
1281 		{
1282 			token = COM_Parse (&s);
1283 			y = bottom + atoi(token)*scale;
1284 			continue;
1285 		}
1286 		if (!strcmp(token, "yv"))
1287 		{
1288 			token = COM_Parse (&s);
1289 			y = midy + (atoi(token) - 100)*scale;
1290 			ny = midy + (atoi(token)/2 - 100)*scale;
1291 			continue;
1292 		}
1293 
1294 		if (!strcmp(token, "pic"))
1295 		{	// draw a pic from a stat number
1296 			if(strcmp(cl_hudimage1->string, "none")) {
1297 				token = COM_Parse (&s);
1298 				value = cl.frame.playerstate.stats[atoi(token)];
1299 				if (value >= MAX_IMAGES)
1300 					Com_Error (ERR_DROP, "Pic >= MAX_IMAGES");
1301 				if( cl.configstrings[CS_IMAGES+value][0] )
1302 				{
1303 					Draw_ScaledPic (x, y, scale, cl.configstrings[CS_IMAGES+value]);
1304 					if(!strcmp(cl.configstrings[CS_IMAGES+value], "i_team1") ||
1305 						!strcmp(cl.configstrings[CS_IMAGES+value], "i_team2"))
1306 					{
1307 						r_gotFlag = false;
1308 						r_lostFlag = true;
1309 						Cvar_Set("rs_hasflag", "0");
1310 						if(!strcmp(cl.configstrings[CS_IMAGES+value], "i_team1"))
1311 							Cvar_Set("rs_team", "blue");
1312 						else
1313 							Cvar_Set("rs_team", "red");
1314 					}
1315 					else if(!strcmp(cl.configstrings[CS_IMAGES+value], "i_flag1") ||
1316 						!strcmp(cl.configstrings[CS_IMAGES+value], "i_flag2"))
1317 					{
1318 						r_gotFlag = true;
1319 						r_lostFlag = false;
1320 						Cvar_Set("rs_hasflag", "1");
1321 						if(!strcmp(cl.configstrings[CS_IMAGES+value], "i_flag1"))
1322 							Cvar_Set("rs_team", "blue");
1323 						else
1324 							Cvar_Set("rs_team", "red");
1325 					}
1326 				}
1327 			}
1328 
1329 			continue;
1330 		}
1331 
1332 		if (!strcmp(token, "newsb"))
1333 		{
1334 			//print header here
1335 			x = midx - 160*scale;
1336 			y = midy - 64*scale;
1337 
1338 			box.x = x + 4 * scale , box.y = y;
1339 			FNT_RawPrint( font , "Player" , 6 , false , box.x , box.y , FNT_colors[ 7 ] );
1340 			box.x += 160 * scale , box.width = 56 * scale , box.height = 0;
1341 			FNT_BoundedPrint( font , "Score" , FNT_CMODE_NONE , FNT_ALIGN_RIGHT , &box , FNT_colors[ 7 ] );
1342 			box.x += 56 * scale , box.width = 48 * scale , box.height = 0;
1343 			FNT_BoundedPrint( font , "Ping" , FNT_CMODE_NONE , FNT_ALIGN_RIGHT , &box , FNT_colors[ 7 ] );
1344 			box.x += 48 * scale , box.width = 48 * scale , box.height = 0;
1345 			FNT_BoundedPrint( font , "Time" , FNT_CMODE_NONE , FNT_ALIGN_RIGHT , &box , FNT_colors[ 7 ] );
1346 
1347 			newSBlayout = true;
1348 			continue;
1349 		}
1350 
1351 		if (!strcmp(token, "newctfsb"))
1352 		{
1353 			//print header here
1354 			x = midx - 256*scale;
1355 			y = midy - 72*scale;
1356 
1357 			while ( x <= midx ) {
1358 				box.x = x + 14 * scale , box.y = y;
1359 				FNT_RawPrint( font , "Player" , 6 , false , box.x , box.y , FNT_colors[ 7 ] );
1360 				box.x += 118 * scale , box.width = 56 * scale , box.height = 0;
1361 				FNT_BoundedPrint( font , "Score" , FNT_CMODE_NONE , FNT_ALIGN_RIGHT , &box , FNT_colors[ 7 ] );
1362 				box.x += 56 * scale , box.width = 48 * scale , box.height = 0;
1363 				FNT_BoundedPrint( font , "Ping" , FNT_CMODE_NONE , FNT_ALIGN_RIGHT , &box , FNT_colors[ 7 ] );
1364 				x += 256 * scale;
1365 			}
1366 
1367 			newSBlayout = true;
1368 			continue;
1369 		}
1370 
1371 		if (!strcmp(token, "client") || !strcmp(token, "queued"))
1372 		{	// draw a deathmatch client block
1373 			qboolean	isQueued = ( token[ 0 ] == 'q' );
1374 			int		score, ping, time;
1375 			const char *	timeMessage;
1376 			int		timeColor;
1377 
1378 			token = COM_Parse (&s);
1379 			x = midx + (atoi(token) - 160)*scale;
1380 			token = COM_Parse (&s);
1381 			if(newSBlayout)
1382 				y = midy + (atoi(token)/2 - 100)*scale;
1383 			else
1384 				y = midy + (atoi(token) - 100)*scale;
1385 
1386 			token = COM_Parse (&s);
1387 			value = atoi(token);
1388 			if (value >= MAX_CLIENTS || value < 0)
1389 				Com_Error (ERR_DROP, "client >= MAX_CLIENTS");
1390 			ci = &cl.clientinfo[value];
1391 
1392 			token = COM_Parse (&s);
1393 			score = atoi(token);
1394 
1395 			token = COM_Parse (&s);
1396 			ping = atoi(token);
1397 
1398 			token = COM_Parse (&s);
1399 			time = atoi(token);
1400 
1401 			if ( isQueued ) {
1402 				COM_Parse (&s);
1403 				timeMessage = "Queue:";
1404 				timeColor = 1;
1405 			} else {
1406 				timeMessage = "Time:";
1407 				timeColor = 7;
1408 			}
1409 
1410 			if(newSBlayout) { //new scoreboard layout
1411 
1412 				box.x = x + 4 * scale , box.y = y + 34 * scale;
1413 				box.width = 160 * scale , box.height = 0;
1414 				FNT_BoundedPrint( font , ci->name , FNT_CMODE_QUAKE_SRS , FNT_ALIGN_LEFT , &box , FNT_colors[ 2 ] );
1415 				box.x += 160 * scale , box.width = 56 * scale , box.height = 0;
1416 				FNT_BoundedPrint( font , va( "%i" , score ) , FNT_CMODE_NONE , FNT_ALIGN_RIGHT , &box , FNT_colors[ 2 ] );
1417 				box.x += 56 * scale , box.width = 48 * scale , box.height = 0;
1418 				FNT_BoundedPrint( font , va( "%i" , ping ) , FNT_CMODE_NONE , FNT_ALIGN_RIGHT , &box , FNT_colors[ 7 ] );
1419 				box.x += 48 * scale , box.width = 48 * scale , box.height = 0;
1420 				FNT_BoundedPrint( font , va( "%i" , time ) , FNT_CMODE_QUAKE , FNT_ALIGN_RIGHT , &box , FNT_colors[ timeColor ] );
1421 			}
1422 			else
1423 			{
1424 				box.x = x + 32 * scale , box.y = y;
1425 				box.width = 288 * scale , box.height = 0;
1426 				FNT_BoundedPrint( font , ci->name , FNT_CMODE_QUAKE_SRS , FNT_ALIGN_LEFT , &box , FNT_colors[ 2 ] );
1427 
1428 				box.y += 8 * scale;
1429 				box.width = 100 * scale , box.height = 0;
1430 				FNT_BoundedPrint( font , "Score:" , FNT_CMODE_NONE , FNT_ALIGN_LEFT , &box , FNT_colors[ 7 ] );
1431 				box.x += box.width;
1432 				box.width = 100 * scale - box.width , box.height = 0;
1433 				FNT_BoundedPrint( font , va( "%i" , score ) , FNT_CMODE_NONE , FNT_ALIGN_RIGHT , &box , FNT_colors[ 2 ] );
1434 
1435 				box.y += 8 * scale , box.x = x + 32 * scale;
1436 				box.width = 100 * scale , box.height = 0;
1437 				FNT_BoundedPrint( font , "Ping:" , FNT_CMODE_NONE , FNT_ALIGN_LEFT , &box , FNT_colors[ 7 ] );
1438 				box.x += box.width;
1439 				box.width = 100 * scale - box.width , box.height = 0;
1440 				FNT_BoundedPrint( font , va( "%i" , ping ) , FNT_CMODE_NONE , FNT_ALIGN_RIGHT , &box , FNT_colors[ 7 ] );
1441 
1442 				box.y += 8 * scale , box.x = x + 32 * scale;
1443 				box.width = 100 * scale , box.height = 0;
1444 				FNT_BoundedPrint( font , timeMessage , FNT_CMODE_NONE , FNT_ALIGN_LEFT , &box , FNT_colors[ timeColor ] );
1445 				box.x += box.width;
1446 				box.width = 100 * scale - box.width , box.height = 0;
1447 				FNT_BoundedPrint( font , va( "%i" , time ) , FNT_CMODE_NONE , FNT_ALIGN_RIGHT , &box , FNT_colors[ timeColor ] );
1448 
1449 				if (!ci->icon)
1450 					ci = &cl.baseclientinfo;
1451 				Draw_ScaledPic (x, y, scale/2, ci->iconname);
1452 			}
1453 
1454 			continue;
1455 		}
1456 		if (!strcmp(token, "ctf"))
1457 		{	// draw a ctf client block
1458 			int	score, ping;
1459 			char	block[80];
1460 			int		team;
1461 
1462 			token = COM_Parse (&s);
1463 			x = midx + (atoi(token) - 160)*scale;
1464 			if(atoi(token) < 0)
1465 				team = 0;
1466 			else
1467 				team = 1;
1468 			token = COM_Parse (&s);
1469 			y = midy + (atoi(token) - 100)*scale;
1470 
1471 			token = COM_Parse (&s);
1472 			value = atoi(token);
1473 			if (value >= MAX_CLIENTS || value < 0)
1474 				Com_Error (ERR_DROP, "client >= MAX_CLIENTS");
1475 			ci = &cl.clientinfo[value];
1476 
1477 			token = COM_Parse (&s);
1478 			score = atoi(token);
1479 
1480 			token = COM_Parse (&s);
1481 			ping = atoi(token);
1482 			if (ping > 999)
1483 				ping = 999;
1484 
1485 			if(newSBlayout) {
1486 				box.x = x + 14 * scale , box.y = y + 2 * scale;
1487 				box.width = 118 * scale , box.height = 0;
1488 				FNT_BoundedPrint( font , ci->name , FNT_CMODE_QUAKE_SRS , FNT_ALIGN_LEFT , &box , FNT_colors[ 2 ] );
1489 				box.x += 120 * scale , box.width = 56 * scale , box.height = 0;
1490 				FNT_BoundedPrint( font , va( "%i" , score ) , FNT_CMODE_NONE , FNT_ALIGN_RIGHT , &box , FNT_colors[ 2 ] );
1491 				box.x += 56 * scale , box.width = 48 * scale , box.height = 0;
1492 				FNT_BoundedPrint( font , va( "%i" , ping ) , FNT_CMODE_NONE , FNT_ALIGN_RIGHT , &box , FNT_colors[ 7 ] );
1493 
1494 				if(team) { //draw pic on left side(done client side to save packetsize
1495 					Draw_ScaledPic (x, y-2*scale, scale, "/pics/blueplayerbox");
1496 				}
1497 				else
1498 					Draw_ScaledPic(x, y-2*scale, scale, "/pics/redplayerbox");
1499 			}
1500 			else {
1501 				sprintf(block, "%3d %3d %s", score, ping, ci->name);
1502 				box.x = x , box.y = y , box.width = 256 , box.height = 0;
1503 				FNT_BoundedPrint( font , block , FNT_CMODE_QUAKE_SRS , FNT_ALIGN_LEFT , &box , FNT_colors[ 2 ] );
1504 			}
1505 
1506 			continue;
1507 		}
1508 
1509 		if (!strcmp(token, "picn"))
1510 		{	// draw a pic from a name
1511 			token = COM_Parse (&s);
1512 			if(newSBlayout && !strcmp(token, "playerbox")) { //cannot simply fill y = ny here
1513 				Draw_ScaledPic (x, ny+32*scale, scale, token);
1514 			}
1515 			else {
1516 				Draw_ScaledPic (x, y, scale, token);
1517 			}
1518 			continue;
1519 		}
1520 
1521 		if (!strcmp(token, "num"))
1522 		{	// draw a number
1523 			if(strcmp(cl_hudimage1->string, "none")) {
1524 				token = COM_Parse (&s);
1525 				numwidth = atoi(token);
1526 				token = COM_Parse (&s);
1527 				value = cl.frame.playerstate.stats[atoi(token)];
1528 				SCR_DrawField (x, y, 0, numwidth, value, scale);
1529 			}
1530 
1531 			continue;
1532 		}
1533 
1534 		if (!strcmp(token, "hnum"))
1535 		{	// health number
1536 			if(strcmp(cl_hudimage1->string, "none")) {
1537 				int		color;
1538 
1539 				numwidth = 3;
1540 				value = cl.frame.playerstate.stats[STAT_HEALTH];
1541 				if (value > 25)
1542 					color = 0;	// green
1543 				else if (value > 0)
1544 					color = (cl.frame.serverframe>>2) & 1;		// flash
1545 				else
1546 					color = 1;
1547 
1548 				SCR_DrawField (x, y, color, numwidth, value, scale);
1549 			}
1550 
1551 			//draw the zoom scope pic if we are using the zoom alt-fire of disruptor
1552 			if (cl.frame.playerstate.stats[STAT_ZOOMED])
1553 			{
1554 				char zoompic[32];
1555 				sprintf(zoompic, "zoomscope%i", cl.frame.playerstate.stats[STAT_ZOOMED]);
1556 				Draw_StretchPic (left, top, width, height, zoompic);
1557 			}
1558 
1559 			continue;
1560 		}
1561 
1562 		if (!strcmp(token, "anum"))
1563 		{	// ammo number
1564 			if(strcmp(cl_hudimage1->string, "none")) {
1565 				int		color;
1566 
1567 				numwidth = 3;
1568 				value = cl.frame.playerstate.stats[STAT_AMMO];
1569 				if (value > 5)
1570 					color = 0;	// green
1571 				else if (value >= 0)
1572 					color = (cl.frame.serverframe>>2) & 1;		// flash
1573 				else
1574 					continue;	// negative number = don't show
1575 
1576 				SCR_DrawField (x, y, color, numwidth, value, scale);
1577 			}
1578 
1579 			continue;
1580 		}
1581 
1582 		if (!strcmp(token, "rnum"))
1583 		{	// armor number
1584 			if(strcmp(cl_hudimage1->string, "none")) {
1585 				int		color;
1586 
1587 				numwidth = 3;
1588 				value = cl.frame.playerstate.stats[STAT_ARMOR];
1589 				if (value < 1)
1590 					continue;
1591 
1592 				color = 0;	// green
1593 
1594 				SCR_DrawField (x, y, color, numwidth, value, scale);
1595 			}
1596 
1597 			continue;
1598 		}
1599 
1600 
1601 		if (!strcmp(token, "stat_string"))
1602 		{
1603 			token = COM_Parse (&s);
1604 			index = atoi(token);
1605 			if (index < 0 || index >= MAX_CONFIGSTRINGS)
1606 				Com_Error (ERR_DROP, "Bad stat_string index");
1607 			index = cl.frame.playerstate.stats[index];
1608 			if (index < 0 || index >= MAX_CONFIGSTRINGS)
1609 				Com_Error (ERR_DROP, "Bad stat_string index");
1610 
1611 			FNT_RawPrint( font , cl.configstrings[index] , strlen( cl.configstrings[index] ) ,
1612 				false , x , y , FNT_colors[ 7 ] );
1613 			continue;
1614 		}
1615 
1616 		if (!strcmp(token, "cstring"))
1617 		{
1618 			token = COM_Parse (&s);
1619 			box.width = 2*(x>midx?(right-x):x);
1620 			box.x = x-box.width/2;
1621 			box.y = y;
1622 			box.height = 0;
1623 			FNT_BoundedPrint( font , token , FNT_CMODE_NONE , FNT_ALIGN_CENTER , &box , FNT_colors[ 7 ] );
1624 			continue;
1625 		}
1626 
1627 		if (!strcmp(token, "string"))
1628 		{
1629 			token = COM_Parse (&s);
1630 			//this line is an Alien Arena specific hack of sorts, remove if needed
1631 			if(!strcmp(token, "Vote"))
1632 				Draw_ScaledPic (midx - 85*scale, y-8*scale, scale, "votebox");
1633 			FNT_RawPrint( font , token , strlen( token ) , false , x , y , FNT_colors[ 7 ] );
1634 			continue;
1635 		}
1636 
1637 		if (!strcmp(token, "cstring2"))
1638 		{
1639 			token = COM_Parse (&s);
1640 			box.width = 2*(x>midx?(right-x):x);
1641 			box.x = x-box.width/2;
1642 			box.y = y;
1643 			box.height = 0;
1644 			FNT_BoundedPrint( font , token , FNT_CMODE_NONE , FNT_ALIGN_CENTER , &box , FNT_colors[ 3 ] );
1645 			continue;
1646 		}
1647 
1648 		if (!strcmp(token, "string2"))
1649 		{
1650 			token = COM_Parse (&s);
1651 			FNT_RawPrint( font , token , strlen( token ) , false , x , y , FNT_colors[ 7 ] );
1652 			continue;
1653 		}
1654 
1655 		if (!strcmp(token, "if"))
1656 		{	// draw a number
1657 			token = COM_Parse (&s);
1658 			value = cl.frame.playerstate.stats[atoi(token)];
1659 			if (!value)
1660 			{	// skip to endif
1661 				while (s && strcmp(token, "endif") )
1662 				{
1663 					token = COM_Parse (&s);
1664 				}
1665 			}
1666 
1667 			continue;
1668 		}
1669 	}
1670 }
1671 
1672 
1673 /*
1674 ================
1675 SCR_DrawStats
1676 
1677 The status bar is a small layout program that
1678 is based on the stats array
1679 ================
1680 */
SCR_DrawStats(void)1681 void SCR_DrawStats (void)
1682 {
1683 	SCR_ExecuteLayoutString (cl.configstrings[CS_STATUSBAR]);
1684 }
1685 
1686 
1687 /*
1688 ================
1689 SCR_DrawLayout
1690 
1691 ================
1692 */
1693 #define	STAT_LAYOUTS		13
1694 
SCR_DrawLayout(void)1695 void SCR_DrawLayout (void)
1696 {
1697 	if (!cl.frame.playerstate.stats[STAT_LAYOUTS])
1698 		return;
1699 	SCR_ExecuteLayoutString (cl.layout);
1700 }
1701 
1702 /*
1703 =================
1704 SCR_DrawPlayerIcon
1705 =================
1706 */
1707 char		scr_playericon[MAX_OSPATH];
1708 char		scr_playername[PLAYERNAME_SIZE];
1709 float		scr_playericonalpha;
SCR_DrawPlayerIcon(void)1710 void SCR_DrawPlayerIcon(void) {
1711 	FNT_font_t		font;
1712 	struct FNT_window_s	box;
1713 	int			w, h;
1714 	float			scale, iconPos;
1715 
1716 	if (cls.key_dest == key_menu || cls.key_dest == key_console)
1717 		return;
1718 
1719 	if(scr_playericonalpha <= 0.0)
1720 		return;
1721 
1722 	scr_playericonalpha -= cls.frametime; //fade map pic in
1723 
1724 	if(scr_playericonalpha < 1.0)
1725 		iconPos = scr_playericonalpha;
1726 	else
1727 		iconPos = 1.0;
1728 
1729 	scale = (float)(viddef.height)/600;
1730 	if(scale < 1)
1731 		scale = 1;
1732 
1733 	w = h = 64; //icon size, will change to be larger
1734 
1735 	w*=scale;
1736 	h*=scale;
1737 
1738 	Draw_AlphaStretchPlayerIcon( -w+(w*iconPos), viddef.height/2 + h/2, w, h, scr_playericon, scr_playericonalpha);
1739 
1740 	font = FNT_AutoGet( CL_gameFont );
1741 	box.x = -w+(w*iconPos);
1742 	box.y = viddef.height/2 + h + 32*scale;
1743 	box.width = viddef.width - box.x;
1744 	box.height = 0;
1745 	FNT_BoundedPrint( font , scr_playername , FNT_CMODE_QUAKE , FNT_ALIGN_LEFT , &box , FNT_colors[ 2 ] );
1746 }
1747 
1748 /*
1749 ================
1750 
1751 SCR_showTimer
1752 
1753 ================
1754 */
1755 int	seconds, minutes;
SCR_showTimer(void)1756 void SCR_showTimer(void)
1757 {
1758 	static char		temptime[ 32 ];
1759 	static int		timecounter;
1760 	FNT_font_t		font;
1761 
1762 	if (cls.key_dest == key_menu || cls.key_dest == key_console)
1763 		return;
1764 
1765 	if ((cls.realtime + 2000) < timecounter)
1766 		timecounter = cl.time + 1000;
1767 
1768 	if (cls.realtime > timecounter)
1769 	{
1770 		seconds += 1;
1771 		if(seconds >= 60) {
1772 			minutes++;
1773 			seconds = 0;
1774 		}
1775 		Com_sprintf(temptime, sizeof(temptime),"%i:%2.2i", minutes, seconds);
1776 		timecounter = cls.realtime + 1000;
1777 	}
1778 
1779 	font = FNT_AutoGet( CL_gameFont );
1780 	Draw_StretchPic( viddef.width - 13 * font->size , viddef.height - 5.25 * font->size , 4 * font->size , 4 * font->size , "timer");
1781 	FNT_RawPrint( font , temptime , strlen( temptime ) , false ,
1782 		viddef.width - 8 * font->size , viddef.height - 3.75 * font->size , FNT_colors[ 7 ] );
1783 }
1784 
1785 /*
1786 ================
1787 
1788 SCR_showPerfTest
1789 
1790 ================
1791 */
1792 
get_perftest(char * name)1793 perftest_t *get_perftest(char *name) {
1794     int         i;
1795     perftest_t  *test = NULL;
1796 
1797     for (i = 0; i < MAX_PERFTESTS; i++) {
1798         if (!perftests[i].in_use) {
1799             test = &perftests[i];
1800             break;
1801         }
1802         if (!strncmp(perftests[i].name, name, sizeof(perftests[i].name)))
1803             return &perftests[i];
1804     }
1805 
1806     if (!test)
1807         return NULL; //remember to handle this in your code!
1808 
1809     memset(test, 0, sizeof(perftest_t));
1810 
1811     test->in_use = true;
1812     strncpy (test->name, name, sizeof(test->name));
1813 
1814     return test;
1815 }
1816 
1817 //slotnum is used for the vertical offset on the screen
SCR_showPerfTest(perftest_t * test,int slotnum)1818 void SCR_showPerfTest (perftest_t *test, int slotnum) {
1819 	FNT_font_t		font;
1820 	int			    end_msec;
1821 	float			time_sec;
1822 	float			rate;
1823 	int				height;
1824 
1825 	if (!test->in_use)
1826 	    return;
1827 
1828 	if (cls.key_dest == key_menu || cls.key_dest == key_console || !test->cvar->integer) {
1829 		test->restart = true;
1830 		return;
1831 	}
1832 
1833 	if (test->restart) {
1834 	    test->start_msec = Sys_Milliseconds();
1835 	    test->counter = 0.0f;
1836 	    test->framecounter = 0.0f;
1837 	    test->update_trigger = 10.0f; //initial delay to update
1838 	    test->text[0] = 0; //blank the text buffer
1839 	    test->restart = false;
1840 	    return;
1841 	}
1842 
1843 	test->framecounter += 1.0f;
1844 	if (test->framecounter >= test->update_trigger) {
1845 	    end_msec = Sys_Milliseconds();
1846         time_sec = ((float)(end_msec - test->start_msec)) / 1000.0f;
1847 	    if (test->is_timerate) {
1848 	        //calculate rate to display
1849 	        rate = test->scale * test->counter / time_sec;
1850 	    } else {
1851 	        rate = test->scale * test->counter;
1852 	    }
1853 
1854 	    //update text buffer for display
1855 	    Com_sprintf( test->text, sizeof(test->text), test->format, rate );
1856 
1857 	    test->start_msec = end_msec;
1858 	    if (test->is_timerate)
1859 	        //setup for next update - 0.25 sec update interval
1860 	        test->update_trigger = test->framecounter / (4.0 * time_sec);
1861 	    else
1862 	        //0.05 sec update interval
1863 	        test->update_trigger = test->framecounter / (20.0 * time_sec);
1864 	    test->framecounter = 0.0f;
1865 	    test->counter = 0.0f;
1866 	}
1867 
1868 	font = FNT_AutoGet( CL_gameFont );
1869 
1870 	height = viddef.height - 2.0 * font->size * (slotnum + 1);
1871 	if (cl_drawtimer->integer)
1872 		height -= 5.25 * font->size;
1873 	FNT_RawPrint( font , test->text , strlen( test->text ) , false ,
1874 		viddef.width - 8 * font->size , height, FNT_colors[ 2 ] );
1875 }
1876 
SCR_showAllPerfTests(void)1877 void SCR_showAllPerfTests (void) {
1878     int i, testsDrawn;
1879     for (i = 0, testsDrawn = 0; i < MAX_PERFTESTS; i++) {
1880         if (perftests[i].in_use && perftests[i].cvar->integer) {
1881             SCR_showPerfTest (&perftests[i], testsDrawn);
1882             testsDrawn++;
1883         }
1884     }
1885 }
1886 
SCR_showFPS(void)1887 void SCR_showFPS(void)
1888 {
1889     static perftest_t *test = NULL;
1890     if (!test) {
1891         test = get_perftest("fps");
1892         if (!test)
1893             return; //couldn't acquire test
1894         test->cvar = cl_drawfps;
1895         test->is_timerate = true;
1896         strcpy (test->format, "%3.0ffps");
1897         test->scale = 1.0f;
1898     }
1899 
1900     test->counter += 1.0f;
1901 
1902 }
1903 
1904 // Shows kilobytes per second from the server
1905 extern int c_incoming_bytes;
SCR_showBandwidth(void)1906 void SCR_showBandwidth (void) {
1907     static perftest_t *test = NULL;
1908     if (!test) {
1909         test = get_perftest("bandwidth");
1910         if (!test)
1911             return; //couldn't acquire test
1912         test->is_timerate = true;
1913         test->cvar = cl_drawbandwidth;
1914         strcpy (test->format, "%2.2fkibps");
1915         test->scale = 1.0f/1024.0f; //the SI is wrong, it's 1024
1916     }
1917 
1918     test->counter += c_incoming_bytes;
1919     c_incoming_bytes = 0;
1920 }
1921 
1922 // Shows number of frames per second which took longer than a configurable
1923 // amount of milliseconds. This is a useful measure of jitter, which isn't
1924 // usually reflected in average FPS rates but which can still be visually
1925 // annoying.
SCR_showFramesOver(void)1926 void SCR_showFramesOver (void) {
1927     static perftest_t *test = NULL;
1928     static int old_milliseconds = 0;
1929     int new_milliseconds;
1930     if (!test) {
1931         test = get_perftest("framesover");
1932         if (!test)
1933             return; //couldn't acquire test
1934         test->is_timerate = true;
1935         test->cvar = cl_drawframesover;
1936         strcpy (test->format, "%3.0fjfps"); //jfps = jitter frames per second
1937         test->scale = 1.0f;
1938         old_milliseconds = Sys_Milliseconds();
1939     }
1940 
1941     new_milliseconds = Sys_Milliseconds();
1942     if ((new_milliseconds - old_milliseconds) > cl_drawframesover->integer)
1943     	test->counter++;
1944     old_milliseconds = new_milliseconds;
1945 }
1946 
1947 /**
1948  *
1949  * @brief Construct map-maker's "r_speed" performance counter displays
1950  *
1951  * the traditional r_speeds cvar is replaced by individual counter cvars,
1952  *  named "rspeed_*"
1953  */
show_rspeed_helper(cvar_t * test_cvar,perftest_t * test_obj,char * test_name,char * test_format,int test_counter)1954 static void show_rspeed_helper(
1955 	cvar_t*     test_cvar,
1956 	perftest_t* test_obj,
1957 	char*       test_name,
1958 	char*       test_format,
1959 	int         test_counter
1960 	)
1961 {
1962 	if ( test_cvar && test_cvar->integer )
1963 	{
1964 		if ( test_obj == NULL )
1965 		{ /* constructor */
1966 			test_obj = get_perftest( test_name );
1967 			if ( test_obj != NULL )
1968 			{ /* slot allocated, construct */
1969 				test_obj->is_timerate = false;
1970 				test_obj->cvar = test_cvar;
1971 				strcpy( test_obj->format, test_format );
1972 				test_obj->scale = 1.0f;
1973 				test_obj->counter = test_counter;
1974 			}
1975 			else
1976 			{ /* no slot, force disable */
1977 				(void)Cvar_ForceSet( test_cvar->name, "0" );
1978 			}
1979 		}
1980 		else
1981 		{ /* running, update counter from refresh counter */
1982 			test_obj->counter = test_counter;
1983 		}
1984 	}
1985 }
1986 
SCR_showRSpeeds(void)1987 void SCR_showRSpeeds( void )
1988 {
1989 	static perftest_t *test_wpoly    = NULL;
1990 	static perftest_t *test_epoly    = NULL;
1991 	static perftest_t *test_flares   = NULL;
1992 	static perftest_t *test_grasses  = NULL;
1993 	static perftest_t *test_beams    = NULL;
1994 	static perftest_t *test_vbobatches = NULL;
1995 	static perftest_t *test_particles = NULL;
1996 
1997 	show_rspeed_helper( rspeed_wpolys, test_wpoly,
1998 			"wpolys", "%5.0f wpolys", c_brush_polys );
1999 
2000 	show_rspeed_helper( rspeed_epolys, test_epoly,
2001 			"epolys", "%5.0f epolys", c_alias_polys );
2002 
2003 	show_rspeed_helper( rspeed_flares, test_flares,
2004 			"flares", "%5.0f flares", c_flares );
2005 
2006 	show_rspeed_helper( rspeed_grasses, test_grasses,
2007 			"grasses", "%5.0f grasses", c_grasses );
2008 
2009 	show_rspeed_helper( rspeed_beams, test_beams,
2010 			"beams", "%5.0f beams", c_beams );
2011 
2012 	show_rspeed_helper( rspeed_vbobatches, test_vbobatches,
2013 			"vbobatches", "%5.0f vbobatches", c_vbo_batches );
2014 
2015 	show_rspeed_helper( rspeed_particles, test_particles,
2016 			"particles", "%5.0f particles", cl.refdef.num_particles );
2017 
2018 }
2019 
2020 /*
2021 ==================
2022 SCR_UpdateScreen
2023 
2024 This is called every frame, and can also be called explicitly to flush
2025 text to the screen.
2026 ==================
2027 */
SCR_UpdateScreen(void)2028 void SCR_UpdateScreen (void)
2029 {
2030 	int numframes;
2031 	int i;
2032 	float separation[2] = { 0, 0 };
2033 
2034 	// if the screen is disabled (loading plaque is up, or vid mode changing)
2035 	// do nothing at all
2036 	if (cls.disable_screen)
2037 	{
2038 		if (Sys_Milliseconds() - cls.disable_screen > 120000)
2039 		{
2040 			cls.disable_screen = 0;
2041 			Com_Printf ("Loading plaque timed out.\n");
2042 			return;
2043 		}
2044 		scr_draw_loading = 2;
2045 	}
2046 
2047 
2048 	if (!scr_initialized)
2049 		return;				// not initialized yet
2050 
2051 	/*
2052 	** range check cl_camera_separation so we don't inadvertently fry someone's
2053 	** brain
2054 	*/
2055 	if ( cl_stereo_separation->value > 1.0 )
2056 		Cvar_SetValue( "cl_stereo_separation", 1.0 );
2057 	else if ( cl_stereo_separation->value < 0 )
2058 		Cvar_SetValue( "cl_stereo_separation", 0.0 );
2059 
2060 	if ( cl_stereo->value )
2061 	{
2062 		numframes = 2;
2063 		separation[0] = -cl_stereo_separation->value / 2;
2064 		separation[1] =  cl_stereo_separation->value / 2;
2065 	}
2066 	else
2067 	{
2068 		separation[0] = 0;
2069 		separation[1] = 0;
2070 		numframes = 1;
2071 	}
2072 
2073 	for ( i = 0; i < numframes; i++ )
2074 	{
2075 		R_BeginFrame( separation[i] );
2076 
2077 		if (scr_draw_loading == 2)
2078 		{	//  loading plaque over black screen
2079 
2080 			SCR_DrawLoading ();
2081 
2082 			if (cls.disable_screen)
2083 				scr_draw_loading = 2;
2084 
2085 			//NO CONSOLE!!!
2086 			continue;
2087 		}
2088 		else
2089 		{
2090 			// do 3D refresh drawing, and then update the screen
2091 			SCR_CalcVrect ();
2092 
2093 			need_free_vbo = true;
2094 
2095 			V_RenderView ( separation[i] );
2096 
2097 			SCR_DrawStats ();
2098 			if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 1)
2099 				SCR_DrawLayout ();
2100 			if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 2)
2101 				CL_DrawInventory ();
2102 
2103 			SCR_DrawNet ();
2104 			SCR_CheckDrawCenterString ();
2105 			SCR_CheckDrawIRCString();
2106 
2107 			if (scr_timegraph->value)
2108 				SCR_DebugGraph (cls.frametime*600, RGBA(0,0,0,1));
2109 
2110 			if (scr_debuggraph->value || scr_timegraph->value || scr_netgraph->value)
2111 				SCR_DrawDebugGraph ();
2112 
2113 			SCR_DrawPause ();
2114 
2115 			SCR_DrawConsole ();
2116 
2117 			if (need_free_vbo)
2118 				R_VCFreeFrame();
2119 
2120 			M_Draw ();
2121 
2122 			SCR_DrawLoading ();
2123 
2124 			if(cl_drawfps->integer)
2125 			{
2126 				SCR_showFPS();
2127 			}
2128 
2129 			if(cl_drawbandwidth->integer)
2130 			{
2131 				SCR_showBandwidth();
2132 			}
2133 
2134 			if(cl_drawframesover->integer)
2135 			{
2136 				SCR_showFramesOver();
2137 			}
2138 
2139 			SCR_showRSpeeds(); /* map-maker's performance counters */
2140 
2141 			SCR_showAllPerfTests();
2142 
2143 			if(cl_drawtimer->integer)
2144 			{
2145 				SCR_showTimer();
2146 			}
2147 			SCR_DrawPlayerIcon();
2148 		}
2149 	}
2150 	R_EndFrame();
2151 }
2152