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