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