1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19*/
20// screen.c -- master for refresh, status bar, console, chat, notify, etc
21
22#include "quakedef.h"
23#include "r_local.h"
24
25#include <time.h>
26
27/*
28
29background clear
30rendering
31turtle/net/ram icons
32sbar
33centerprint / slow centerprint
34notify lines
35intermission / finale overlay
36loading plaque
37console
38menu
39
40required background clears
41required update regions
42
43
44syncronous draw mode or async
45One off screen buffer, with updates either copied or xblited
46Need to double buffer?
47
48
49async draw will require the refresh area to be cleared, because it will be
50xblited, but sync draw can just ignore it.
51
52sync
53draw
54
55CenterPrint ()
56SlowPrint ()
57Screen_Update ();
58Con_Printf ();
59
60net
61turn off messages option
62
63the refresh is allways rendered, unless the console is full screen
64
65
66console is:
67	notify lines
68	half
69	full
70
71
72*/
73
74
75// only the refresh window will be updated unless these variables are flagged
76int			scr_copytop;
77int			scr_copyeverything;
78
79float		scr_con_current;
80float		scr_conlines;		// lines of console to display
81
82float		oldscreensize, oldfov;
83float		oldsbar;
84cvar_t		scr_viewsize = {"viewsize","100", true};
85cvar_t		scr_fov = {"fov","90"};	// 10 - 170
86cvar_t		scr_conspeed = {"scr_conspeed","300"};
87cvar_t		scr_centertime = {"scr_centertime","2"};
88cvar_t		scr_showram = {"showram","1"};
89cvar_t		scr_showturtle = {"showturtle","0"};
90cvar_t		scr_showpause = {"showpause","1"};
91cvar_t		scr_printspeed = {"scr_printspeed","8"};
92cvar_t		scr_allowsnap = {"scr_allowsnap", "1"};
93
94qboolean	scr_initialized;		// ready to draw
95
96qpic_t		*scr_ram;
97qpic_t		*scr_net;
98qpic_t		*scr_turtle;
99
100int			scr_fullupdate;
101
102int			clearconsole;
103int			clearnotify;
104
105int			sb_lines;
106
107viddef_t	vid;				// global video state
108
109vrect_t		*pconupdate;
110vrect_t		scr_vrect;
111
112qboolean	scr_disabled_for_loading;
113
114qboolean	scr_skipupdate;
115
116qboolean	block_drawing;
117
118void SCR_ScreenShot_f (void);
119void SCR_RSShot_f (void);
120
121/*
122===============================================================================
123
124CENTER PRINTING
125
126===============================================================================
127*/
128
129char		scr_centerstring[1024];
130float		scr_centertime_start;	// for slow victory printing
131float		scr_centertime_off;
132int			scr_center_lines;
133int			scr_erase_lines;
134int			scr_erase_center;
135
136/*
137==============
138SCR_CenterPrint
139
140Called for important messages that should stay in the center of the screen
141for a few moments
142==============
143*/
144void SCR_CenterPrint (char *str)
145{
146	strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
147	scr_centertime_off = scr_centertime.value;
148	scr_centertime_start = cl.time;
149
150// count the number of lines for centering
151	scr_center_lines = 1;
152	while (*str)
153	{
154		if (*str == '\n')
155			scr_center_lines++;
156		str++;
157	}
158}
159
160void SCR_EraseCenterString (void)
161{
162	int		y;
163
164	if (scr_erase_center++ > vid.numpages)
165	{
166		scr_erase_lines = 0;
167		return;
168	}
169
170	if (scr_center_lines <= 4)
171		y = vid.height*0.35;
172	else
173		y = 48;
174
175	scr_copytop = 1;
176	Draw_TileClear (0, y, vid.width, min(8*scr_erase_lines, vid.height - y - 1));
177}
178
179void SCR_DrawCenterString (void)
180{
181	char	*start;
182	int		l;
183	int		j;
184	int		x, y;
185	int		remaining;
186
187// the finale prints the characters one at a time
188	if (cl.intermission)
189		remaining = scr_printspeed.value * (cl.time - scr_centertime_start);
190	else
191		remaining = 9999;
192
193	scr_erase_center = 0;
194	start = scr_centerstring;
195
196	if (scr_center_lines <= 4)
197		y = vid.height*0.35;
198	else
199		y = 48;
200
201	do
202	{
203	// scan the width of the line
204		for (l=0 ; l<40 ; l++)
205			if (start[l] == '\n' || !start[l])
206				break;
207		x = (vid.width - l*8)/2;
208		for (j=0 ; j<l ; j++, x+=8)
209		{
210			Draw_Character (x, y, start[j]);
211			if (!remaining--)
212				return;
213		}
214
215		y += 8;
216
217		while (*start && *start != '\n')
218			start++;
219
220		if (!*start)
221			break;
222		start++;		// skip the \n
223	} while (1);
224}
225
226void SCR_CheckDrawCenterString (void)
227{
228	scr_copytop = 1;
229	if (scr_center_lines > scr_erase_lines)
230		scr_erase_lines = scr_center_lines;
231
232	scr_centertime_off -= host_frametime;
233
234	if (scr_centertime_off <= 0 && !cl.intermission)
235		return;
236	if (key_dest != key_game)
237		return;
238
239	SCR_DrawCenterString ();
240}
241
242//=============================================================================
243
244/*
245====================
246CalcFov
247====================
248*/
249float CalcFov (float fov_x, float width, float height)
250{
251        float   a;
252        float   x;
253
254        if (fov_x < 1 || fov_x > 179)
255                Sys_Error ("Bad fov: %f", fov_x);
256
257        x = width/tan(fov_x/360*M_PI);
258
259        a = atan (height/x);
260
261        a = a*360/M_PI;
262
263        return a;
264}
265
266/*
267=================
268SCR_CalcRefdef
269
270Must be called whenever vid changes
271Internal use only
272=================
273*/
274static void SCR_CalcRefdef (void)
275{
276	vrect_t		vrect;
277	float		size;
278
279	scr_fullupdate = 0;		// force a background redraw
280	vid.recalc_refdef = 0;
281
282// force the status bar to redraw
283	Sbar_Changed ();
284
285//========================================
286
287// bound viewsize
288	if (scr_viewsize.value < 30)
289		Cvar_Set ("viewsize","30");
290	if (scr_viewsize.value > 120)
291		Cvar_Set ("viewsize","120");
292
293// bound field of view
294	if (scr_fov.value < 10)
295		Cvar_Set ("fov","10");
296	if (scr_fov.value > 170)
297		Cvar_Set ("fov","170");
298
299	r_refdef.fov_x = scr_fov.value;
300	r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height);
301
302// intermission is always full screen
303	if (cl.intermission)
304		size = 120;
305	else
306		size = scr_viewsize.value;
307
308	if (size >= 120)
309		sb_lines = 0;		// no status bar at all
310	else if (size >= 110)
311		sb_lines = 24;		// no inventory
312	else
313		sb_lines = 24+16+8;
314
315// these calculations mirror those in R_Init() for r_refdef, but take no
316// account of water warping
317	vrect.x = 0;
318	vrect.y = 0;
319	vrect.width = vid.width;
320	vrect.height = vid.height;
321
322	R_SetVrect (&vrect, &scr_vrect, sb_lines);
323
324// guard against going from one mode to another that's less than half the
325// vertical resolution
326	if (scr_con_current > vid.height)
327		scr_con_current = vid.height;
328
329// notify the refresh of the change
330	R_ViewChanged (&vrect, sb_lines, vid.aspect);
331}
332
333
334/*
335=================
336SCR_SizeUp_f
337
338Keybinding command
339=================
340*/
341void SCR_SizeUp_f (void)
342{
343	if (scr_viewsize.value < 120) {
344	Cvar_SetValue ("viewsize",scr_viewsize.value+10);
345	vid.recalc_refdef = 1;
346	}
347}
348
349
350/*
351=================
352SCR_SizeDown_f
353
354Keybinding command
355=================
356*/
357void SCR_SizeDown_f (void)
358{
359	Cvar_SetValue ("viewsize",scr_viewsize.value-10);
360	vid.recalc_refdef = 1;
361}
362
363//============================================================================
364
365/*
366==================
367SCR_Init
368==================
369*/
370void SCR_Init (void)
371{
372	Cvar_RegisterVariable (&scr_fov);
373	Cvar_RegisterVariable (&scr_viewsize);
374	Cvar_RegisterVariable (&scr_conspeed);
375	Cvar_RegisterVariable (&scr_showram);
376	Cvar_RegisterVariable (&scr_showturtle);
377	Cvar_RegisterVariable (&scr_showpause);
378	Cvar_RegisterVariable (&scr_centertime);
379	Cvar_RegisterVariable (&scr_printspeed);
380	Cvar_RegisterVariable (&scr_allowsnap);
381
382//
383// register our commands
384//
385	Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
386	Cmd_AddCommand ("snap",SCR_RSShot_f);
387	Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
388	Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
389
390	scr_ram = W_GetLumpName ("ram");
391	scr_net = W_GetLumpName ("net");
392	scr_turtle = W_GetLumpName ("turtle");
393
394	scr_initialized = true;
395}
396
397
398
399/*
400==============
401SCR_DrawRam
402==============
403*/
404void SCR_DrawRam (void)
405{
406	if (!scr_showram.value)
407		return;
408
409	if (!r_cache_thrash)
410		return;
411
412	Draw_Pic (scr_vrect.x+32, scr_vrect.y, scr_ram);
413}
414
415/*
416==============
417SCR_DrawTurtle
418==============
419*/
420void SCR_DrawTurtle (void)
421{
422	static int	count;
423
424	if (!scr_showturtle.value)
425		return;
426
427	if (host_frametime < 0.1)
428	{
429		count = 0;
430		return;
431	}
432
433	count++;
434	if (count < 3)
435		return;
436
437	Draw_Pic (scr_vrect.x, scr_vrect.y, scr_turtle);
438}
439
440/*
441==============
442SCR_DrawNet
443==============
444*/
445void SCR_DrawNet (void)
446{
447	if (cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged < UPDATE_BACKUP-1)
448		return;
449	if (cls.demoplayback)
450		return;
451
452	Draw_Pic (scr_vrect.x+64, scr_vrect.y, scr_net);
453}
454
455void SCR_DrawFPS (void)
456{
457	extern cvar_t show_fps;
458	static double lastframetime;
459	double t;
460	extern int fps_count;
461	static lastfps;
462	int x, y;
463	char st[80];
464
465	if (!show_fps.value)
466		return;
467
468	t = Sys_DoubleTime();
469	if ((t - lastframetime) >= 1.0) {
470		lastfps = fps_count;
471		fps_count = 0;
472		lastframetime = t;
473	}
474
475	sprintf(st, "%3d FPS", lastfps);
476	x = vid.width - strlen(st) * 8 - 8;
477	y = vid.height - sb_lines - 8;
478//	Draw_TileClear(x, y, strlen(st) * 8, 8);
479	Draw_String(x, y, st);
480}
481
482/*
483==============
484DrawPause
485==============
486*/
487void SCR_DrawPause (void)
488{
489	qpic_t	*pic;
490
491	if (!scr_showpause.value)		// turn off for screenshots
492		return;
493
494	if (!cl.paused)
495		return;
496
497	pic = Draw_CachePic ("gfx/pause.lmp");
498	Draw_Pic ( (vid.width - pic->width)/2,
499		(vid.height - 48 - pic->height)/2, pic);
500}
501
502
503//=============================================================================
504
505
506/*
507==================
508SCR_SetUpToDrawConsole
509==================
510*/
511void SCR_SetUpToDrawConsole (void)
512{
513	Con_CheckResize ();
514
515// decide on the height of the console
516	if (cls.state != ca_active)
517	{
518		scr_conlines = vid.height;		// full screen
519		scr_con_current = scr_conlines;
520	}
521	else if (key_dest == key_console)
522		scr_conlines = vid.height/2;	// half screen
523	else
524		scr_conlines = 0;				// none visible
525
526	if (scr_conlines < scr_con_current)
527	{
528		scr_con_current -= scr_conspeed.value*host_frametime;
529		if (scr_conlines > scr_con_current)
530			scr_con_current = scr_conlines;
531
532	}
533	else if (scr_conlines > scr_con_current)
534	{
535		scr_con_current += scr_conspeed.value*host_frametime;
536		if (scr_conlines < scr_con_current)
537			scr_con_current = scr_conlines;
538	}
539
540	if (clearconsole++ < vid.numpages)
541	{
542		scr_copytop = 1;
543		Draw_TileClear (0,(int)scr_con_current,vid.width, vid.height - (int)scr_con_current);
544		Sbar_Changed ();
545	}
546	else if (clearnotify++ < vid.numpages)
547	{
548		scr_copytop = 1;
549		Draw_TileClear (0,0,vid.width, con_notifylines);
550	}
551	else
552		con_notifylines = 0;
553}
554
555/*
556==================
557SCR_DrawConsole
558==================
559*/
560void SCR_DrawConsole (void)
561{
562	if (scr_con_current)
563	{
564		scr_copyeverything = 1;
565		Con_DrawConsole (scr_con_current);
566		clearconsole = 0;
567	}
568	else
569	{
570		if (key_dest == key_game || key_dest == key_message)
571			Con_DrawNotify ();	// only draw notify in game
572	}
573}
574
575
576/*
577==============================================================================
578
579						SCREEN SHOTS
580
581==============================================================================
582*/
583
584
585/*
586==============
587WritePCXfile
588==============
589*/
590void WritePCXfile (char *filename, byte *data, int width, int height,
591	int rowbytes, byte *palette, qboolean upload)
592{
593	int		i, j, length;
594	pcx_t	*pcx;
595	byte		*pack;
596
597	pcx = Hunk_TempAlloc (width*height*2+1000);
598	if (pcx == NULL)
599	{
600		Con_Printf("SCR_ScreenShot_f: not enough memory\n");
601		return;
602	}
603
604	pcx->manufacturer = 0x0a;	// PCX id
605	pcx->version = 5;			// 256 color
606 	pcx->encoding = 1;		// uncompressed
607	pcx->bits_per_pixel = 8;		// 256 color
608	pcx->xmin = 0;
609	pcx->ymin = 0;
610	pcx->xmax = LittleShort((short)(width-1));
611	pcx->ymax = LittleShort((short)(height-1));
612	pcx->hres = LittleShort((short)width);
613	pcx->vres = LittleShort((short)height);
614	Q_memset (pcx->palette,0,sizeof(pcx->palette));
615	pcx->color_planes = 1;		// chunky image
616	pcx->bytes_per_line = LittleShort((short)width);
617	pcx->palette_type = LittleShort(2);		// not a grey scale
618	Q_memset (pcx->filler,0,sizeof(pcx->filler));
619
620// pack the image
621	pack = &pcx->data;
622
623	for (i=0 ; i<height ; i++)
624	{
625		for (j=0 ; j<width ; j++)
626		{
627			if ( (*data & 0xc0) != 0xc0)
628				*pack++ = *data++;
629			else
630			{
631				*pack++ = 0xc1;
632				*pack++ = *data++;
633			}
634		}
635
636		data += rowbytes - width;
637	}
638
639// write the palette
640	*pack++ = 0x0c;	// palette ID byte
641	for (i=0 ; i<768 ; i++)
642		*pack++ = *palette++;
643
644// write output file
645	length = pack - (byte *)pcx;
646	if (upload)
647		CL_StartUpload((void *)pcx, length);
648	else
649		COM_WriteFile (filename, pcx, length);
650}
651
652
653
654/*
655==================
656SCR_ScreenShot_f
657==================
658*/
659void SCR_ScreenShot_f (void)
660{
661	int     i;
662	char		pcxname[80];
663	char		checkname[MAX_OSPATH];
664
665//
666// find a file name to save it to
667//
668	strcpy(pcxname,"quake00.pcx");
669
670	for (i=0 ; i<=99 ; i++)
671	{
672		pcxname[5] = i/10 + '0';
673		pcxname[6] = i%10 + '0';
674		sprintf (checkname, "%s/%s", com_gamedir, pcxname);
675		if (Sys_FileTime(checkname) == -1)
676			break;	// file doesn't exist
677	}
678	if (i==100)
679	{
680		Con_Printf ("SCR_ScreenShot_f: Couldn't create a PCX");
681		return;
682	}
683
684//
685// save the pcx file
686//
687	D_EnableBackBufferAccess ();	// enable direct drawing of console to back
688									//  buffer
689
690	WritePCXfile (pcxname, vid.buffer, vid.width, vid.height, vid.rowbytes,
691				  host_basepal, false);
692
693	D_DisableBackBufferAccess ();	// for adapters that can't stay mapped in
694									//  for linear writes all the time
695
696	Con_Printf ("Wrote %s\n", pcxname);
697}
698
699/*
700Find closest color in the palette for named color
701*/
702int MipColor(int r, int g, int b)
703{
704	int i;
705	float dist;
706	int best;
707	float bestdist;
708	int r1, g1, b1;
709	static int lr = -1, lg = -1, lb = -1;
710	static int lastbest;
711
712	if (r == lr && g == lg && b == lb)
713		return lastbest;
714
715	bestdist = 256*256*3;
716
717	for (i = 0; i < 256; i++) {
718		r1 = host_basepal[i*3] - r;
719		g1 = host_basepal[i*3+1] - g;
720		b1 = host_basepal[i*3+2] - b;
721		dist = r1*r1 + g1*g1 + b1*b1;
722		if (dist < bestdist) {
723			bestdist = dist;
724			best = i;
725		}
726	}
727	lr = r; lg = g; lb = b;
728	lastbest = best;
729	return best;
730}
731
732// in draw.c
733extern byte		*draw_chars;				// 8*8 graphic characters
734
735void SCR_DrawCharToSnap (int num, byte *dest, int width)
736{
737	int		row, col;
738	byte	*source;
739	int		drawline;
740	int		x;
741
742	row = num>>4;
743	col = num&15;
744	source = draw_chars + (row<<10) + (col<<3);
745
746	drawline = 8;
747
748	while (drawline--)
749	{
750		for (x=0 ; x<8 ; x++)
751			if (source[x])
752				dest[x] = source[x];
753			else
754				dest[x] = 98;
755		source += 128;
756		dest += width;
757	}
758
759}
760
761void SCR_DrawStringToSnap (const char *s, byte *buf, int x, int y, int width)
762{
763	byte *dest;
764	const unsigned char *p;
765
766	dest = buf + ((y * width) + x);
767
768	p = (const unsigned char *)s;
769	while (*p) {
770		SCR_DrawCharToSnap(*p++, dest, width);
771		dest += 8;
772	}
773}
774
775
776/*
777==================
778SCR_RSShot_f
779==================
780*/
781void SCR_RSShot_f (void)
782{
783	int     i, x, y;
784	unsigned char		*src, *dest;
785	char		pcxname[80];
786	char		checkname[MAX_OSPATH];
787	unsigned char		*newbuf, *srcbuf;
788	int srcrowbytes;
789	int w, h;
790	int dx, dy, dex, dey, nx;
791	int r, b, g;
792	int count;
793	float fracw, frach;
794	char st[80];
795	time_t now;
796
797	if (CL_IsUploading())
798		return; // already one pending
799
800	if (cls.state < ca_onserver)
801		return; // gotta be connected
802
803	if (!scr_allowsnap.value) {
804		MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
805		SZ_Print (&cls.netchan.message, "snap\n");
806		Con_Printf("Refusing remote screen shot request.\n");
807		return;
808	}
809
810	Con_Printf("Remote screen shot requested.\n");
811
812#if 0
813//
814// find a file name to save it to
815//
816	strcpy(pcxname,"mquake00.pcx");
817
818	for (i=0 ; i<=99 ; i++)
819	{
820		pcxname[6] = i/10 + '0';
821		pcxname[7] = i%10 + '0';
822		sprintf (checkname, "%s/%s", com_gamedir, pcxname);
823		if (Sys_FileTime(checkname) == -1)
824			break;	// file doesn't exist
825	}
826	if (i==100)
827	{
828		Con_Printf ("SCR_ScreenShot_f: Couldn't create a PCX");
829		return;
830	}
831#endif
832
833//
834// save the pcx file
835//
836	D_EnableBackBufferAccess ();	// enable direct drawing of console to back
837									//  buffer
838
839	w = (vid.width < RSSHOT_WIDTH) ? vid.width : RSSHOT_WIDTH;
840	h = (vid.height < RSSHOT_HEIGHT) ? vid.height : RSSHOT_HEIGHT;
841
842	fracw = (float)vid.width / (float)w;
843	frach = (float)vid.height / (float)h;
844
845	newbuf = malloc(w*h);
846
847	for (y = 0; y < h; y++) {
848		dest = newbuf + (w * y);
849
850		for (x = 0; x < w; x++) {
851			r = g = b = 0;
852
853			dx = x * fracw;
854			dex = (x + 1) * fracw;
855			if (dex == dx) dex++; // at least one
856			dy = y * frach;
857			dey = (y + 1) * frach;
858			if (dey == dy) dey++; // at least one
859
860			count = 0;
861			for (/* */; dy < dey; dy++) {
862				src = vid.buffer + (vid.rowbytes * dy) + dx;
863				for (nx = dx; nx < dex; nx++) {
864					r += host_basepal[*src * 3];
865					g += host_basepal[*src * 3+1];
866					b += host_basepal[*src * 3+2];
867					src++;
868					count++;
869				}
870			}
871			r /= count;
872			g /= count;
873			b /= count;
874			*dest++ = MipColor(r, g, b);
875		}
876	}
877
878	time(&now);
879	strcpy(st, ctime(&now));
880	st[strlen(st) - 1] = 0;
881	SCR_DrawStringToSnap (st, newbuf, w - strlen(st)*8, 0, w);
882
883	strncpy(st, cls.servername, sizeof(st));
884	st[sizeof(st) - 1] = 0;
885	SCR_DrawStringToSnap (st, newbuf, w - strlen(st)*8, 10, w);
886
887	strncpy(st, name.string, sizeof(st));
888	st[sizeof(st) - 1] = 0;
889	SCR_DrawStringToSnap (st, newbuf, w - strlen(st)*8, 20, w);
890
891	WritePCXfile (pcxname, newbuf, w, h, w, host_basepal, true);
892
893	free(newbuf);
894
895	D_DisableBackBufferAccess ();	// for adapters that can't stay mapped in
896									//  for linear writes all the time
897
898//	Con_Printf ("Wrote %s\n", pcxname);
899	Con_Printf ("Sending shot to server...\n");
900}
901
902
903//=============================================================================
904
905char	*scr_notifystring;
906qboolean	scr_drawdialog;
907
908void SCR_DrawNotifyString (void)
909{
910	char	*start;
911	int		l;
912	int		j;
913	int		x, y;
914
915	start = scr_notifystring;
916
917	y = vid.height*0.35;
918
919	do
920	{
921	// scan the width of the line
922		for (l=0 ; l<40 ; l++)
923			if (start[l] == '\n' || !start[l])
924				break;
925		x = (vid.width - l*8)/2;
926		for (j=0 ; j<l ; j++, x+=8)
927			Draw_Character (x, y, start[j]);
928
929		y += 8;
930
931		while (*start && *start != '\n')
932			start++;
933
934		if (!*start)
935			break;
936		start++;		// skip the \n
937	} while (1);
938}
939
940/*
941==================
942SCR_ModalMessage
943
944Displays a text string in the center of the screen and waits for a Y or N
945keypress.
946==================
947*/
948int SCR_ModalMessage (char *text)
949{
950	scr_notifystring = text;
951
952// draw a fresh screen
953	scr_fullupdate = 0;
954	scr_drawdialog = true;
955	SCR_UpdateScreen ();
956	scr_drawdialog = false;
957
958	S_ClearBuffer ();		// so dma doesn't loop current sound
959
960	do
961	{
962		key_count = -1;		// wait for a key down and up
963		Sys_SendKeyEvents ();
964	} while (key_lastpress != 'y' && key_lastpress != 'n' && key_lastpress != K_ESCAPE);
965
966	scr_fullupdate = 0;
967	SCR_UpdateScreen ();
968
969	return key_lastpress == 'y';
970}
971
972
973//=============================================================================
974
975/*
976===============
977SCR_BringDownConsole
978
979Brings the console down and fades the palettes back to normal
980================
981*/
982void SCR_BringDownConsole (void)
983{
984	int		i;
985
986	scr_centertime_off = 0;
987
988	for (i=0 ; i<20 && scr_conlines != scr_con_current ; i++)
989		SCR_UpdateScreen ();
990
991	cl.cshifts[0].percent = 0;		// no area contents palette on next frame
992	VID_SetPalette (host_basepal);
993}
994
995
996/*
997==================
998SCR_UpdateScreen
999
1000This is called every frame, and can also be called explicitly to flush
1001text to the screen.
1002
1003WARNING: be very careful calling this from elsewhere, because the refresh
1004needs almost the entire 256k of stack space!
1005==================
1006*/
1007void SCR_UpdateScreen (void)
1008{
1009	static float	oldscr_viewsize;
1010	vrect_t		vrect;
1011
1012	if (scr_skipupdate || block_drawing)
1013		return;
1014
1015	if (scr_disabled_for_loading)
1016		return;
1017
1018#ifdef _WIN32
1019	{	// don't suck up any cpu if minimized
1020		extern int Minimized;
1021
1022		if (Minimized)
1023			return;
1024	}
1025#endif
1026
1027	scr_copytop = 0;
1028	scr_copyeverything = 0;
1029
1030	if (!scr_initialized || !con_initialized)
1031		return;				// not initialized yet
1032
1033	if (scr_viewsize.value != oldscr_viewsize)
1034	{
1035		oldscr_viewsize = scr_viewsize.value;
1036		vid.recalc_refdef = 1;
1037	}
1038
1039//
1040// check for vid changes
1041//
1042	if (oldfov != scr_fov.value)
1043	{
1044		oldfov = scr_fov.value;
1045		vid.recalc_refdef = true;
1046	}
1047
1048	if (oldscreensize != scr_viewsize.value)
1049	{
1050		oldscreensize = scr_viewsize.value;
1051		vid.recalc_refdef = true;
1052	}
1053
1054	if (oldsbar != cl_sbar.value)
1055	{
1056		oldsbar = cl_sbar.value;
1057		vid.recalc_refdef = true;
1058	}
1059
1060	if (vid.recalc_refdef)
1061	{
1062		// something changed, so reorder the screen
1063		SCR_CalcRefdef ();
1064	}
1065
1066//
1067// do 3D refresh drawing, and then update the screen
1068//
1069	D_EnableBackBufferAccess ();	// of all overlay stuff if drawing directly
1070
1071	if (scr_fullupdate++ < vid.numpages)
1072	{	// clear the entire screen
1073		scr_copyeverything = 1;
1074		Draw_TileClear (0,0,vid.width,vid.height);
1075		Sbar_Changed ();
1076	}
1077
1078	pconupdate = NULL;
1079
1080
1081	SCR_SetUpToDrawConsole ();
1082	SCR_EraseCenterString ();
1083
1084	D_DisableBackBufferAccess ();	// for adapters that can't stay mapped in
1085									//  for linear writes all the time
1086
1087	VID_LockBuffer ();
1088	V_RenderView ();
1089	VID_UnlockBuffer ();
1090
1091	D_EnableBackBufferAccess ();	// of all overlay stuff if drawing directly
1092
1093	if (scr_drawdialog)
1094	{
1095		Sbar_Draw ();
1096		Draw_FadeScreen ();
1097		SCR_DrawNotifyString ();
1098		scr_copyeverything = true;
1099	}
1100	else if (cl.intermission == 1 && key_dest == key_game)
1101	{
1102		Sbar_IntermissionOverlay ();
1103	}
1104	else if (cl.intermission == 2 && key_dest == key_game)
1105	{
1106		Sbar_FinaleOverlay ();
1107		SCR_CheckDrawCenterString ();
1108	}
1109	else
1110	{
1111		SCR_DrawRam ();
1112		SCR_DrawNet ();
1113		SCR_DrawTurtle ();
1114		SCR_DrawPause ();
1115		SCR_DrawFPS ();
1116		SCR_CheckDrawCenterString ();
1117		Sbar_Draw ();
1118		SCR_DrawConsole ();
1119		M_Draw ();
1120	}
1121
1122
1123	D_DisableBackBufferAccess ();	// for adapters that can't stay mapped in
1124									//  for linear writes all the time
1125	if (pconupdate)
1126	{
1127		D_UpdateRects (pconupdate);
1128	}
1129
1130	V_UpdatePalette ();
1131
1132//
1133// update one of three areas
1134//
1135	if (scr_copyeverything)
1136	{
1137		vrect.x = 0;
1138		vrect.y = 0;
1139		vrect.width = vid.width;
1140		vrect.height = vid.height;
1141		vrect.pnext = 0;
1142
1143		VID_Update (&vrect);
1144	}
1145	else if (scr_copytop)
1146	{
1147		vrect.x = 0;
1148		vrect.y = 0;
1149		vrect.width = vid.width;
1150		vrect.height = vid.height - sb_lines;
1151		vrect.pnext = 0;
1152
1153		VID_Update (&vrect);
1154	}
1155	else
1156	{
1157		vrect.x = scr_vrect.x;
1158		vrect.y = scr_vrect.y;
1159		vrect.width = scr_vrect.width;
1160		vrect.height = scr_vrect.height;
1161		vrect.pnext = 0;
1162
1163		VID_Update (&vrect);
1164	}
1165}
1166
1167/*
1168==================
1169SCR_UpdateWholeScreen
1170==================
1171*/
1172void SCR_UpdateWholeScreen (void)
1173{
1174	scr_fullupdate = 0;
1175	SCR_UpdateScreen ();
1176}
1177