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 #include "client.h"
23
24 qboolean scr_initialized; // ready to draw
25
26 vrect_t scr_vrect; // position of render window on screen
27
28 glconfig_t scr_glconfig;
29
30
31 cvar_t *scr_viewsize;
32 cvar_t *scr_centertime;
33 cvar_t *scr_showpause;
34 cvar_t *scr_printspeed;
35
36 cvar_t *scr_netgraph;
37 cvar_t *scr_timegraph;
38 cvar_t *scr_debuggraph;
39 cvar_t *scr_graphheight;
40 cvar_t *scr_graphscale;
41 cvar_t *scr_graphshift;
42 cvar_t *scr_demobar;
43 cvar_t *scr_fontvar;
44 cvar_t *scr_scale;
45
46 cvar_t *crosshair;
47
48 qhandle_t crosshair_pic;
49 int crosshair_width, crosshair_height;
50
51 qhandle_t scr_backtile;
52 qhandle_t scr_pause;
53 qhandle_t scr_net;
54 qhandle_t scr_font;
55
56 int scr_hudWidth;
57 int scr_hudHeight;
58
59 #define STAT_MINUS 10 // num frame for '-' stats digit
60
61 static const char *sb_nums[2][11] = {
62 { "num_0", "num_1", "num_2", "num_3", "num_4", "num_5",
63 "num_6", "num_7", "num_8", "num_9", "num_minus" },
64 { "anum_0", "anum_1", "anum_2", "anum_3", "anum_4", "anum_5",
65 "anum_6", "anum_7", "anum_8", "anum_9", "anum_minus" }
66 };
67
68 static qhandle_t sb_pics[2][11];
69 static qhandle_t sb_inventory;
70 static qhandle_t sb_field;
71
72 #define ICON_WIDTH 24
73 #define ICON_HEIGHT 24
74 #define CHAR_WIDTH 16
75 #define ICON_SPACE 8
76
77 void SCR_TimeRefresh_f (void);
78 void SCR_Loading_f (void);
79
80
81 /*
82 ===============================================================================
83
84 BAR GRAPHS
85
86 ===============================================================================
87 */
88
89 /*
90 ==============
91 CL_AddNetgraph
92
93 A new packet was just parsed
94 ==============
95 */
CL_AddNetgraph(void)96 void CL_AddNetgraph (void)
97 {
98 int i;
99 int in;
100 int ping;
101
102 // if using the debuggraph for something else, don't
103 // add the net lines
104 if (scr_debuggraph->integer || scr_timegraph->integer)
105 return;
106
107 for (i=0 ; i<cls.netchan->dropped ; i++)
108 SCR_DebugGraph (30, 0x40);
109
110 for (i=0 ; i<cl.surpressCount ; i++)
111 SCR_DebugGraph (30, 0xdf);
112
113 // see what the latency was on this packet
114 in = cls.netchan->incoming_acknowledged & CMD_MASK;
115 ping = cls.realtime - cl.history[in].realtime;
116 ping /= 30;
117 if (ping > 30)
118 ping = 30;
119 SCR_DebugGraph (ping, 0xd0);
120 }
121
122
123 typedef struct
124 {
125 float value;
126 int color;
127 } graphsamp_t;
128
129 static int current;
130 static graphsamp_t values[1024];
131
132 /*
133 ==============
134 SCR_DebugGraph
135 ==============
136 */
SCR_DebugGraph(float value,int color)137 void SCR_DebugGraph (float value, int color)
138 {
139 values[current&1023].value = value;
140 values[current&1023].color = color;
141 current++;
142 }
143
144 /*
145 ==============
146 SCR_DrawDebugGraph
147 ==============
148 */
SCR_DrawDebugGraph(void)149 void SCR_DrawDebugGraph (void)
150 {
151 int a, x, y, w, i, h;
152 float v;
153 int color;
154
155 //
156 // draw the graph
157 //
158 w = scr_vrect.width;
159
160 x = scr_vrect.x;
161 y = scr_vrect.y+scr_vrect.height;
162 ref.DrawFill (x, y-scr_graphheight->value,
163 w, scr_graphheight->value, 8);
164
165 for (a=0 ; a<w ; a++)
166 {
167 i = (current-1-a+1024) & 1023;
168 v = values[i].value;
169 color = values[i].color;
170 v = v*scr_graphscale->value + scr_graphshift->value;
171
172 if (v < 0)
173 v += scr_graphheight->value * (1+(int)(-v/scr_graphheight->value));
174 h = (int)v % (int)scr_graphheight->value;
175 ref.DrawFill (x+w-1-a, y - h, 1, h, color);
176 }
177 }
178
SCR_DrawPercentBar(int percent)179 static void SCR_DrawPercentBar( int percent ) {
180 char buffer[8];
181 int x, w;
182 int length;
183
184 scr_hudHeight -= TINYCHAR_HEIGHT;
185
186 w = scr_hudWidth * percent / 100;
187
188 ref.DrawFill( 0, scr_hudHeight, w, TINYCHAR_HEIGHT, 4 );
189 ref.DrawFill( w, scr_hudHeight, scr_hudWidth - w, TINYCHAR_HEIGHT, 0 );
190
191 length = Com_sprintf( buffer, sizeof( buffer ), "%d%%", percent );
192 x = ( scr_hudWidth - length * TINYCHAR_WIDTH ) / 2;
193 ref.DrawString( x, scr_hudHeight, 0, MAX_STRING_CHARS, buffer, scr_font );
194 }
195
196 /*
197 ================
198 SCR_DrawDemoBar
199 ================
200 */
SCR_DrawDemoBar(void)201 static void SCR_DrawDemoBar( void ) {
202 int percent, bufferPercent;
203
204 if( !scr_demobar->integer ) {
205 return;
206 }
207
208 if( cls.demoplayback ) {
209 SCR_DrawPercentBar( cls.demofilePercent );
210 return;
211 }
212
213 if( sv_running->integer != ss_broadcast ) {
214 return;
215 }
216
217 if( !MVD_GetDemoPercent( &percent, &bufferPercent ) ) {
218 return;
219 }
220
221 if( scr_demobar->integer & 1 ) {
222 SCR_DrawPercentBar( percent );
223 }
224 if( scr_demobar->integer & 2 ) {
225 SCR_DrawPercentBar( bufferPercent );
226 }
227
228 }
229
230 /*
231 ===============================================================================
232
233 CENTER PRINTING
234
235 ===============================================================================
236 */
237
238 static char scr_centerstring[MAX_STRING_CHARS];
239 static int scr_centertime_start; // for slow victory printing
240 static int scr_center_lines;
241
242 /*
243 ==============
244 SCR_CenterPrint
245
246 Called for important messages that should stay in the center of the screen
247 for a few moments
248 ==============
249 */
SCR_CenterPrint(const char * str)250 void SCR_CenterPrint( const char *str ) {
251 const char *s;
252
253 scr_centertime_start = cls.realtime;
254 if( !strcmp( scr_centerstring, str ) ) {
255 return;
256 }
257
258 Q_strncpyz( scr_centerstring, str, sizeof( scr_centerstring ) );
259
260 // count the number of lines for centering
261 scr_center_lines = 1;
262 s = str;
263 while( *s ) {
264 if( *s == '\n' )
265 scr_center_lines++;
266 s++;
267 }
268
269 // echo it to the console
270 Com_Printf( "%s\n", scr_centerstring );
271 Con_ClearNotify_f();
272 }
273
SCR_DrawCenterString(void)274 void SCR_DrawCenterString( void ) {
275 int y;
276 float alpha;
277
278 Cvar_ClampValue( scr_centertime, 0.3f, 10.0f );
279
280 alpha = SCR_FadeAlpha( scr_centertime_start, scr_centertime->value * 1000, 300 );
281 if( !alpha ) {
282 return;
283 }
284
285 ref.SetColor( DRAW_COLOR_ALPHA, ( byte * )&alpha );
286
287 y = scr_hudHeight / 4 - scr_center_lines * 8 / 2;
288
289 UIS_DrawStringEx( scr_hudWidth / 2, y, UI_CENTER|UI_MULTILINE,
290 MAX_STRING_CHARS, scr_centerstring, scr_font );
291
292 ref.SetColor( DRAW_COLOR_CLEAR, NULL );
293 }
294
295 //============================================================================
296
297 /*
298 =================
299 SCR_CalcVrect
300
301 Sets scr_vrect, the coordinates of the rendered window
302 =================
303 */
SCR_CalcVrect(void)304 static void SCR_CalcVrect( void ) {
305 int size;
306
307 // bound viewsize
308 Cvar_ClampInteger( scr_viewsize, 40, 100 );
309 scr_viewsize->modified = qfalse;
310
311 size = scr_viewsize->integer;
312
313 scr_vrect.width = scr_hudWidth * size / 100;
314 scr_vrect.width &= ~7;
315
316 scr_vrect.height = scr_hudHeight * size / 100;
317 scr_vrect.height &= ~1;
318
319 scr_vrect.x = ( scr_hudWidth - scr_vrect.width ) / 2;
320 scr_vrect.y = ( scr_hudHeight - scr_vrect.height ) / 2;
321 }
322
323 /*
324 =================
325 SCR_SizeUp_f
326
327 Keybinding command
328 =================
329 */
SCR_SizeUp_f(void)330 void SCR_SizeUp_f (void)
331 {
332 Cvar_SetInteger("viewsize",scr_viewsize->integer+10);
333 }
334
335
336 /*
337 =================
338 SCR_SizeDown_f
339
340 Keybinding command
341 =================
342 */
SCR_SizeDown_f(void)343 void SCR_SizeDown_f (void)
344 {
345 Cvar_SetInteger ("viewsize",scr_viewsize->integer-10);
346 }
347
348 /*
349 =================
350 SCR_Sky_f
351
352 Set a specific sky and rotation speed
353 =================
354 */
SCR_Sky_f(void)355 void SCR_Sky_f (void)
356 {
357 float rotate;
358 vec3_t axis;
359
360 if (Cmd_Argc() < 2)
361 {
362 Com_Printf ("Usage: sky <basename> [rotate] [axis x y z]\n");
363 return;
364 }
365 if (Cmd_Argc() > 2)
366 rotate = atof(Cmd_Argv(2));
367 else
368 rotate = 0;
369 if (Cmd_Argc() == 6)
370 {
371 axis[0] = atof(Cmd_Argv(3));
372 axis[1] = atof(Cmd_Argv(4));
373 axis[2] = atof(Cmd_Argv(5));
374 }
375 else
376 {
377 axis[0] = 0;
378 axis[1] = 0;
379 axis[2] = 1;
380 }
381
382 ref.SetSky (Cmd_Argv(1), rotate, axis);
383 }
384
385 //============================================================================
386
387 /*
388 ===============
389 SCR_TouchPics
390
391 Allows rendering code to cache all needed sbar graphics
392 ===============
393 */
SCR_TouchPics(void)394 void SCR_TouchPics( void ) {
395 int i, j;
396 char buffer[16];
397
398 for( i = 0; i < 2; i++ )
399 for( j = 0; j < 11; j++ )
400 sb_pics[i][j] = ref.RegisterPic( sb_nums[i][j] );
401
402 sb_inventory = ref.RegisterPic( "inventory" );
403 sb_field = ref.RegisterPic( "field_3" );
404
405 if( crosshair->integer ) {
406 if( crosshair->integer < 0 ) {
407 Cvar_SetInteger( "crosshair", 0 );
408 }
409
410 Com_sprintf( buffer, sizeof( buffer ), "ch%i", crosshair->integer );
411 crosshair_pic = ref.RegisterPic( buffer );
412 ref.DrawGetPicSize( &crosshair_width, &crosshair_height,
413 crosshair_pic );
414 }
415 }
416
417 /*
418 ==================
419 SCR_RegisterMedia
420 ==================
421 */
SCR_RegisterMedia(void)422 void SCR_RegisterMedia( void ) {
423 ref.GetConfig( &scr_glconfig );
424
425 scr_backtile = ref.RegisterPic( "backtile" );
426 scr_pause = ref.RegisterPic( "pause" );
427 scr_net = ref.RegisterPic( "net" );
428 scr_font = ref.RegisterFont( scr_fontvar->string );
429 }
430
SCR_FontImage_OnChange(cvar_t * self,void * arg)431 static void SCR_FontImage_OnChange( cvar_t *self, void *arg ) {
432 scr_font = ref.RegisterFont( self->string );
433 }
434
435 /*
436 ==================
437 SCR_Init
438 ==================
439 */
SCR_Init(void)440 void SCR_Init (void)
441 {
442 scr_viewsize = Cvar_Get ("viewsize", "100", CVAR_ARCHIVE);
443 scr_showpause = Cvar_Get ("scr_showpause", "1", 0);
444 scr_centertime = Cvar_Get ("scr_centertime", "2.5", 0);
445 scr_printspeed = Cvar_Get ("scr_printspeed", "8", 0);
446 scr_netgraph = Cvar_Get ("netgraph", "0", 0);
447 scr_timegraph = Cvar_Get ("timegraph", "0", 0);
448 scr_debuggraph = Cvar_Get ("debuggraph", "0", 0);
449 scr_graphheight = Cvar_Get ("graphheight", "32", 0);
450 scr_graphscale = Cvar_Get ("graphscale", "1", 0);
451 scr_graphshift = Cvar_Get ("graphshift", "0", 0);
452 scr_demobar = Cvar_Get( "scr_demobar", "1", CVAR_ARCHIVE );
453 scr_fontvar = Cvar_Get( "scr_font", "conchars", CVAR_ARCHIVE );
454 scr_fontvar->changedFunc = SCR_FontImage_OnChange;
455 scr_scale = Cvar_Get( "scr_scale", "1", CVAR_ARCHIVE );
456
457 SCR_InitDraw();
458
459 //
460 // register our commands
461 //
462 Cmd_AddCommand ("timerefresh",SCR_TimeRefresh_f);
463 Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
464 Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
465 Cmd_AddCommand ("sky",SCR_Sky_f);
466
467 scr_glconfig.vidWidth = 320;
468 scr_glconfig.vidHeight = 240;
469
470 scr_initialized = qtrue;
471 }
472
473
474
475
476 /*
477 ==============
478 SCR_DrawPause
479 ==============
480 */
SCR_DrawPause(void)481 void SCR_DrawPause( void ) {
482 int x, y, w, h;
483
484 if( !sv_paused->integer ) {
485 return;
486 }
487
488 if( !scr_showpause->integer ) { // turn off for screenshots
489 return;
490 }
491
492 if( cls.key_dest & KEY_MENU ) {
493 return;
494 }
495
496 ref.DrawGetPicSize( &w, &h, scr_pause );
497 x = ( scr_glconfig.vidWidth - w ) / 2;
498 y = scr_glconfig.vidHeight / 2 + 8;
499 ref.DrawPic( x, y, scr_pause );
500 }
501
502 //=============================================================================
503
504 /*
505 ================
506 SCR_BeginLoadingPlaque
507 ================
508 */
SCR_BeginLoadingPlaque(void)509 void SCR_BeginLoadingPlaque( void ) {
510 Con_Close();
511 UI_OpenMenu( UIMENU_NONE );
512 S_StopAllSounds();
513 CDAudio_Stop();
514 }
515
516 /*
517 ================
518 SCR_EndLoadingPlaque
519 ================
520 */
SCR_EndLoadingPlaque(void)521 void SCR_EndLoadingPlaque( void ) {
522 Con_ClearNotify_f();
523 }
524
525
526 /*
527 ================
528 SCR_TimeRefresh_f
529 ================
530 */
SCR_TimeRefresh_f(void)531 void SCR_TimeRefresh_f (void)
532 {
533 int i;
534 int start, stop;
535 float time;
536
537 if ( cls.state != ca_active )
538 return;
539
540 start = Sys_Milliseconds ();
541
542 if (Cmd_Argc() == 2) {
543 // run without page flipping
544 ref.BeginFrame( 0 );
545 for (i=0 ; i<128 ; i++) {
546 cl.refdef.viewangles[1] = i/128.0*360.0;
547 ref.RenderFrame (&cl.refdef);
548 }
549 ref.EndFrame();
550 } else {
551 for (i=0 ; i<128 ; i++) {
552 cl.refdef.viewangles[1] = i/128.0*360.0;
553
554 ref.BeginFrame( 0 );
555 ref.RenderFrame (&cl.refdef);
556 ref.EndFrame();
557 }
558 }
559
560 stop = Sys_Milliseconds ();
561 time = (stop-start)/1000.0;
562 Com_Printf ("%f seconds (%f fps)\n", time, 128/time);
563 }
564
565
566
567 /*
568 ==============
569 SCR_TileClear
570
571 Clear any parts of the tiled background that were drawn on last frame
572 ==============
573 */
SCR_TileClear(void)574 void SCR_TileClear( void ) {
575 int top, bottom, left, right;
576
577 //if( con.currentHeight == 1 )
578 // return; // full screen console
579
580 if( scr_viewsize->integer == 100 )
581 return; // full screen rendering
582
583 if( cl.cinematictime > 0 )
584 return; // full screen cinematic
585
586 top = scr_vrect.y;
587 bottom = top + scr_vrect.height - 1;
588 left = scr_vrect.x;
589 right = left + scr_vrect.width - 1;
590
591
592 // clear above view screen
593 ref.DrawTileClear( 0, 0, scr_glconfig.vidWidth, top, scr_backtile );
594
595 // clear below view screen
596 ref.DrawTileClear( 0, bottom, scr_glconfig.vidWidth,
597 scr_glconfig.vidHeight - bottom, scr_backtile );
598
599 // clear left of view screen
600 ref.DrawTileClear( 0, top, left, scr_vrect.height, scr_backtile );
601
602 // clear right of view screen
603 ref.DrawTileClear( right, top, scr_glconfig.vidWidth - right,
604 scr_vrect.height, scr_backtile );
605
606 }
607
608
609 /*
610 ===============================================================================
611
612 STAT PROGRAMS
613
614 ===============================================================================
615 */
616
617 #define HUD_DrawString( x, y, string ) \
618 ref.DrawString( x, y, 0, MAX_STRING_CHARS, string, scr_font )
619
620 #define HUD_DrawAltString( x, y, string ) \
621 ref.DrawString( x, y, UI_ALTCOLOR, MAX_STRING_CHARS, string, scr_font )
622
623 #define HUD_DrawCenterString( x, y, string ) \
624 UIS_DrawStringEx( x, y, UI_CENTER|UI_MULTILINE, MAX_STRING_CHARS, string, scr_font )
625
626 #define HUD_DrawAltCenterString( x, y, string ) \
627 UIS_DrawStringEx( x, y, UI_CENTER|UI_MULTILINE|UI_ALTCOLOR, MAX_STRING_CHARS, string, scr_font )
628
629
630
631 /*
632 ==============
633 HUD_DrawNumber
634 ==============
635 */
HUD_DrawNumber(int x,int y,int color,int width,int value)636 void HUD_DrawNumber( int x, int y, int color, int width, int value ) {
637 char num[16], *ptr;
638 int l;
639 int frame;
640
641 if( width < 1 )
642 return;
643
644 // draw number string
645 if( width > 5 )
646 width = 5;
647
648 color &= 1;
649
650 Com_sprintf( num, sizeof( num ), "%i", value );
651 l = strlen( num );
652 if( l > width )
653 l = width;
654 x += 2 + CHAR_WIDTH * ( width - l );
655
656 ptr = num;
657 while( *ptr && l ) {
658 if( *ptr == '-' )
659 frame = STAT_MINUS;
660 else
661 frame = *ptr - '0';
662
663 ref.DrawPic( x, y, sb_pics[color][frame] );
664 x += CHAR_WIDTH;
665 ptr++;
666 l--;
667 }
668 }
669
670 /*
671 ================
672 CL_DrawInventory
673 ================
674 */
675 #define DISPLAY_ITEMS 17
676
SCR_DrawInventory(void)677 void SCR_DrawInventory( void ) {
678 int i;
679 int num, selected_num, item;
680 int index[MAX_ITEMS];
681 char string[MAX_STRING_CHARS];
682 int x, y;
683 char *bind;
684 int selected;
685 int top;
686
687 selected = cl.frame.ps.ps.stats[STAT_SELECTED_ITEM];
688
689 num = 0;
690 selected_num = 0;
691 for( i = 0; i < MAX_ITEMS; i++ ) {
692 if( i == selected ) {
693 selected_num = num;
694 }
695 if( cl.inventory[i] ) {
696 index[num++] = i;
697 }
698 }
699
700 // determine scroll point
701 top = selected_num - DISPLAY_ITEMS / 2;
702 clamp( top, 0, num - DISPLAY_ITEMS );
703
704 x = ( scr_hudWidth - 256 ) / 2;
705 y = ( scr_hudHeight - 240 ) / 2;
706
707 ref.DrawPic( x, y + 8, sb_inventory );
708 y += 24;
709 x += 24;
710
711 HUD_DrawString( x, y, "hotkey ### item" );
712 y += TINYCHAR_HEIGHT;
713
714 HUD_DrawString( x, y, "------ --- ----" );
715 y += TINYCHAR_HEIGHT;
716
717 for( i = top; i < num && i < top + DISPLAY_ITEMS; i++ ) {
718 item = index[i];
719 // search for a binding
720 Com_sprintf( string, sizeof( string ), "use %s",
721 cl.configstrings[CS_ITEMS + item] );
722 bind = Key_GetBinding( string );
723
724 Com_sprintf( string, sizeof( string ), "%6s %3i %s",
725 bind, cl.inventory[item], cl.configstrings[CS_ITEMS + item] );
726
727 if( item != selected ) {
728 HUD_DrawAltString( x, y, string );
729 } else { // draw a blinky cursor by the selected item
730 HUD_DrawString( x, y, string );
731 if( ( cls.realtime >> 8 ) & 1 ) {
732 ref.DrawChar( x - TINYCHAR_WIDTH, y, 0, 15, scr_font );
733 }
734
735 }
736
737 y += TINYCHAR_HEIGHT;
738 }
739
740
741 }
742
743 /*
744 ================
745 SCR_ExecuteLayoutString
746
747 ================
748 */
SCR_ExecuteLayoutString(const char * s)749 void SCR_ExecuteLayoutString( const char *s ) {
750 char buffer[80];
751 int x, y;
752 int value;
753 char *token;
754 int width;
755 int index;
756 clientinfo_t *ci;
757
758 if( !s[0] )
759 return;
760
761 x = 0;
762 y = 0;
763 width = 3;
764
765 while( s ) {
766 token = COM_Parse( &s );
767 if( token[2] == 0 ) {
768 if( token[0] == 'x' ) {
769 if( token[1] == 'l' ) {
770 token = COM_Parse( &s );
771 x = atoi( token );
772 continue;
773 }
774
775 if( token[1] == 'r' ) {
776 token = COM_Parse( &s );
777 x = scr_hudWidth + atoi( token );
778 continue;
779 }
780
781 if( token[1] == 'v' ) {
782 token = COM_Parse( &s );
783 x = scr_hudWidth / 2 - 160 + atoi( token );
784 continue;
785 }
786 }
787
788 if( token[0] == 'y' ) {
789 if( token[1] == 't' ) {
790 token = COM_Parse( &s );
791 y = atoi( token );
792 continue;
793 }
794
795 if( token[1] == 'b' ) {
796 token = COM_Parse( &s );
797 y = scr_hudHeight + atoi( token );
798 continue;
799 }
800
801 if( token[1] == 'v' ) {
802 token = COM_Parse( &s );
803 y = scr_hudHeight / 2 - 120 + atoi( token );
804 continue;
805 }
806 }
807 }
808
809 if( !strcmp( token, "pic" ) ) {
810 // draw a pic from a stat number
811 token = COM_Parse( &s );
812 value = atoi( token );
813 if( value < 0 || value >= MAX_STATS ) {
814 Com_Error( ERR_DROP,
815 "SCR_ExecuteLayoutString: invalid pic index" );
816 }
817 value = cl.frame.ps.ps.stats[value];
818 if( value < 0 || value >= MAX_IMAGES ) {
819 Com_Error( ERR_DROP,
820 "SCR_ExecuteLayoutString: invalid pic index" );
821 }
822 token = cl.configstrings[CS_IMAGES + value];
823 if( token[0] ) {
824 UIS_DrawPicByName( x, y, token );
825 }
826 continue;
827 }
828
829 if( !strcmp( token, "client" ) ) {
830 // draw a deathmatch client block
831 int score, ping, time;
832
833 token = COM_Parse( &s );
834 x = scr_hudWidth / 2 - 160 + atoi( token );
835 token = COM_Parse( &s );
836 y = scr_hudHeight / 2 - 120 + atoi( token );
837
838 token = COM_Parse( &s );
839 value = atoi( token );
840 if( value < 0 || value >= MAX_CLIENTS ) {
841 Com_Error( ERR_DROP,
842 "SCR_ExecuteLayoutString: invalid client index" );
843 }
844 ci = &cl.clientinfo[value];
845
846 token = COM_Parse( &s );
847 score = atoi( token );
848
849 token = COM_Parse( &s );
850 ping = atoi( token );
851
852 token = COM_Parse( &s );
853 time = atoi( token );
854
855 HUD_DrawString( x + 32, y, ci->name );
856 Com_sprintf( buffer, sizeof( buffer ), "Score: %i", score );
857 HUD_DrawString( x + 32, y + TINYCHAR_HEIGHT, buffer );
858 Com_sprintf( buffer, sizeof( buffer ), "Ping: %i", ping );
859 HUD_DrawString( x + 32, y + 2 * TINYCHAR_HEIGHT, buffer );
860 Com_sprintf( buffer, sizeof( buffer ), "Time: %i", time );
861 HUD_DrawString( x + 32, y + 3 * TINYCHAR_HEIGHT, buffer );
862
863 if( !ci->icon ) {
864 ci = &cl.baseclientinfo;
865 }
866 ref.DrawPic( x, y, ci->icon );
867 continue;
868 }
869
870 if( !strcmp( token, "ctf" ) ) {
871 // draw a ctf client block
872 int score, ping;
873
874 token = COM_Parse( &s );
875 x = scr_hudWidth / 2 - 160 + atoi( token );
876 token = COM_Parse( &s );
877 y = scr_hudHeight / 2 - 120 + atoi( token );
878
879 token = COM_Parse( &s );
880 value = atoi( token );
881 if( value < 0 || value >= MAX_CLIENTS ) {
882 Com_Error( ERR_DROP,
883 "SCR_ExecuteLayoutString: invalid client index" );
884 }
885 ci = &cl.clientinfo[value];
886
887 token = COM_Parse( &s );
888 score = atoi( token );
889
890 token = COM_Parse( &s );
891 ping = atoi( token );
892 if( ping > 999 )
893 ping = 999;
894
895 Com_sprintf( buffer, sizeof( buffer ), "%3d %3d %-12.12s",
896 score, ping, ci->name );
897 if( value == cl.frame.ps.clientNum ) {
898 HUD_DrawAltString( x, y, buffer );
899 } else {
900 HUD_DrawString( x, y, buffer );
901 }
902 continue;
903 }
904
905 if( !strcmp( token, "picn" ) ) {
906 // draw a pic from a name
907 token = COM_Parse( &s );
908 UIS_DrawPicByName( x, y, token );
909 continue;
910 }
911
912 if( !strcmp( token, "num" ) ) {
913 // draw a number
914 token = COM_Parse( &s );
915 width = atoi( token );
916 token = COM_Parse( &s );
917 value = atoi( token );
918 if( value < 0 || value >= MAX_STATS ) {
919 Com_Error( ERR_DROP,
920 "SCR_ExecuteLayoutString: invalid stat index" );
921 }
922 value = cl.frame.ps.ps.stats[value];
923 HUD_DrawNumber( x, y, 0, width, value );
924 continue;
925 }
926
927 if( !strcmp( token, "hnum" ) ) {
928 // health number
929 int color;
930
931 width = 3;
932 value = cl.frame.ps.ps.stats[STAT_HEALTH];
933 if( value > 25 )
934 color = 0; // green
935 else if( value > 0 )
936 color = ( cl.frame.serverFrame >> 2 ) & 1; // flash
937 else
938 color = 1;
939
940 if( cl.frame.ps.ps.stats[STAT_FLASHES] & 1 )
941 ref.DrawPic( x, y, sb_field );
942
943 HUD_DrawNumber( x, y, color, width, value );
944 continue;
945 }
946
947 if( !strcmp( token, "anum" ) ) {
948 // ammo number
949 int color;
950
951 width = 3;
952 value = cl.frame.ps.ps.stats[STAT_AMMO];
953 if( value > 5 )
954 color = 0; // green
955 else if( value >= 0 )
956 color = ( cl.frame.serverFrame >> 2 ) & 1; // flash
957 else
958 continue; // negative number = don't show
959
960 if( cl.frame.ps.ps.stats[STAT_FLASHES] & 4 )
961 ref.DrawPic( x, y, sb_field );
962
963 HUD_DrawNumber( x, y, color, width, value );
964 continue;
965 }
966
967 if( !strcmp( token, "rnum" ) ) {
968 // armor number
969 int color;
970
971 width = 3;
972 value = cl.frame.ps.ps.stats[STAT_ARMOR];
973 if( value < 1 )
974 continue;
975
976 color = 0; // green
977
978 if( cl.frame.ps.ps.stats[STAT_FLASHES] & 2 )
979 ref.DrawPic( x, y, sb_field );
980
981 HUD_DrawNumber( x, y, color, width, value );
982 continue;
983 }
984
985
986 if( !strcmp( token, "stat_string" ) ) {
987 token = COM_Parse( &s );
988 index = atoi( token );
989 if( index < 0 || index >= MAX_STATS ) {
990 Com_Error( ERR_DROP, "SCR_ExecuteLayoutString: "
991 "invalid stat_string index" );
992 }
993 index = cl.frame.ps.ps.stats[index];
994 if( index < 0 || index >= MAX_CONFIGSTRINGS ) {
995 Com_Error( ERR_DROP, "SCR_ExecuteLayoutString: "
996 "invalid stat_string index" );
997 }
998 HUD_DrawString( x, y, cl.configstrings[index] );
999 continue;
1000 }
1001
1002 if( !strcmp( token, "cstring" ) ) {
1003 token = COM_Parse( &s );
1004 HUD_DrawCenterString( x + 320 / 2, y, token );
1005 continue;
1006 }
1007
1008 if( !strcmp( token, "cstring2" ) ) {
1009 token = COM_Parse( &s );
1010 HUD_DrawAltCenterString( x + 320 / 2, y, token );
1011 continue;
1012 }
1013
1014 if( !strcmp( token, "string" ) ) {
1015 token = COM_Parse( &s );
1016 HUD_DrawString( x, y, token );
1017 continue;
1018 }
1019
1020 if( !strcmp( token, "string2" ) ) {
1021 token = COM_Parse( &s );
1022 HUD_DrawAltString( x, y, token );
1023 continue;
1024 }
1025
1026 if( !strcmp( token, "if" ) ) {
1027 token = COM_Parse( &s );
1028 value = atoi( token );
1029 if( value < 0 || value >= MAX_STATS ) {
1030 Com_Error( ERR_DROP, "SCR_ExecuteLayoutString: "
1031 "invalid stat index" );
1032 }
1033 value = cl.frame.ps.ps.stats[value];
1034 if( !value ) { // skip to endif
1035 while( strcmp( token, "endif" ) ) {
1036 token = COM_Parse( &s );
1037 if( !s ) {
1038 break;
1039 }
1040 }
1041 }
1042
1043 continue;
1044 }
1045
1046
1047 }
1048 }
1049
SCR_DrawActiveFrame(float separation)1050 static void SCR_DrawActiveFrame( float separation ) {
1051 float scale;
1052
1053 scr_hudHeight = scr_glconfig.vidHeight;
1054 scr_hudWidth = scr_glconfig.vidWidth;
1055
1056 SCR_DrawDemoBar();
1057
1058 SCR_CalcVrect();
1059
1060 /* clear any dirty part of the background */
1061 SCR_TileClear();
1062
1063 /* draw 3D game view */
1064 V_RenderView( separation );
1065
1066 Cvar_ClampValue( scr_scale, 1, 9 );
1067
1068 scale = 1.0f / scr_scale->value;
1069 ref.SetScale( &scale );
1070
1071 scr_hudHeight *= scale;
1072 scr_hudWidth *= scale;
1073
1074 /* draw all 2D elements */
1075 SCR_Draw2D();
1076
1077 ref.SetScale( NULL );
1078 }
1079
1080 #if 0
1081 static void PlayerConfig_MenuDraw( void ) {
1082 refdef_t refdef;
1083 char scratch[MAX_QPATH];
1084 entity_t entity[2];
1085
1086 memset( &refdef, 0, sizeof( refdef ) );
1087
1088 refdef.x = SCREEN_WIDTH / 2;
1089 refdef.y = 60;
1090 refdef.width = SCREEN_WIDTH / 2;
1091 refdef.height = SCREEN_HEIGHT - 122;
1092
1093 refdef.fov_x = 40;
1094 refdef.fov_y = Com_CalcFov( refdef.fov_x, refdef.width, refdef.height );
1095 refdef.time = cls.realtime * 0.001f;
1096
1097 memset( entity, 0, sizeof( entity ) );
1098
1099 Com_sprintf( scratch, sizeof( scratch ), "players/%s/tris.md2", "male" );
1100 entity[0].model = ref.RegisterModel( scratch );
1101 Com_sprintf( scratch, sizeof( scratch ), "players/%s/%s.pcx", "male", "flak" );
1102 entity[0].skin = ref.RegisterSkin( scratch );
1103 entity[0].flags = RF_FULLBRIGHT;
1104 entity[0].origin[0] = 80;
1105 entity[0].origin[1] = 0;
1106 entity[0].origin[2] = 0;
1107 VectorCopy( entity[0].origin, entity[0].oldorigin );
1108 entity[0].frame = 0;
1109 entity[0].oldframe = 0;
1110 entity[0].backlerp = 0.0;
1111 entity[0].angles[1] = anglemod( cls.realtime / 20.0f );
1112
1113 entity[1] = entity[0];
1114 entity[1].skin = 0;
1115 entity[1].skinnum = 0;
1116 entity[1].alpha = 0;
1117 Com_sprintf( scratch, sizeof( scratch ), "players/%s/w_railgun.md2", "male" );
1118 entity[1].model = ref.RegisterModel( scratch );
1119
1120 entity[0].flags |= RF_TRANSLUCENT|RF_SHELL_RED;
1121 entity[0].alpha = 0.5 + 0.5 * sin(cls.realtime * 0.001f);
1122
1123 refdef.areabits = 0;
1124 refdef.num_entities = 2;
1125 refdef.entities = entity;
1126 refdef.lightstyles = 0;
1127 refdef.rdflags = RDF_NOWORLDMODEL;
1128
1129
1130 ref.RenderFrame( &refdef );
1131
1132 }
1133
1134
1135 void TestDraw( void ) {
1136 color_t color = { 0, 0, 255, 33 };
1137
1138 ref.DrawFillEx( scr_vrect.x + 100, scr_vrect.y + 100, scr_vrect.width - 200, scr_vrect.height - 200, color );
1139 PlayerConfig_MenuDraw();
1140 }
1141 #endif
1142
1143 //=======================================================
1144
1145 /*
1146 ==================
1147 SCR_DrawScreenFrame
1148 ==================
1149 */
SCR_DrawScreenFrame(float separation)1150 static void SCR_DrawScreenFrame( float separation ) {
1151 ref.BeginFrame( separation );
1152
1153 /* if a cinematic is supposed to be running, handle menus
1154 * and console specially
1155 */
1156 if( cl.cinematictime > 0 ) {
1157 if( cls.key_dest & (KEY_CONSOLE|KEY_MENU) ) {
1158 if( cl.cinematicpalette_active ) {
1159 ref.CinematicSetPalette( NULL );
1160 cl.cinematicpalette_active = qfalse;
1161 }
1162 UI_Draw( cls.realtime );
1163 Con_DrawConsole();
1164 } else {
1165 SCR_DrawCinematic();
1166 }
1167 return;
1168 }
1169
1170 /* make sure the game palette is active */
1171 if( cl.cinematicpalette_active ) {
1172 ref.CinematicSetPalette( NULL );
1173 cl.cinematicpalette_active = qfalse;
1174 }
1175
1176 switch( cls.state ) {
1177 case ca_disconnected:
1178 /* make sure at least fullscreen console or main menu is up */
1179 if( !( cls.key_dest & (KEY_MENU|KEY_CONSOLE) ) ) {
1180 Key_SetDest( cls.key_dest | KEY_CONSOLE );
1181 Con_RunConsole();
1182 }
1183
1184 /* draw main menu */
1185 UI_Draw( cls.realtime );
1186 break;
1187
1188 case ca_challenging:
1189 case ca_connecting:
1190 case ca_connected:
1191 case ca_loading:
1192 case ca_precached:
1193 /* make sure main menu is down */
1194 if( cls.key_dest & KEY_MENU ) {
1195 UI_OpenMenu( UIMENU_NONE );
1196 }
1197
1198 /* draw loading screen */
1199 UI_DrawLoading( cls.realtime );
1200 break;
1201
1202 case ca_active:
1203 if( UI_IsTransparent() ) {
1204 /* do 3D refresh drawing */
1205 SCR_DrawActiveFrame( separation );
1206 }
1207
1208 /* draw ingame menu */
1209 UI_Draw( cls.realtime );
1210 break;
1211
1212 default:
1213 Com_Error( ERR_FATAL, "SCR_DrawScreenFrame: bad cls.state" );
1214 break;
1215 }
1216
1217 Con_DrawConsole();
1218
1219 // TestDraw();
1220
1221 if( scr_timegraph->integer )
1222 SCR_DebugGraph( cls.frametime*300, 0 );
1223
1224 if( scr_debuggraph->integer || scr_timegraph->integer ||
1225 scr_netgraph->integer )
1226 {
1227 SCR_DrawDebugGraph();
1228 }
1229 }
1230
1231 /*
1232 ==================
1233 SCR_UpdateScreen
1234
1235 This is called every frame, and can also be called explicitly to flush
1236 text to the screen.
1237 ==================
1238 */
SCR_UpdateScreen(void)1239 void SCR_UpdateScreen( void ) {
1240 static int recursive;
1241
1242 if( !scr_initialized )
1243 return; // not initialized yet
1244
1245 if( recursive > 1 ) {
1246 Com_Error( ERR_FATAL, "SCR_UpdateScreen: recursively called" );
1247 }
1248
1249 recursive++;
1250
1251 /*
1252 ** range check cl_camera_separation so we don't inadvertently fry someone's
1253 ** brain
1254 */
1255 if( cl_stereo_separation->value > 1 )
1256 Cvar_SetValue( "cl_stereo_separation", 1 );
1257 else if( cl_stereo_separation->value < 0 )
1258 Cvar_SetValue( "cl_stereo_separation", 0 );
1259
1260 if( cl_stereo->integer ) {
1261 SCR_DrawScreenFrame( -cl_stereo_separation->value / 2 );
1262 SCR_DrawScreenFrame( cl_stereo_separation->value / 2 );
1263 } else {
1264 SCR_DrawScreenFrame( 0 );
1265 }
1266
1267 ref.EndFrame();
1268
1269 recursive--;
1270 }
1271
1272
1273