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// only the refresh window will be updated unless these variables are flagged 26int scr_copytop; 27int scr_copyeverything; 28 29float scr_con_current; 30float scr_conlines; // lines of console to display 31 32float oldscreensize, oldfov; 33cvar_t scr_viewsize = {"viewsize","100", true}; 34cvar_t scr_fov = {"fov","90"}; // 10 - 170 35cvar_t scr_conspeed = {"scr_conspeed","300"}; 36cvar_t scr_centertime = {"scr_centertime","2"}; 37cvar_t scr_showram = {"showram","1"}; 38cvar_t scr_showturtle = {"showturtle","0"}; 39cvar_t scr_showpause = {"showpause","1"}; 40cvar_t scr_printspeed = {"scr_printspeed","8"}; 41 42qboolean scr_initialized; // ready to draw 43 44qpic_t *scr_ram; 45qpic_t *scr_net; 46qpic_t *scr_turtle; 47 48int scr_fullupdate; 49 50int clearconsole; 51int clearnotify; 52 53viddef_t vid; // global video state 54 55vrect_t *pconupdate; 56vrect_t scr_vrect; 57 58qboolean scr_disabled_for_loading; 59qboolean scr_drawloading; 60float scr_disabled_time; 61qboolean scr_skipupdate; 62 63qboolean block_drawing; 64 65void SCR_ScreenShot_f (void); 66 67/* 68=============================================================================== 69 70CENTER PRINTING 71 72=============================================================================== 73*/ 74 75char scr_centerstring[1024]; 76float scr_centertime_start; // for slow victory printing 77float scr_centertime_off; 78int scr_center_lines; 79int scr_erase_lines; 80int scr_erase_center; 81 82/* 83============== 84SCR_CenterPrint 85 86Called for important messages that should stay in the center of the screen 87for a few moments 88============== 89*/ 90void SCR_CenterPrint (char *str) 91{ 92 strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1); 93 scr_centertime_off = scr_centertime.value; 94 scr_centertime_start = cl.time; 95 96// count the number of lines for centering 97 scr_center_lines = 1; 98 while (*str) 99 { 100 if (*str == '\n') 101 scr_center_lines++; 102 str++; 103 } 104} 105 106void SCR_EraseCenterString (void) 107{ 108 int y; 109 110 if (scr_erase_center++ > vid.numpages) 111 { 112 scr_erase_lines = 0; 113 return; 114 } 115 116 if (scr_center_lines <= 4) 117 y = vid.height*0.35; 118 else 119 y = 48; 120 121 scr_copytop = 1; 122 Draw_TileClear (0, y,vid.width, 8*scr_erase_lines); 123} 124 125void SCR_DrawCenterString (void) 126{ 127 char *start; 128 int l; 129 int j; 130 int x, y; 131 int remaining; 132 133// the finale prints the characters one at a time 134 if (cl.intermission) 135 remaining = scr_printspeed.value * (cl.time - scr_centertime_start); 136 else 137 remaining = 9999; 138 139 scr_erase_center = 0; 140 start = scr_centerstring; 141 142 if (scr_center_lines <= 4) 143 y = vid.height*0.35; 144 else 145 y = 48; 146 147 do 148 { 149 // scan the width of the line 150 for (l=0 ; l<40 ; l++) 151 if (start[l] == '\n' || !start[l]) 152 break; 153 x = (vid.width - l*8)/2; 154 for (j=0 ; j<l ; j++, x+=8) 155 { 156 Draw_Character (x, y, start[j]); 157 if (!remaining--) 158 return; 159 } 160 161 y += 8; 162 163 while (*start && *start != '\n') 164 start++; 165 166 if (!*start) 167 break; 168 start++; // skip the \n 169 } while (1); 170} 171 172void SCR_CheckDrawCenterString (void) 173{ 174 scr_copytop = 1; 175 if (scr_center_lines > scr_erase_lines) 176 scr_erase_lines = scr_center_lines; 177 178 scr_centertime_off -= host_frametime; 179 180 if (scr_centertime_off <= 0 && !cl.intermission) 181 return; 182 if (key_dest != key_game) 183 return; 184 185 SCR_DrawCenterString (); 186} 187 188//============================================================================= 189 190/* 191==================== 192CalcFov 193==================== 194*/ 195float CalcFov (float fov_x, float width, float height) 196{ 197 float a; 198 float x; 199 200 if (fov_x < 1 || fov_x > 179) 201 Sys_Error ("Bad fov: %f", fov_x); 202 203 x = width/tan(fov_x/360*M_PI); 204 205 a = atan (height/x); 206 207 a = a*360/M_PI; 208 209 return a; 210} 211 212/* 213================= 214SCR_CalcRefdef 215 216Must be called whenever vid changes 217Internal use only 218================= 219*/ 220static void SCR_CalcRefdef (void) 221{ 222 vrect_t vrect; 223 float size; 224 225 scr_fullupdate = 0; // force a background redraw 226 vid.recalc_refdef = 0; 227 228// force the status bar to redraw 229 Sbar_Changed (); 230 231//======================================== 232 233// bound viewsize 234 if (scr_viewsize.value < 30) 235 Cvar_Set ("viewsize","30"); 236 if (scr_viewsize.value > 120) 237 Cvar_Set ("viewsize","120"); 238 239// bound field of view 240 if (scr_fov.value < 10) 241 Cvar_Set ("fov","10"); 242 if (scr_fov.value > 170) 243 Cvar_Set ("fov","170"); 244 245 r_refdef.fov_x = scr_fov.value; 246 r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height); 247 248// intermission is always full screen 249 if (cl.intermission) 250 size = 120; 251 else 252 size = scr_viewsize.value; 253 254 if (size >= 120) 255 sb_lines = 0; // no status bar at all 256 else if (size >= 110) 257 sb_lines = 24; // no inventory 258 else 259 sb_lines = 24+16+8; 260 261// these calculations mirror those in R_Init() for r_refdef, but take no 262// account of water warping 263 vrect.x = 0; 264 vrect.y = 0; 265 vrect.width = vid.width; 266 vrect.height = vid.height; 267 268 R_SetVrect (&vrect, &scr_vrect, sb_lines); 269 270// guard against going from one mode to another that's less than half the 271// vertical resolution 272 if (scr_con_current > vid.height) 273 scr_con_current = vid.height; 274 275// notify the refresh of the change 276 R_ViewChanged (&vrect, sb_lines, vid.aspect); 277} 278 279 280/* 281================= 282SCR_SizeUp_f 283 284Keybinding command 285================= 286*/ 287void SCR_SizeUp_f (void) 288{ 289 Cvar_SetValue ("viewsize",scr_viewsize.value+10); 290 vid.recalc_refdef = 1; 291} 292 293 294/* 295================= 296SCR_SizeDown_f 297 298Keybinding command 299================= 300*/ 301void SCR_SizeDown_f (void) 302{ 303 Cvar_SetValue ("viewsize",scr_viewsize.value-10); 304 vid.recalc_refdef = 1; 305} 306 307//============================================================================ 308 309/* 310================== 311SCR_Init 312================== 313*/ 314void SCR_Init (void) 315{ 316 Cvar_RegisterVariable (&scr_fov); 317 Cvar_RegisterVariable (&scr_viewsize); 318 Cvar_RegisterVariable (&scr_conspeed); 319 Cvar_RegisterVariable (&scr_showram); 320 Cvar_RegisterVariable (&scr_showturtle); 321 Cvar_RegisterVariable (&scr_showpause); 322 Cvar_RegisterVariable (&scr_centertime); 323 Cvar_RegisterVariable (&scr_printspeed); 324 325// 326// register our commands 327// 328 Cmd_AddCommand ("screenshot",SCR_ScreenShot_f); 329 Cmd_AddCommand ("sizeup",SCR_SizeUp_f); 330 Cmd_AddCommand ("sizedown",SCR_SizeDown_f); 331 332 scr_ram = Draw_PicFromWad ("ram"); 333 scr_net = Draw_PicFromWad ("net"); 334 scr_turtle = Draw_PicFromWad ("turtle"); 335 336 scr_initialized = true; 337} 338 339 340 341/* 342============== 343SCR_DrawRam 344============== 345*/ 346void SCR_DrawRam (void) 347{ 348 if (!scr_showram.value) 349 return; 350 351 if (!r_cache_thrash) 352 return; 353 354 Draw_Pic (scr_vrect.x+32, scr_vrect.y, scr_ram); 355} 356 357/* 358============== 359SCR_DrawTurtle 360============== 361*/ 362void SCR_DrawTurtle (void) 363{ 364 static int count; 365 366 if (!scr_showturtle.value) 367 return; 368 369 if (host_frametime < 0.1) 370 { 371 count = 0; 372 return; 373 } 374 375 count++; 376 if (count < 3) 377 return; 378 379 Draw_Pic (scr_vrect.x, scr_vrect.y, scr_turtle); 380} 381 382/* 383============== 384SCR_DrawNet 385============== 386*/ 387void SCR_DrawNet (void) 388{ 389 if (realtime - cl.last_received_message < 0.3) 390 return; 391 if (cls.demoplayback) 392 return; 393 394 Draw_Pic (scr_vrect.x+64, scr_vrect.y, scr_net); 395} 396 397/* 398============== 399DrawPause 400============== 401*/ 402void SCR_DrawPause (void) 403{ 404 qpic_t *pic; 405 406 if (!scr_showpause.value) // turn off for screenshots 407 return; 408 409 if (!cl.paused) 410 return; 411 412 pic = Draw_CachePic ("gfx/pause.lmp"); 413 Draw_Pic ( (vid.width - pic->width)/2, 414 (vid.height - 48 - pic->height)/2, pic); 415} 416 417 418 419/* 420============== 421SCR_DrawLoading 422============== 423*/ 424void SCR_DrawLoading (void) 425{ 426 qpic_t *pic; 427 428 if (!scr_drawloading) 429 return; 430 431 pic = Draw_CachePic ("gfx/loading.lmp"); 432 Draw_Pic ( (vid.width - pic->width)/2, 433 (vid.height - 48 - pic->height)/2, pic); 434} 435 436 437 438//============================================================================= 439 440 441/* 442================== 443SCR_SetUpToDrawConsole 444================== 445*/ 446void SCR_SetUpToDrawConsole (void) 447{ 448 Con_CheckResize (); 449 450 if (scr_drawloading) 451 return; // never a console with loading plaque 452 453// decide on the height of the console 454 con_forcedup = !cl.worldmodel || cls.signon != SIGNONS; 455 456 if (con_forcedup) 457 { 458 scr_conlines = vid.height; // full screen 459 scr_con_current = scr_conlines; 460 } 461 else if (key_dest == key_console) 462 scr_conlines = vid.height/2; // half screen 463 else 464 scr_conlines = 0; // none visible 465 466 if (scr_conlines < scr_con_current) 467 { 468 scr_con_current -= scr_conspeed.value*host_frametime; 469 if (scr_conlines > scr_con_current) 470 scr_con_current = scr_conlines; 471 472 } 473 else if (scr_conlines > scr_con_current) 474 { 475 scr_con_current += scr_conspeed.value*host_frametime; 476 if (scr_conlines < scr_con_current) 477 scr_con_current = scr_conlines; 478 } 479 480 if (clearconsole++ < vid.numpages) 481 { 482 scr_copytop = 1; 483 Draw_TileClear (0,(int)scr_con_current,vid.width, vid.height - (int)scr_con_current); 484 Sbar_Changed (); 485 } 486 else if (clearnotify++ < vid.numpages) 487 { 488 scr_copytop = 1; 489 Draw_TileClear (0,0,vid.width, con_notifylines); 490 } 491 else 492 con_notifylines = 0; 493} 494 495/* 496================== 497SCR_DrawConsole 498================== 499*/ 500void SCR_DrawConsole (void) 501{ 502 if (scr_con_current) 503 { 504 scr_copyeverything = 1; 505 Con_DrawConsole (scr_con_current, true); 506 clearconsole = 0; 507 } 508 else 509 { 510 if (key_dest == key_game || key_dest == key_message) 511 Con_DrawNotify (); // only draw notify in game 512 } 513} 514 515 516/* 517============================================================================== 518 519 SCREEN SHOTS 520 521============================================================================== 522*/ 523 524 525typedef struct 526{ 527 char manufacturer; 528 char version; 529 char encoding; 530 char bits_per_pixel; 531 unsigned short xmin,ymin,xmax,ymax; 532 unsigned short hres,vres; 533 unsigned char palette[48]; 534 char reserved; 535 char color_planes; 536 unsigned short bytes_per_line; 537 unsigned short palette_type; 538 char filler[58]; 539 unsigned char data; // unbounded 540} pcx_t; 541 542/* 543============== 544WritePCXfile 545============== 546*/ 547void WritePCXfile (char *filename, byte *data, int width, int height, 548 int rowbytes, byte *palette) 549{ 550 int i, j, length; 551 pcx_t *pcx; 552 byte *pack; 553 554 pcx = Hunk_TempAlloc (width*height*2+1000); 555 if (pcx == NULL) 556 { 557 Con_Printf("SCR_ScreenShot_f: not enough memory\n"); 558 return; 559 } 560 561 pcx->manufacturer = 0x0a; // PCX id 562 pcx->version = 5; // 256 color 563 pcx->encoding = 1; // uncompressed 564 pcx->bits_per_pixel = 8; // 256 color 565 pcx->xmin = 0; 566 pcx->ymin = 0; 567 pcx->xmax = LittleShort((short)(width-1)); 568 pcx->ymax = LittleShort((short)(height-1)); 569 pcx->hres = LittleShort((short)width); 570 pcx->vres = LittleShort((short)height); 571 Q_memset (pcx->palette,0,sizeof(pcx->palette)); 572 pcx->color_planes = 1; // chunky image 573 pcx->bytes_per_line = LittleShort((short)width); 574 pcx->palette_type = LittleShort(2); // not a grey scale 575 Q_memset (pcx->filler,0,sizeof(pcx->filler)); 576 577// pack the image 578 pack = &pcx->data; 579 580 for (i=0 ; i<height ; i++) 581 { 582 for (j=0 ; j<width ; j++) 583 { 584 if ( (*data & 0xc0) != 0xc0) 585 *pack++ = *data++; 586 else 587 { 588 *pack++ = 0xc1; 589 *pack++ = *data++; 590 } 591 } 592 593 data += rowbytes - width; 594 } 595 596// write the palette 597 *pack++ = 0x0c; // palette ID byte 598 for (i=0 ; i<768 ; i++) 599 *pack++ = *palette++; 600 601// write output file 602 length = pack - (byte *)pcx; 603 COM_WriteFile (filename, pcx, length); 604} 605 606 607 608/* 609================== 610SCR_ScreenShot_f 611================== 612*/ 613void SCR_ScreenShot_f (void) 614{ 615 int i; 616 char pcxname[80]; 617 char checkname[MAX_OSPATH]; 618 619// 620// find a file name to save it to 621// 622 strcpy(pcxname,"quake00.pcx"); 623 624 for (i=0 ; i<=99 ; i++) 625 { 626 pcxname[5] = i/10 + '0'; 627 pcxname[6] = i%10 + '0'; 628 sprintf (checkname, "%s/%s", com_gamedir, pcxname); 629 if (Sys_FileTime(checkname) == -1) 630 break; // file doesn't exist 631 } 632 if (i==100) 633 { 634 Con_Printf ("SCR_ScreenShot_f: Couldn't create a PCX file\n"); 635 return; 636 } 637 638// 639// save the pcx file 640// 641 D_EnableBackBufferAccess (); // enable direct drawing of console to back 642 // buffer 643 644 WritePCXfile (pcxname, vid.buffer, vid.width, vid.height, vid.rowbytes, 645 host_basepal); 646 647 D_DisableBackBufferAccess (); // for adapters that can't stay mapped in 648 // for linear writes all the time 649 650 Con_Printf ("Wrote %s\n", pcxname); 651} 652 653 654//============================================================================= 655 656 657/* 658=============== 659SCR_BeginLoadingPlaque 660 661================ 662*/ 663void SCR_BeginLoadingPlaque (void) 664{ 665 S_StopAllSounds (true); 666 667 if (cls.state != ca_connected) 668 return; 669 if (cls.signon != SIGNONS) 670 return; 671 672// redraw with no console and the loading plaque 673 Con_ClearNotify (); 674 scr_centertime_off = 0; 675 scr_con_current = 0; 676 677 scr_drawloading = true; 678 scr_fullupdate = 0; 679 Sbar_Changed (); 680 SCR_UpdateScreen (); 681 scr_drawloading = false; 682 683 scr_disabled_for_loading = true; 684 scr_disabled_time = realtime; 685 scr_fullupdate = 0; 686} 687 688/* 689=============== 690SCR_EndLoadingPlaque 691 692================ 693*/ 694void SCR_EndLoadingPlaque (void) 695{ 696 scr_disabled_for_loading = false; 697 scr_fullupdate = 0; 698 Con_ClearNotify (); 699} 700 701//============================================================================= 702 703char *scr_notifystring; 704qboolean scr_drawdialog; 705 706void SCR_DrawNotifyString (void) 707{ 708 char *start; 709 int l; 710 int j; 711 int x, y; 712 713 start = scr_notifystring; 714 715 y = vid.height*0.35; 716 717 do 718 { 719 // scan the width of the line 720 for (l=0 ; l<40 ; l++) 721 if (start[l] == '\n' || !start[l]) 722 break; 723 x = (vid.width - l*8)/2; 724 for (j=0 ; j<l ; j++, x+=8) 725 Draw_Character (x, y, start[j]); 726 727 y += 8; 728 729 while (*start && *start != '\n') 730 start++; 731 732 if (!*start) 733 break; 734 start++; // skip the \n 735 } while (1); 736} 737 738/* 739================== 740SCR_ModalMessage 741 742Displays a text string in the center of the screen and waits for a Y or N 743keypress. 744================== 745*/ 746int SCR_ModalMessage (const char *text) 747{ 748 if (cls.state == ca_dedicated) 749 return true; 750 751 scr_notifystring = text; 752 753// draw a fresh screen 754 scr_fullupdate = 0; 755 scr_drawdialog = true; 756 SCR_UpdateScreen (); 757 scr_drawdialog = false; 758 759 S_ClearBuffer (); // so dma doesn't loop current sound 760 761 do 762 { 763 key_count = -1; // wait for a key down and up 764 Sys_SendKeyEvents (); 765 } while (key_lastpress != 'y' && key_lastpress != 'n' && key_lastpress != K_ESCAPE); 766 767 scr_fullupdate = 0; 768 SCR_UpdateScreen (); 769 770 return key_lastpress == 'y'; 771} 772 773 774//============================================================================= 775 776/* 777=============== 778SCR_BringDownConsole 779 780Brings the console down and fades the palettes back to normal 781================ 782*/ 783void SCR_BringDownConsole (void) 784{ 785 int i; 786 787 scr_centertime_off = 0; 788 789 for (i=0 ; i<20 && scr_conlines != scr_con_current ; i++) 790 SCR_UpdateScreen (); 791 792 cl.cshifts[0].percent = 0; // no area contents palette on next frame 793 VID_SetPalette (host_basepal); 794} 795 796 797/* 798================== 799SCR_UpdateScreen 800 801This is called every frame, and can also be called explicitly to flush 802text to the screen. 803 804WARNING: be very careful calling this from elsewhere, because the refresh 805needs almost the entire 256k of stack space! 806================== 807*/ 808void SCR_UpdateScreen (void) 809{ 810 static float oldscr_viewsize; 811 static float oldlcd_x; 812 vrect_t vrect; 813 814 if (scr_skipupdate || block_drawing) 815 return; 816 817 scr_copytop = 0; 818 scr_copyeverything = 0; 819 820 if (scr_disabled_for_loading) 821 { 822 if (realtime - scr_disabled_time > 60) 823 { 824 scr_disabled_for_loading = false; 825 Con_Printf ("load failed.\n"); 826 } 827 else 828 return; 829 } 830 831 if (cls.state == ca_dedicated) 832 return; // stdout only 833 834 if (!scr_initialized || !con_initialized) 835 return; // not initialized yet 836 837 if (scr_viewsize.value != oldscr_viewsize) 838 { 839 oldscr_viewsize = scr_viewsize.value; 840 vid.recalc_refdef = 1; 841 } 842 843// 844// check for vid changes 845// 846 if (oldfov != scr_fov.value) 847 { 848 oldfov = scr_fov.value; 849 vid.recalc_refdef = true; 850 } 851 852 if (oldlcd_x != lcd_x.value) 853 { 854 oldlcd_x = lcd_x.value; 855 vid.recalc_refdef = true; 856 } 857 858 if (oldscreensize != scr_viewsize.value) 859 { 860 oldscreensize = scr_viewsize.value; 861 vid.recalc_refdef = true; 862 } 863 864 if (vid.recalc_refdef) 865 { 866 // something changed, so reorder the screen 867 SCR_CalcRefdef (); 868 } 869 870// 871// do 3D refresh drawing, and then update the screen 872// 873 D_EnableBackBufferAccess (); // of all overlay stuff if drawing directly 874 875 if (scr_fullupdate++ < vid.numpages) 876 { // clear the entire screen 877 scr_copyeverything = 1; 878 Draw_TileClear (0,0,vid.width,vid.height); 879 Sbar_Changed (); 880 } 881 882 pconupdate = NULL; 883 884 885 SCR_SetUpToDrawConsole (); 886 SCR_EraseCenterString (); 887 888 D_DisableBackBufferAccess (); // for adapters that can't stay mapped in 889 // for linear writes all the time 890 891 VID_LockBuffer (); 892 893 V_RenderView (); 894 895 VID_UnlockBuffer (); 896 897 D_EnableBackBufferAccess (); // of all overlay stuff if drawing directly 898 899 if (scr_drawdialog) 900 { 901 Sbar_Draw (); 902 Draw_FadeScreen (); 903 SCR_DrawNotifyString (); 904 scr_copyeverything = true; 905 } 906 else if (scr_drawloading) 907 { 908 SCR_DrawLoading (); 909 Sbar_Draw (); 910 } 911 else if (cl.intermission == 1 && key_dest == key_game) 912 { 913 Sbar_IntermissionOverlay (); 914 } 915 else if (cl.intermission == 2 && key_dest == key_game) 916 { 917 Sbar_FinaleOverlay (); 918 SCR_CheckDrawCenterString (); 919 } 920 else if (cl.intermission == 3 && key_dest == key_game) 921 { 922 SCR_CheckDrawCenterString (); 923 } 924 else 925 { 926 SCR_DrawRam (); 927 SCR_DrawNet (); 928 SCR_DrawTurtle (); 929 SCR_DrawPause (); 930 SCR_CheckDrawCenterString (); 931 Sbar_Draw (); 932 SCR_DrawConsole (); 933 M_Draw (); 934 } 935 936 D_DisableBackBufferAccess (); // for adapters that can't stay mapped in 937 // for linear writes all the time 938 if (pconupdate) 939 { 940 D_UpdateRects (pconupdate); 941 } 942 943 V_UpdatePalette (); 944 945// 946// update one of three areas 947// 948 949 if (scr_copyeverything) 950 { 951 vrect.x = 0; 952 vrect.y = 0; 953 vrect.width = vid.width; 954 vrect.height = vid.height; 955 vrect.pnext = 0; 956 957 VID_Update (&vrect); 958 } 959 else if (scr_copytop) 960 { 961 vrect.x = 0; 962 vrect.y = 0; 963 vrect.width = vid.width; 964 vrect.height = vid.height - sb_lines; 965 vrect.pnext = 0; 966 967 VID_Update (&vrect); 968 } 969 else 970 { 971 vrect.x = scr_vrect.x; 972 vrect.y = scr_vrect.y; 973 vrect.width = scr_vrect.width; 974 vrect.height = scr_vrect.height; 975 vrect.pnext = 0; 976 977 VID_Update (&vrect); 978 } 979} 980 981 982/* 983================== 984SCR_UpdateWholeScreen 985================== 986*/ 987void SCR_UpdateWholeScreen (void) 988{ 989 scr_fullupdate = 0; 990 SCR_UpdateScreen (); 991} 992