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