1 /*
2 ===========================================================================
3 Copyright (C) 1999 - 2005, Id Software, Inc.
4 Copyright (C) 2000 - 2013, Raven Software, Inc.
5 Copyright (C) 2001 - 2013, Activision, Inc.
6 Copyright (C) 2005 - 2015, ioquake3 contributors
7 Copyright (C) 2013 - 2015, OpenJK contributors
8
9 This file is part of the OpenJK source code.
10
11 OpenJK is free software; you can redistribute it and/or modify it
12 under the terms of the GNU General Public License version 2 as
13 published by the Free Software Foundation.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, see <http://www.gnu.org/licenses/>.
22 ===========================================================================
23 */
24
25 // cl_scrn.c -- master for refresh, status bar, console, chat, notify, etc
26
27 #include "../server/exe_headers.h"
28
29 #include "client.h"
30 #include "client_ui.h"
31
32 extern console_t con;
33
34 qboolean scr_initialized; // ready to draw
35
36 cvar_t *cl_timegraph;
37 cvar_t *cl_debuggraph;
38 cvar_t *cl_graphheight;
39 cvar_t *cl_graphscale;
40 cvar_t *cl_graphshift;
41
42 /*
43 ================
44 SCR_DrawNamedPic
45
46 Coordinates are 640*480 virtual values
47 =================
48 */
SCR_DrawNamedPic(float x,float y,float width,float height,const char * picname)49 void SCR_DrawNamedPic( float x, float y, float width, float height, const char *picname ) {
50 qhandle_t hShader;
51
52 assert( width != 0 );
53
54 hShader = re.RegisterShader( picname );
55 re.DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );
56 }
57
58
59 /*
60 ================
61 SCR_FillRect
62
63 Coordinates are 640*480 virtual values
64 =================
65 */
SCR_FillRect(float x,float y,float width,float height,const float * color)66 void SCR_FillRect( float x, float y, float width, float height, const float *color ) {
67 re.SetColor( color );
68
69 re.DrawStretchPic( x, y, width, height, 0, 0, 0, 0, cls.whiteShader );
70
71 re.SetColor( NULL );
72 }
73
74
75 /*
76 ================
77 SCR_DrawPic
78
79 Coordinates are 640*480 virtual values
80 A width of 0 will draw with the original image width
81 =================
82 */
SCR_DrawPic(float x,float y,float width,float height,qhandle_t hShader)83 void SCR_DrawPic( float x, float y, float width, float height, qhandle_t hShader ) {
84 re.DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );
85 }
86
87
88 /*
89 ** SCR_DrawBigChar
90 ** big chars are drawn at 640*480 virtual screen size
91 */
SCR_DrawBigChar(int x,int y,int ch)92 void SCR_DrawBigChar( int x, int y, int ch ) {
93 int row, col;
94 float frow, fcol;
95 float size;
96 float ax, ay, aw, ah;
97
98 ch &= 255;
99
100 if ( ch == ' ' ) {
101 return;
102 }
103
104 if ( y < -BIGCHAR_HEIGHT ) {
105 return;
106 }
107
108 ax = x;
109 ay = y;
110 aw = BIGCHAR_WIDTH;
111 ah = BIGCHAR_HEIGHT;
112
113 row = ch>>4;
114 col = ch&15;
115
116 frow = row*0.0625;
117 fcol = col*0.0625;
118 size = 0.0625;
119 /*
120 re.DrawStretchPic( ax, ay, aw, ah,
121 fcol, frow,
122 fcol + size, frow + size,
123 cls.charSetShader );
124 */
125 float size2;
126
127 frow = row*0.0625;
128 fcol = col*0.0625;
129 size = 0.03125;
130 size2 = 0.0625;
131
132 re.DrawStretchPic( ax, ay, aw, ah,
133 fcol, frow,
134 fcol + size, frow + size2,
135 cls.charSetShader );
136
137 }
138
139 /*
140 ** SCR_DrawSmallChar
141 ** small chars are drawn at native screen resolution
142 */
SCR_DrawSmallChar(int x,int y,int ch)143 void SCR_DrawSmallChar( int x, int y, int ch ) {
144 int row, col;
145 float frow, fcol;
146 float size;
147
148 ch &= 255;
149
150 if ( ch == ' ' ) {
151 return;
152 }
153
154 if ( y < -SMALLCHAR_HEIGHT ) {
155 return;
156 }
157
158 row = ch>>4;
159 col = ch&15;
160 /*
161 frow = row*0.0625;
162 fcol = col*0.0625;
163 size = 0.0625;
164
165 re.DrawStretchPic( x, y, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT,
166 fcol, frow,
167 fcol + size, frow + size,
168 cls.charSetShader );
169 */
170
171 float size2;
172
173 frow = row*0.0625;
174 fcol = col*0.0625;
175 size = 0.03125;
176 size2 = 0.0625;
177
178 re.DrawStretchPic( x * con.xadjust, y * con.yadjust,
179 SMALLCHAR_WIDTH * con.xadjust, SMALLCHAR_HEIGHT * con.yadjust,
180 fcol, frow,
181 fcol + size, frow + size2,
182 cls.charSetShader );
183
184 }
185
186
187
188 /*
189 ==================
190 SCR_DrawBigString[Color]
191
192 Draws a multi-colored string with a drop shadow, optionally forcing
193 to a fixed color.
194
195 Coordinates are at 640 by 480 virtual resolution
196 ==================
197 */
SCR_DrawBigStringExt(int x,int y,const char * string,float * setColor,qboolean forceColor,qboolean noColorEscape)198 void SCR_DrawBigStringExt( int x, int y, const char *string, float *setColor, qboolean forceColor, qboolean noColorEscape ) {
199 vec4_t color;
200 const char *s;
201 int xx;
202
203 // draw the drop shadow
204 color[0] = color[1] = color[2] = 0;
205 color[3] = setColor[3];
206 re.SetColor( color );
207 s = string;
208 xx = x;
209 while ( *s ) {
210 if ( !noColorEscape && Q_IsColorString( s ) ) {
211 s += 2;
212 continue;
213 }
214 SCR_DrawBigChar( xx+2, y+2, *s );
215 xx += BIGCHAR_WIDTH;
216 s++;
217 }
218
219
220 // draw the colored text
221 s = string;
222 xx = x;
223 re.SetColor( setColor );
224 while ( *s ) {
225 if ( Q_IsColorString( s ) ) {
226 if ( !forceColor ) {
227 memcpy( color, g_color_table[ColorIndex(*(s+1))], sizeof( color ) );
228 color[3] = setColor[3];
229 re.SetColor( color );
230 }
231 if ( !noColorEscape ) {
232 s += 2;
233 continue;
234 }
235 }
236 SCR_DrawBigChar( xx, y, *s );
237 xx += BIGCHAR_WIDTH;
238 s++;
239 }
240 re.SetColor( NULL );
241 }
242
243
SCR_DrawBigString(int x,int y,const char * s,float alpha,qboolean noColorEscape)244 void SCR_DrawBigString( int x, int y, const char *s, float alpha, qboolean noColorEscape ) {
245 float color[4];
246
247 color[0] = color[1] = color[2] = 1.0;
248 color[3] = alpha;
249 SCR_DrawBigStringExt( x, y, s, color, qfalse, noColorEscape );
250 }
251
SCR_DrawBigStringColor(int x,int y,const char * s,vec4_t color,qboolean noColorEscape)252 void SCR_DrawBigStringColor( int x, int y, const char *s, vec4_t color, qboolean noColorEscape ) {
253 SCR_DrawBigStringExt( x, y, s, color, qtrue, noColorEscape );
254 }
255
256 /*
257 ==================
258 SCR_DrawSmallString[Color]
259
260 Draws a multi-colored string with a drop shadow, optionally forcing
261 to a fixed color.
262 ==================
263 */
SCR_DrawSmallStringExt(int x,int y,const char * string,float * setColor,qboolean forceColor,qboolean noColorEscape)264 void SCR_DrawSmallStringExt( int x, int y, const char *string, float *setColor, qboolean forceColor,
265 qboolean noColorEscape ) {
266 vec4_t color;
267 const char *s;
268 int xx;
269
270 // draw the colored text
271 s = string;
272 xx = x;
273 re.SetColor( setColor );
274 while ( *s ) {
275 if ( Q_IsColorString( s ) ) {
276 if ( !forceColor ) {
277 memcpy( color, g_color_table[ColorIndex(*(s+1))], sizeof( color ) );
278 color[3] = setColor[3];
279 re.SetColor( color );
280 }
281 if ( !noColorEscape ) {
282 s += 2;
283 continue;
284 }
285 }
286 SCR_DrawSmallChar( xx, y, *s );
287 xx += SMALLCHAR_WIDTH;
288 s++;
289 }
290 re.SetColor( NULL );
291 }
292
293 /*
294 ** SCR_Strlen -- skips color escape codes
295 */
SCR_Strlen(const char * str)296 static int SCR_Strlen( const char *str ) {
297 const char *s = str;
298 int count = 0;
299
300 while ( *s ) {
301 if ( Q_IsColorString( s ) ) {
302 s += 2;
303 } else {
304 count++;
305 s++;
306 }
307 }
308
309 return count;
310 }
311
312 /*
313 ** SCR_GetBigStringWidth
314 */
SCR_GetBigStringWidth(const char * str)315 int SCR_GetBigStringWidth( const char *str ) {
316 return SCR_Strlen( str ) * BIGCHAR_WIDTH;
317 }
318
319 //===============================================================================
320
321
322 /*
323 ===============================================================================
324
325 DEBUG GRAPH
326
327 ===============================================================================
328 */
329 typedef struct
330 {
331 float value;
332 int color;
333 } graphsamp_t;
334
335 static int current;
336 static graphsamp_t values[1024];
337
338 /*
339 ==============
340 SCR_DebugGraph
341 ==============
342 */
SCR_DebugGraph(float value,int color)343 void SCR_DebugGraph (float value, int color)
344 {
345 values[current&1023].value = value;
346 values[current&1023].color = color;
347 current++;
348 }
349
350 /*
351 ==============
352 SCR_DrawDebugGraph
353 ==============
354 */
SCR_DrawDebugGraph(void)355 void SCR_DrawDebugGraph (void)
356 {
357 int a, x, y, w, i, h;
358 float v;
359
360 //
361 // draw the graph
362 //
363 w = cls.glconfig.vidWidth;
364 x = 0;
365 y = cls.glconfig.vidHeight;
366 re.SetColor( g_color_table[0] );
367 re.DrawStretchPic(x, y - cl_graphheight->integer,
368 w, cl_graphheight->integer, 0, 0, 0, 0, 0 );
369 re.SetColor( NULL );
370
371 for (a=0 ; a<w ; a++)
372 {
373 i = (current-1-a+1024) & 1023;
374 v = values[i].value;
375 v = v * cl_graphscale->integer + cl_graphshift->integer;
376
377 if (v < 0)
378 v += cl_graphheight->integer * (1+(int)(-v / cl_graphheight->integer));
379 h = (int)v % cl_graphheight->integer;
380 re.DrawStretchPic( x+w-1-a, y - h, 1, h, 0, 0, 0, 0, 0 );
381 }
382 }
383 //=============================================================================
384
385 /*
386 ==================
387 SCR_Init
388 ==================
389 */
SCR_Init(void)390 void SCR_Init( void ) {
391 cl_timegraph = Cvar_Get ("timegraph", "0", CVAR_CHEAT);
392 cl_debuggraph = Cvar_Get ("debuggraph", "0", CVAR_CHEAT);
393 cl_graphheight = Cvar_Get ("graphheight", "32", CVAR_CHEAT);
394 cl_graphscale = Cvar_Get ("graphscale", "1", CVAR_CHEAT);
395 cl_graphshift = Cvar_Get ("graphshift", "0", CVAR_CHEAT);
396
397 scr_initialized = qtrue;
398 }
399
400
401 //=======================================================
402
403 void UI_SetActiveMenu( const char* menuname,const char *menuID );
404 void _UI_Refresh( int realtime );
405 void UI_DrawConnect( const char *servername, const char * updateInfoString );
406
407 /*
408 ==================
409 SCR_DrawScreenField
410
411 This will be called twice if rendering in stereo mode
412 ==================
413 */
SCR_DrawScreenField(stereoFrame_t stereoFrame)414 void SCR_DrawScreenField( stereoFrame_t stereoFrame ) {
415
416 re.BeginFrame( stereoFrame );
417
418 qboolean uiFullscreen = _UI_IsFullscreen();
419
420 // if the menu is going to cover the entire screen, we
421 // don't need to render anything under it
422 if ( !uiFullscreen ) {
423 switch( cls.state ) {
424 default:
425 Com_Error( ERR_FATAL, "SCR_DrawScreenField: bad cls.state" );
426 break;
427 case CA_CINEMATIC:
428 SCR_DrawCinematic();
429 break;
430 case CA_DISCONNECTED:
431 // force menu up
432 UI_SetActiveMenu( "mainMenu", NULL );
433 break;
434 case CA_CONNECTING:
435 case CA_CHALLENGING:
436 case CA_CONNECTED:
437 // connecting clients will only show the connection dialog
438 UI_DrawConnect( clc.servername, cls.updateInfoString );
439 break;
440 case CA_LOADING:
441 case CA_PRIMED:
442 // draw the game information screen and loading progress
443 CL_CGameRendering( stereoFrame );
444 break;
445 case CA_ACTIVE:
446 if (CL_IsRunningInGameCinematic() || CL_InGameCinematicOnStandBy())
447 {
448 SCR_DrawCinematic();
449 }
450 else
451 {
452 CL_CGameRendering( stereoFrame );
453 }
454 break;
455 }
456 }
457
458 re.ProcessDissolve();
459
460 // draw downloading progress bar
461
462 // the menu draws next
463 _UI_Refresh( cls.realtime );
464
465 // console draws next
466 Con_DrawConsole ();
467
468 // debug graph can be drawn on top of anything
469 if ( cl_debuggraph->integer || cl_timegraph->integer ) {
470 SCR_DrawDebugGraph ();
471 }
472 }
473
474 /*
475 ==================
476 SCR_UpdateScreen
477
478 This is called every frame, and can also be called explicitly to flush
479 text to the screen.
480 ==================
481 */
SCR_UpdateScreen(void)482 void SCR_UpdateScreen( void ) {
483 static int recursive;
484
485 if ( !scr_initialized ) {
486 return; // not initialized yet
487 }
488
489 // load the ref / ui / cgame if needed
490 CL_StartHunkUsers();
491
492 if ( ++recursive > 2 ) {
493 Com_Error( ERR_FATAL, "SCR_UpdateScreen: recursively called" );
494 }
495 recursive = qtrue;
496
497 // If there is no VM, there are also no rendering commands issued. Stop the renderer in
498 // that case.
499 if ( cls.uiStarted )
500 {
501 // if running in stereo, we need to draw the frame twice
502 if ( cls.glconfig.stereoEnabled ) {
503 SCR_DrawScreenField( STEREO_LEFT );
504 SCR_DrawScreenField( STEREO_RIGHT );
505 } else {
506 SCR_DrawScreenField( STEREO_CENTER );
507 }
508
509 if ( com_speeds->integer ) {
510 re.EndFrame( &time_frontend, &time_backend );
511 } else {
512 re.EndFrame( NULL, NULL );
513 }
514 }
515
516 recursive = 0;
517 }
518
519 // this stuff is only used by the savegame (SG) code for screenshots...
520 //
521
522
523 static byte bScreenData[SG_SCR_WIDTH * SG_SCR_HEIGHT * 4];
524 static qboolean screenDataValid = qfalse;
SCR_UnprecacheScreenshot()525 void SCR_UnprecacheScreenshot()
526 {
527 screenDataValid = qfalse;
528 }
529
530
SCR_PrecacheScreenshot()531 void SCR_PrecacheScreenshot()
532 {
533 // No screenshots unless connected to single player local server...
534 //
535 // char *psInfo = cl.gameState.stringData + cl.gameState.stringOffsets[ CS_SERVERINFO ];
536 // int iMaxClients = atoi(Info_ValueForKey( psInfo, "sv_maxclients" ));
537
538 // (no need to check single-player status in voyager, this code base is all singleplayer)
539 if ( cls.state != CA_ACTIVE )
540 {
541 return;
542 }
543
544 if (!Key_GetCatcher( ))
545 {
546 // in-game...
547 //
548 // SCR_UnprecacheScreenshot();
549 // pbScreenData = (byte *)Z_Malloc(SG_SCR_WIDTH * SG_SCR_HEIGHT * 4);
550 S_ClearSoundBuffer(); // clear DMA etc because the following glReadPixels() call can take ages
551 re.GetScreenShot( (byte *) &bScreenData, SG_SCR_WIDTH, SG_SCR_HEIGHT);
552 screenDataValid = qtrue;
553 }
554
555 }
556
SCR_GetScreenshot(qboolean * qValid)557 byte *SCR_GetScreenshot(qboolean *qValid)
558 {
559 if (!screenDataValid) {
560 SCR_PrecacheScreenshot();
561 }
562 if (qValid) {
563 *qValid = screenDataValid;
564 }
565 return (byte *)&bScreenData;
566 }
567
568 // called from save-game code to set the lo-res loading screen to be the one from the save file...
569 //
SCR_SetScreenshot(const byte * pbData,int w,int h)570 void SCR_SetScreenshot(const byte *pbData, int w, int h)
571 {
572 if (w == SG_SCR_WIDTH && h == SG_SCR_HEIGHT)
573 {
574 screenDataValid = qtrue;
575 memcpy(&bScreenData, pbData, SG_SCR_WIDTH*SG_SCR_HEIGHT*4);
576 }
577 else
578 {
579 screenDataValid = qfalse;
580 memset(&bScreenData, 0, SG_SCR_WIDTH*SG_SCR_HEIGHT*4);
581 }
582 }
583
584
585 #ifdef JK2_MODE
586 // This is just a client-side wrapper for the function RE_TempRawImage_ReadFromFile() in the renderer code...
587 //
588
SCR_TempRawImage_ReadFromFile(const char * psLocalFilename,int * piWidth,int * piHeight,byte * pbReSampleBuffer,qboolean qbVertFlip)589 byte* SCR_TempRawImage_ReadFromFile(const char *psLocalFilename, int *piWidth, int *piHeight, byte *pbReSampleBuffer, qboolean qbVertFlip)
590 {
591 return re.TempRawImage_ReadFromFile(psLocalFilename, piWidth, piHeight, pbReSampleBuffer, qbVertFlip);
592 }
593 //
594 // ditto (sort of)...
595 //
SCR_TempRawImage_CleanUp()596 void SCR_TempRawImage_CleanUp()
597 {
598 re.TempRawImage_CleanUp();
599 }
600 #endif
601
602
603