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