|
|
1.1.1.3 ! root 1: /* ! 2: Copyright (C) 1997-2001 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: */ 1.1 root 20: // cl_scrn.c -- master for refresh, status bar, console, chat, notify, etc 1.1.1.2 root 21: 1.1 root 22: /* 1.1.1.2 root 23: 1.1 root 24: full screen console 25: put up loading plaque 26: blanked background with loading plaque 27: blanked background with menu 28: cinematics 29: full screen image for quit and victory 1.1.1.2 root 30: 1.1 root 31: end of unit intermissions 1.1.1.2 root 32: 1.1 root 33: */ 1.1.1.2 root 34: 1.1 root 35: #include "client.h" 1.1.1.2 root 36: 1.1 root 37: float scr_con_current; // aproaches scr_conlines at scr_conspeed 38: float scr_conlines; // 0.0 to 1.0 lines of console to display 1.1.1.2 root 39: 1.1 root 40: qboolean scr_initialized; // ready to draw 1.1.1.2 root 41: 1.1 root 42: int scr_draw_loading; 1.1.1.2 root 43: 1.1 root 44: vrect_t scr_vrect; // position of render window on screen 1.1.1.2 root 45: 46: 1.1 root 47: cvar_t *scr_viewsize; 48: cvar_t *scr_conspeed; 49: cvar_t *scr_centertime; 50: cvar_t *scr_showturtle; 51: cvar_t *scr_showpause; 52: cvar_t *scr_printspeed; 1.1.1.2 root 53: 1.1 root 54: cvar_t *scr_netgraph; 55: cvar_t *scr_timegraph; 56: cvar_t *scr_debuggraph; 57: cvar_t *scr_graphheight; 58: cvar_t *scr_graphscale; 59: cvar_t *scr_graphshift; 60: cvar_t *scr_drawall; 1.1.1.2 root 61: 1.1 root 62: typedef struct 63: { 64: int x1, y1, x2, y2; 65: } dirty_t; 1.1.1.2 root 66: 1.1 root 67: dirty_t scr_dirty, scr_old_dirty[2]; 68: 69: char crosshair_pic[MAX_QPATH]; 70: int crosshair_width, crosshair_height; 1.1.1.2 root 71: 1.1 root 72: void SCR_TimeRefresh_f (void); 73: void SCR_Loading_f (void); 1.1.1.2 root 74: 75: 1.1 root 76: /* 77: =============================================================================== 1.1.1.2 root 78: 1.1 root 79: BAR GRAPHS 1.1.1.2 root 80: 1.1 root 81: =============================================================================== 82: */ 83: 84: /* 85: ============== 86: CL_AddNetgraph 87: 88: A new packet was just parsed 89: ============== 90: */ 91: void CL_AddNetgraph (void) 92: { 93: int i; 94: int in; 95: int ping; 96: 97: // if using the debuggraph for something else, don't 98: // add the net lines 99: if (scr_debuggraph->value || scr_timegraph->value) 100: return; 101: 102: for (i=0 ; i<cls.netchan.dropped ; i++) 103: SCR_DebugGraph (30, 0x40); 104: 105: for (i=0 ; i<cl.surpressCount ; i++) 106: SCR_DebugGraph (30, 0xdf); 107: 108: // see what the latency was on this packet 109: in = cls.netchan.incoming_acknowledged & (CMD_BACKUP-1); 110: ping = cls.realtime - cl.cmd_time[in]; 111: ping /= 30; 112: if (ping > 30) 113: ping = 30; 114: SCR_DebugGraph (ping, 0xd0); 115: } 1.1.1.2 root 116: 117: 1.1 root 118: typedef struct 119: { 120: float value; 121: int color; 122: } graphsamp_t; 1.1.1.2 root 123: 1.1 root 124: static int current; 125: static graphsamp_t values[1024]; 1.1.1.2 root 126: 1.1 root 127: /* 128: ============== 129: SCR_DebugGraph 130: ============== 131: */ 132: void SCR_DebugGraph (float value, int color) 133: { 134: values[current&1023].value = value; 135: values[current&1023].color = color; 136: current++; 137: } 1.1.1.2 root 138: 1.1 root 139: /* 140: ============== 141: SCR_DrawDebugGraph 142: ============== 143: */ 144: void SCR_DrawDebugGraph (void) 145: { 146: int a, x, y, w, i, h; 147: float v; 148: int color; 1.1.1.2 root 149: 1.1 root 150: // 151: // draw the graph 152: // 153: w = scr_vrect.width; 1.1.1.2 root 154: 1.1 root 155: x = scr_vrect.x; 156: y = scr_vrect.y+scr_vrect.height; 157: re.DrawFill (x, y-scr_graphheight->value, 158: w, scr_graphheight->value, 8); 1.1.1.2 root 159: 1.1 root 160: for (a=0 ; a<w ; a++) 161: { 162: i = (current-1-a+1024) & 1023; 163: v = values[i].value; 164: color = values[i].color; 165: v = v*scr_graphscale->value + scr_graphshift->value; 166: 167: if (v < 0) 168: v += scr_graphheight->value * (1+(int)(-v/scr_graphheight->value)); 169: h = (int)v % (int)scr_graphheight->value; 170: re.DrawFill (x+w-1-a, y - h, 1, h, color); 171: } 172: } 1.1.1.2 root 173: 1.1 root 174: /* 175: =============================================================================== 1.1.1.2 root 176: 1.1 root 177: CENTER PRINTING 1.1.1.2 root 178: 1.1 root 179: =============================================================================== 180: */ 1.1.1.2 root 181: 1.1 root 182: char scr_centerstring[1024]; 183: float scr_centertime_start; // for slow victory printing 184: float scr_centertime_off; 185: int scr_center_lines; 186: int scr_erase_center; 1.1.1.2 root 187: 1.1 root 188: /* 189: ============== 190: SCR_CenterPrint 1.1.1.2 root 191: 1.1 root 192: Called for important messages that should stay in the center of the screen 193: for a few moments 194: ============== 195: */ 196: void SCR_CenterPrint (char *str) 197: { 198: char *s; 199: char line[64]; 200: int i, j, l; 1.1.1.2 root 201: 1.1 root 202: strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1); 203: scr_centertime_off = scr_centertime->value; 204: scr_centertime_start = cl.time; 1.1.1.2 root 205: 1.1 root 206: // count the number of lines for centering 207: scr_center_lines = 1; 208: s = str; 209: while (*s) 210: { 211: if (*s == '\n') 212: scr_center_lines++; 213: s++; 214: } 215: 216: // echo it to the console 217: Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n"); 218: 219: s = str; 220: do 221: { 222: // scan the width of the line 223: for (l=0 ; l<40 ; l++) 224: if (s[l] == '\n' || !s[l]) 225: break; 226: for (i=0 ; i<(40-l)/2 ; i++) 227: line[i] = ' '; 228: 229: for (j=0 ; j<l ; j++) 230: { 231: line[i++] = s[j]; 232: } 233: 234: line[i] = '\n'; 235: line[i+1] = 0; 236: 237: Com_Printf ("%s", line); 238: 239: while (*s && *s != '\n') 240: s++; 241: 242: if (!*s) 243: break; 244: s++; // skip the \n 245: } while (1); 246: Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n"); 247: Con_ClearNotify (); 248: } 1.1.1.2 root 249: 250: 1.1 root 251: void SCR_DrawCenterString (void) 252: { 253: char *start; 254: int l; 255: int j; 256: int x, y; 257: int remaining; 1.1.1.2 root 258: 1.1 root 259: // the finale prints the characters one at a time 260: remaining = 9999; 1.1.1.2 root 261: 1.1 root 262: scr_erase_center = 0; 263: start = scr_centerstring; 1.1.1.2 root 264: 1.1 root 265: if (scr_center_lines <= 4) 266: y = viddef.height*0.35; 267: else 268: y = 48; 1.1.1.2 root 269: 1.1 root 270: do 271: { 272: // scan the width of the line 273: for (l=0 ; l<40 ; l++) 274: if (start[l] == '\n' || !start[l]) 275: break; 276: x = (viddef.width - l*8)/2; 277: SCR_AddDirtyPoint (x, y); 278: for (j=0 ; j<l ; j++, x+=8) 279: { 280: re.DrawChar (x, y, start[j]); 281: if (!remaining--) 282: return; 283: } 284: SCR_AddDirtyPoint (x, y+8); 285: 286: y += 8; 1.1.1.2 root 287: 1.1 root 288: while (*start && *start != '\n') 289: start++; 1.1.1.2 root 290: 1.1 root 291: if (!*start) 292: break; 293: start++; // skip the \n 294: } while (1); 295: } 1.1.1.2 root 296: 1.1 root 297: void SCR_CheckDrawCenterString (void) 298: { 299: scr_centertime_off -= cls.frametime; 300: 301: if (scr_centertime_off <= 0) 302: return; 1.1.1.2 root 303: 1.1 root 304: SCR_DrawCenterString (); 305: } 1.1.1.2 root 306: 1.1 root 307: //============================================================================= 1.1.1.2 root 308: 1.1 root 309: /* 310: ================= 311: SCR_CalcVrect 1.1.1.2 root 312: 1.1 root 313: Sets scr_vrect, the coordinates of the rendered window 314: ================= 315: */ 316: static void SCR_CalcVrect (void) 317: { 318: int size; 1.1.1.2 root 319: 1.1 root 320: // bound viewsize 321: if (scr_viewsize->value < 40) 322: Cvar_Set ("viewsize","40"); 323: if (scr_viewsize->value > 100) 324: Cvar_Set ("viewsize","100"); 1.1.1.2 root 325: 1.1 root 326: size = scr_viewsize->value; 1.1.1.2 root 327: 1.1 root 328: scr_vrect.width = viddef.width*size/100; 329: scr_vrect.width &= ~7; 1.1.1.2 root 330: 1.1 root 331: scr_vrect.height = viddef.height*size/100; 332: scr_vrect.height &= ~1; 1.1.1.2 root 333: 1.1 root 334: scr_vrect.x = (viddef.width - scr_vrect.width)/2; 335: scr_vrect.y = (viddef.height - scr_vrect.height)/2; 336: } 1.1.1.2 root 337: 338: 1.1 root 339: /* 340: ================= 341: SCR_SizeUp_f 1.1.1.2 root 342: 1.1 root 343: Keybinding command 344: ================= 345: */ 346: void SCR_SizeUp_f (void) 347: { 348: Cvar_SetValue ("viewsize",scr_viewsize->value+10); 349: } 1.1.1.2 root 350: 351: 1.1 root 352: /* 353: ================= 354: SCR_SizeDown_f 1.1.1.2 root 355: 1.1 root 356: Keybinding command 357: ================= 358: */ 359: void SCR_SizeDown_f (void) 360: { 361: Cvar_SetValue ("viewsize",scr_viewsize->value-10); 362: } 1.1.1.2 root 363: 1.1 root 364: /* 365: ================= 366: SCR_Sky_f 1.1.1.2 root 367: 1.1 root 368: Set a specific sky and rotation speed 369: ================= 370: */ 371: void SCR_Sky_f (void) 372: { 373: float rotate; 374: vec3_t axis; 1.1.1.2 root 375: 1.1 root 376: if (Cmd_Argc() < 2) 377: { 378: Com_Printf ("Usage: sky <basename> <rotate> <axis x y z>\n"); 379: return; 380: } 381: if (Cmd_Argc() > 2) 382: rotate = atof(Cmd_Argv(2)); 383: else 384: rotate = 0; 385: if (Cmd_Argc() == 6) 386: { 387: axis[0] = atof(Cmd_Argv(3)); 388: axis[1] = atof(Cmd_Argv(4)); 389: axis[2] = atof(Cmd_Argv(5)); 390: } 391: else 392: { 393: axis[0] = 0; 394: axis[1] = 0; 395: axis[2] = 1; 396: } 1.1.1.2 root 397: 1.1 root 398: re.SetSky (Cmd_Argv(1), rotate, axis); 399: } 1.1.1.2 root 400: 1.1 root 401: //============================================================================ 1.1.1.2 root 402: 1.1 root 403: /* 404: ================== 405: SCR_Init 406: ================== 407: */ 408: void SCR_Init (void) 409: { 410: scr_viewsize = Cvar_Get ("viewsize", "100", CVAR_ARCHIVE); 411: scr_conspeed = Cvar_Get ("scr_conspeed", "3", 0); 412: scr_showturtle = Cvar_Get ("scr_showturtle", "0", 0); 413: scr_showpause = Cvar_Get ("scr_showpause", "1", 0); 414: scr_centertime = Cvar_Get ("scr_centertime", "2.5", 0); 415: scr_printspeed = Cvar_Get ("scr_printspeed", "8", 0); 416: scr_netgraph = Cvar_Get ("netgraph", "0", 0); 417: scr_timegraph = Cvar_Get ("timegraph", "0", 0); 418: scr_debuggraph = Cvar_Get ("debuggraph", "0", 0); 419: scr_graphheight = Cvar_Get ("graphheight", "32", 0); 420: scr_graphscale = Cvar_Get ("graphscale", "1", 0); 421: scr_graphshift = Cvar_Get ("graphshift", "0", 0); 422: scr_drawall = Cvar_Get ("scr_drawall", "0", 0); 1.1.1.2 root 423: 1.1 root 424: // 425: // register our commands 426: // 427: Cmd_AddCommand ("timerefresh",SCR_TimeRefresh_f); 428: Cmd_AddCommand ("loading",SCR_Loading_f); 429: Cmd_AddCommand ("sizeup",SCR_SizeUp_f); 430: Cmd_AddCommand ("sizedown",SCR_SizeDown_f); 431: Cmd_AddCommand ("sky",SCR_Sky_f); 1.1.1.2 root 432: 1.1 root 433: scr_initialized = true; 434: } 1.1.1.2 root 435: 436: 1.1 root 437: /* 438: ============== 439: SCR_DrawNet 440: ============== 441: */ 442: void SCR_DrawNet (void) 443: { 444: if (cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged 445: < CMD_BACKUP-1) 446: return; 1.1.1.2 root 447: 1.1 root 448: re.DrawPic (scr_vrect.x+64, scr_vrect.y, "net"); 449: } 1.1.1.2 root 450: 1.1 root 451: /* 452: ============== 453: SCR_DrawPause 454: ============== 455: */ 456: void SCR_DrawPause (void) 457: { 458: int w, h; 1.1.1.2 root 459: 1.1 root 460: if (!scr_showpause->value) // turn off for screenshots 461: return; 1.1.1.2 root 462: 1.1 root 463: if (!cl_paused->value) 464: return; 1.1.1.2 root 465: 1.1 root 466: re.DrawGetPicSize (&w, &h, "pause"); 467: re.DrawPic ((viddef.width-w)/2, viddef.height/2 + 8, "pause"); 468: } 1.1.1.2 root 469: 1.1 root 470: /* 471: ============== 472: SCR_DrawLoading 473: ============== 474: */ 475: void SCR_DrawLoading (void) 476: { 477: int w, h; 478: 479: if (!scr_draw_loading) 480: return; 1.1.1.2 root 481: 1.1 root 482: scr_draw_loading = false; 483: re.DrawGetPicSize (&w, &h, "loading"); 484: re.DrawPic ((viddef.width-w)/2, (viddef.height-h)/2, "loading"); 485: } 1.1.1.2 root 486: 1.1 root 487: //============================================================================= 1.1.1.2 root 488: 1.1 root 489: /* 490: ================== 491: SCR_RunConsole 1.1.1.2 root 492: 1.1 root 493: Scroll it up or down 494: ================== 495: */ 496: void SCR_RunConsole (void) 497: { 498: // decide on the height of the console 499: if (cls.key_dest == key_console) 500: scr_conlines = 0.5; // half screen 501: else 502: scr_conlines = 0; // none visible 503: 504: if (scr_conlines < scr_con_current) 505: { 506: scr_con_current -= scr_conspeed->value*cls.frametime; 507: if (scr_conlines > scr_con_current) 508: scr_con_current = scr_conlines; 1.1.1.2 root 509: 1.1 root 510: } 511: else if (scr_conlines > scr_con_current) 512: { 513: scr_con_current += scr_conspeed->value*cls.frametime; 514: if (scr_conlines < scr_con_current) 515: scr_con_current = scr_conlines; 516: } 1.1.1.2 root 517: 1.1 root 518: } 1.1.1.2 root 519: 1.1 root 520: /* 521: ================== 522: SCR_DrawConsole 523: ================== 524: */ 525: void SCR_DrawConsole (void) 526: { 527: Con_CheckResize (); 528: 529: if (cls.state == ca_disconnected || cls.state == ca_connecting) 530: { // forced full screen console 531: Con_DrawConsole (1.0); 532: return; 533: } 1.1.1.2 root 534: 1.1 root 535: if (cls.state != ca_active || !cl.refresh_prepped) 536: { // connected, but can't render 537: Con_DrawConsole (0.5); 538: re.DrawFill (0, viddef.height/2, viddef.width, viddef.height/2, 0); 539: return; 540: } 1.1.1.2 root 541: 1.1 root 542: if (scr_con_current) 543: { 544: Con_DrawConsole (scr_con_current); 545: } 546: else 547: { 548: if (cls.key_dest == key_game || cls.key_dest == key_message) 549: Con_DrawNotify (); // only draw notify in game 550: } 551: } 1.1.1.2 root 552: 1.1 root 553: //============================================================================= 1.1.1.2 root 554: 1.1 root 555: /* 556: ================ 557: SCR_BeginLoadingPlaque 558: ================ 559: */ 560: void SCR_BeginLoadingPlaque (void) 561: { 562: S_StopAllSounds (); 563: cl.sound_prepped = false; // don't play ambients 564: CDAudio_Stop (); 565: if (cls.disable_screen) 566: return; 567: if (developer->value) 568: return; 569: if (cls.state == ca_disconnected) 570: return; // if at console, don't bring up the plaque 571: if (cls.key_dest == key_console) 572: return; 573: if (cl.cinematictime > 0) 574: scr_draw_loading = 2; // clear to balack first 575: else 576: scr_draw_loading = 1; 577: SCR_UpdateScreen (); 578: cls.disable_screen = Sys_Milliseconds (); 579: cls.disable_servercount = cl.servercount; 580: } 1.1.1.2 root 581: 1.1 root 582: /* 583: ================ 584: SCR_EndLoadingPlaque 585: ================ 586: */ 587: void SCR_EndLoadingPlaque (void) 588: { 589: cls.disable_screen = 0; 590: Con_ClearNotify (); 591: } 1.1.1.2 root 592: 1.1 root 593: /* 594: ================ 595: SCR_Loading_f 596: ================ 597: */ 598: void SCR_Loading_f (void) 599: { 600: SCR_BeginLoadingPlaque (); 601: } 1.1.1.2 root 602: 1.1 root 603: /* 604: ================ 605: SCR_TimeRefresh_f 606: ================ 607: */ 608: int entitycmpfnc( const entity_t *a, const entity_t *b ) 609: { 610: /* 611: ** all other models are sorted by model then skin 612: */ 613: if ( a->model == b->model ) 614: { 615: return ( ( int ) a->skin - ( int ) b->skin ); 616: } 617: else 618: { 619: return ( ( int ) a->model - ( int ) b->model ); 620: } 621: } 622: 623: void SCR_TimeRefresh_f (void) 624: { 625: int i; 626: int start, stop; 627: float time; 628: 629: if ( cls.state != ca_active ) 630: return; 1.1.1.2 root 631: 1.1 root 632: start = Sys_Milliseconds (); 1.1.1.2 root 633: 1.1 root 634: if (Cmd_Argc() == 2) 635: { // run without page flipping 636: re.BeginFrame( 0 ); 637: for (i=0 ; i<128 ; i++) 638: { 639: cl.refdef.viewangles[1] = i/128.0*360.0; 640: re.RenderFrame (&cl.refdef); 641: } 642: re.EndFrame(); 643: } 644: else 645: { 646: for (i=0 ; i<128 ; i++) 647: { 648: cl.refdef.viewangles[1] = i/128.0*360.0; 1.1.1.2 root 649: 1.1 root 650: re.BeginFrame( 0 ); 651: re.RenderFrame (&cl.refdef); 652: re.EndFrame(); 653: } 654: } 1.1.1.2 root 655: 1.1 root 656: stop = Sys_Milliseconds (); 657: time = (stop-start)/1000.0; 658: Com_Printf ("%f seconds (%f fps)\n", time, 128/time); 659: } 1.1.1.2 root 660: 1.1 root 661: /* 662: ================= 663: SCR_AddDirtyPoint 664: ================= 665: */ 666: void SCR_AddDirtyPoint (int x, int y) 667: { 668: if (x < scr_dirty.x1) 669: scr_dirty.x1 = x; 670: if (x > scr_dirty.x2) 671: scr_dirty.x2 = x; 672: if (y < scr_dirty.y1) 673: scr_dirty.y1 = y; 674: if (y > scr_dirty.y2) 675: scr_dirty.y2 = y; 676: } 1.1.1.2 root 677: 1.1 root 678: void SCR_DirtyScreen (void) 679: { 680: SCR_AddDirtyPoint (0, 0); 681: SCR_AddDirtyPoint (viddef.width-1, viddef.height-1); 682: } 1.1.1.2 root 683: 1.1 root 684: /* 685: ============== 686: SCR_TileClear 1.1.1.2 root 687: 1.1 root 688: Clear any parts of the tiled background that were drawn on last frame 689: ============== 690: */ 691: void SCR_TileClear (void) 692: { 693: int i; 694: int top, bottom, left, right; 695: dirty_t clear; 696: 697: if (scr_drawall->value) 698: SCR_DirtyScreen (); // for power vr or broken page flippers... 1.1.1.2 root 699: 1.1 root 700: if (scr_con_current == 1.0) 701: return; // full screen console 702: if (scr_viewsize->value == 100) 703: return; // full screen rendering 704: if (cl.cinematictime > 0) 705: return; // full screen cinematic 1.1.1.2 root 706: 1.1 root 707: // erase rect will be the union of the past three frames 708: // so tripple buffering works properly 709: clear = scr_dirty; 710: for (i=0 ; i<2 ; i++) 711: { 712: if (scr_old_dirty[i].x1 < clear.x1) 713: clear.x1 = scr_old_dirty[i].x1; 714: if (scr_old_dirty[i].x2 > clear.x2) 715: clear.x2 = scr_old_dirty[i].x2; 716: if (scr_old_dirty[i].y1 < clear.y1) 717: clear.y1 = scr_old_dirty[i].y1; 718: if (scr_old_dirty[i].y2 > clear.y2) 719: clear.y2 = scr_old_dirty[i].y2; 720: } 1.1.1.2 root 721: 1.1 root 722: scr_old_dirty[1] = scr_old_dirty[0]; 723: scr_old_dirty[0] = scr_dirty; 1.1.1.2 root 724: 1.1 root 725: scr_dirty.x1 = 9999; 726: scr_dirty.x2 = -9999; 727: scr_dirty.y1 = 9999; 728: scr_dirty.y2 = -9999; 1.1.1.2 root 729: 1.1 root 730: // don't bother with anything convered by the console) 731: top = scr_con_current*viddef.height; 732: if (top >= clear.y1) 733: clear.y1 = top; 1.1.1.2 root 734: 1.1 root 735: if (clear.y2 <= clear.y1) 736: return; // nothing disturbed 1.1.1.2 root 737: 1.1 root 738: top = scr_vrect.y; 739: bottom = top + scr_vrect.height-1; 740: left = scr_vrect.x; 741: right = left + scr_vrect.width-1; 1.1.1.2 root 742: 1.1 root 743: if (clear.y1 < top) 744: { // clear above view screen 745: i = clear.y2 < top-1 ? clear.y2 : top-1; 746: re.DrawTileClear (clear.x1 , clear.y1, 747: clear.x2 - clear.x1 + 1, i - clear.y1+1, "backtile"); 748: clear.y1 = top; 749: } 750: if (clear.y2 > bottom) 751: { // clear below view screen 752: i = clear.y1 > bottom+1 ? clear.y1 : bottom+1; 753: re.DrawTileClear (clear.x1, i, 754: clear.x2-clear.x1+1, clear.y2-i+1, "backtile"); 755: clear.y2 = bottom; 756: } 757: if (clear.x1 < left) 758: { // clear left of view screen 759: i = clear.x2 < left-1 ? clear.x2 : left-1; 760: re.DrawTileClear (clear.x1, clear.y1, 761: i-clear.x1+1, clear.y2 - clear.y1 + 1, "backtile"); 762: clear.x1 = left; 763: } 764: if (clear.x2 > right) 765: { // clear left of view screen 766: i = clear.x1 > right+1 ? clear.x1 : right+1; 767: re.DrawTileClear (i, clear.y1, 768: clear.x2-i+1, clear.y2 - clear.y1 + 1, "backtile"); 769: clear.x2 = right; 770: } 1.1.1.2 root 771: 1.1 root 772: } 1.1.1.2 root 773: 774: 1.1 root 775: //=============================================================== 1.1.1.2 root 776: 777: 1.1 root 778: #define STAT_MINUS 10 // num frame for '-' stats digit 779: char *sb_nums[2][11] = 780: { 781: {"num_0", "num_1", "num_2", "num_3", "num_4", "num_5", 782: "num_6", "num_7", "num_8", "num_9", "num_minus"}, 783: {"anum_0", "anum_1", "anum_2", "anum_3", "anum_4", "anum_5", 784: "anum_6", "anum_7", "anum_8", "anum_9", "anum_minus"} 785: }; 1.1.1.2 root 786: 1.1 root 787: #define ICON_WIDTH 24 788: #define ICON_HEIGHT 24 789: #define CHAR_WIDTH 16 790: #define ICON_SPACE 8 1.1.1.2 root 791: 792: 793: 1.1 root 794: /* 795: ================ 796: SizeHUDString 1.1.1.2 root 797: 1.1 root 798: Allow embedded \n in the string 799: ================ 800: */ 801: void SizeHUDString (char *string, int *w, int *h) 802: { 803: int lines, width, current; 1.1.1.2 root 804: 1.1 root 805: lines = 1; 806: width = 0; 1.1.1.2 root 807: 1.1 root 808: current = 0; 809: while (*string) 810: { 811: if (*string == '\n') 812: { 813: lines++; 814: current = 0; 815: } 816: else 817: { 818: current++; 819: if (current > width) 820: width = current; 821: } 822: string++; 823: } 1.1.1.2 root 824: 1.1 root 825: *w = width * 8; 826: *h = lines * 8; 827: } 1.1.1.2 root 828: 1.1 root 829: void DrawHUDString (char *string, int x, int y, int centerwidth, int xor) 830: { 831: int margin; 832: char line[1024]; 833: int width; 834: int i; 1.1.1.2 root 835: 1.1 root 836: margin = x; 1.1.1.2 root 837: 1.1 root 838: while (*string) 839: { 840: // scan out one line of text from the string 841: width = 0; 842: while (*string && *string != '\n') 843: line[width++] = *string++; 844: line[width] = 0; 1.1.1.2 root 845: 1.1 root 846: if (centerwidth) 847: x = margin + (centerwidth - width*8)/2; 848: else 849: x = margin; 850: for (i=0 ; i<width ; i++) 851: { 852: re.DrawChar (x, y, line[i]^xor); 853: x += 8; 854: } 855: if (*string) 856: { 857: string++; // skip the \n 858: x = margin; 859: y += 8; 860: } 861: } 862: } 1.1.1.2 root 863: 864: 1.1 root 865: /* 866: ============== 867: SCR_DrawField 868: ============== 869: */ 870: void SCR_DrawField (int x, int y, int color, int width, int value) 871: { 872: char num[16], *ptr; 873: int l; 874: int frame; 1.1.1.2 root 875: 1.1 root 876: if (width < 1) 877: return; 1.1.1.2 root 878: 1.1 root 879: // draw number string 880: if (width > 5) 881: width = 5; 1.1.1.2 root 882: 1.1 root 883: SCR_AddDirtyPoint (x, y); 884: SCR_AddDirtyPoint (x+width*CHAR_WIDTH+2, y+23); 885: 886: Com_sprintf (num, sizeof(num), "%i", value); 887: l = strlen(num); 888: if (l > width) 889: l = width; 890: x += 2 + CHAR_WIDTH*(width - l); 1.1.1.2 root 891: 1.1 root 892: ptr = num; 893: while (*ptr && l) 894: { 895: if (*ptr == '-') 896: frame = STAT_MINUS; 897: else 898: frame = *ptr -'0'; 1.1.1.2 root 899: 1.1 root 900: re.DrawPic (x,y,sb_nums[color][frame]); 901: x += CHAR_WIDTH; 902: ptr++; 903: l--; 904: } 905: } 1.1.1.2 root 906: 907: 1.1 root 908: /* 909: =============== 910: SCR_TouchPics 1.1.1.2 root 911: 1.1 root 912: Allows rendering code to cache all needed sbar graphics 913: =============== 914: */ 915: void SCR_TouchPics (void) 916: { 917: int i, j; 1.1.1.2 root 918: 1.1 root 919: for (i=0 ; i<2 ; i++) 920: for (j=0 ; j<11 ; j++) 921: re.RegisterPic (sb_nums[i][j]); 922: 923: if (crosshair->value) 924: { 925: if (crosshair->value > 3 || crosshair->value < 0) 926: crosshair->value = 3; 927: 928: Com_sprintf (crosshair_pic, sizeof(crosshair_pic), "ch%i", (int)(crosshair->value)); 929: re.DrawGetPicSize (&crosshair_width, &crosshair_height, crosshair_pic); 930: if (!crosshair_width) 931: crosshair_pic[0] = 0; 932: } 933: } 1.1.1.2 root 934: 1.1 root 935: /* 936: ================ 937: SCR_ExecuteLayoutString 1.1.1.2 root 938: 1.1 root 939: ================ 940: */ 941: void SCR_ExecuteLayoutString (char *s) 942: { 943: int x, y; 944: int value; 945: char *token; 946: int width; 947: int index; 948: clientinfo_t *ci; 1.1.1.2 root 949: 1.1 root 950: if (cls.state != ca_active || !cl.refresh_prepped) 951: return; 1.1.1.2 root 952: 1.1 root 953: if (!s[0]) 954: return; 1.1.1.2 root 955: 1.1 root 956: x = 0; 957: y = 0; 958: width = 3; 1.1.1.2 root 959: 1.1 root 960: while (s) 961: { 962: token = COM_Parse (&s); 963: if (!strcmp(token, "xl")) 964: { 965: token = COM_Parse (&s); 966: x = atoi(token); 967: continue; 968: } 969: if (!strcmp(token, "xr")) 970: { 971: token = COM_Parse (&s); 972: x = viddef.width + atoi(token); 973: continue; 974: } 975: if (!strcmp(token, "xv")) 976: { 977: token = COM_Parse (&s); 978: x = viddef.width/2 - 160 + atoi(token); 979: continue; 980: } 1.1.1.2 root 981: 1.1 root 982: if (!strcmp(token, "yt")) 983: { 984: token = COM_Parse (&s); 985: y = atoi(token); 986: continue; 987: } 988: if (!strcmp(token, "yb")) 989: { 990: token = COM_Parse (&s); 991: y = viddef.height + atoi(token); 992: continue; 993: } 994: if (!strcmp(token, "yv")) 995: { 996: token = COM_Parse (&s); 997: y = viddef.height/2 - 120 + atoi(token); 998: continue; 999: } 1.1.1.2 root 1000: 1.1 root 1001: if (!strcmp(token, "pic")) 1002: { // draw a pic from a stat number 1003: token = COM_Parse (&s); 1004: value = cl.frame.playerstate.stats[atoi(token)]; 1005: if (value >= MAX_IMAGES) 1006: Com_Error (ERR_DROP, "Pic >= MAX_IMAGES"); 1007: if (cl.configstrings[CS_IMAGES+value]) 1008: { 1009: SCR_AddDirtyPoint (x, y); 1010: SCR_AddDirtyPoint (x+23, y+23); 1011: re.DrawPic (x, y, cl.configstrings[CS_IMAGES+value]); 1012: } 1013: continue; 1014: } 1015: 1016: if (!strcmp(token, "client")) 1017: { // draw a deathmatch client block 1018: int score, ping, time; 1019: 1020: token = COM_Parse (&s); 1021: x = viddef.width/2 - 160 + atoi(token); 1022: token = COM_Parse (&s); 1023: y = viddef.height/2 - 120 + atoi(token); 1024: SCR_AddDirtyPoint (x, y); 1025: SCR_AddDirtyPoint (x+159, y+31); 1026: 1027: token = COM_Parse (&s); 1028: value = atoi(token); 1029: if (value >= MAX_CLIENTS || value < 0) 1030: Com_Error (ERR_DROP, "client >= MAX_CLIENTS"); 1031: ci = &cl.clientinfo[value]; 1032: 1033: token = COM_Parse (&s); 1034: score = atoi(token); 1035: 1036: token = COM_Parse (&s); 1037: ping = atoi(token); 1038: 1039: token = COM_Parse (&s); 1040: time = atoi(token); 1041: 1042: DrawAltString (x+32, y, ci->name); 1043: DrawString (x+32, y+8, "Score: "); 1044: DrawAltString (x+32+7*8, y+8, va("%i", score)); 1045: DrawString (x+32, y+16, va("Ping: %i", ping)); 1046: DrawString (x+32, y+24, va("Time: %i", time)); 1047: 1048: if (!ci->icon) 1049: ci = &cl.baseclientinfo; 1050: re.DrawPic (x, y, ci->iconname); 1051: continue; 1052: } 1053: 1054: if (!strcmp(token, "ctf")) 1055: { // draw a ctf client block 1056: int score, ping; 1057: char block[80]; 1058: 1059: token = COM_Parse (&s); 1060: x = viddef.width/2 - 160 + atoi(token); 1061: token = COM_Parse (&s); 1062: y = viddef.height/2 - 120 + atoi(token); 1063: SCR_AddDirtyPoint (x, y); 1064: SCR_AddDirtyPoint (x+159, y+31); 1065: 1066: token = COM_Parse (&s); 1067: value = atoi(token); 1068: if (value >= MAX_CLIENTS || value < 0) 1069: Com_Error (ERR_DROP, "client >= MAX_CLIENTS"); 1070: ci = &cl.clientinfo[value]; 1071: 1072: token = COM_Parse (&s); 1073: score = atoi(token); 1074: 1075: token = COM_Parse (&s); 1076: ping = atoi(token); 1077: if (ping > 999) 1078: ping = 999; 1079: 1080: sprintf(block, "%3d %3d %-12.12s", score, ping, ci->name); 1081: 1082: if (value == cl.playernum) 1083: DrawAltString (x, y, block); 1084: else 1085: DrawString (x, y, block); 1086: continue; 1087: } 1088: 1089: if (!strcmp(token, "picn")) 1090: { // draw a pic from a name 1091: token = COM_Parse (&s); 1092: SCR_AddDirtyPoint (x, y); 1093: SCR_AddDirtyPoint (x+23, y+23); 1094: re.DrawPic (x, y, token); 1095: continue; 1096: } 1.1.1.2 root 1097: 1.1 root 1098: if (!strcmp(token, "num")) 1099: { // draw a number 1100: token = COM_Parse (&s); 1101: width = atoi(token); 1102: token = COM_Parse (&s); 1103: value = cl.frame.playerstate.stats[atoi(token)]; 1104: SCR_DrawField (x, y, 0, width, value); 1105: continue; 1106: } 1107: 1108: if (!strcmp(token, "hnum")) 1109: { // health number 1110: int color; 1111: 1112: width = 3; 1113: value = cl.frame.playerstate.stats[STAT_HEALTH]; 1114: if (value > 25) 1115: color = 0; // green 1116: else if (value > 0) 1117: color = (cl.frame.serverframe>>2) & 1; // flash 1118: else 1119: color = 1; 1120: 1121: if (cl.frame.playerstate.stats[STAT_FLASHES] & 1) 1122: re.DrawPic (x, y, "field_3"); 1123: 1124: SCR_DrawField (x, y, color, width, value); 1125: continue; 1126: } 1127: 1128: if (!strcmp(token, "anum")) 1129: { // ammo number 1130: int color; 1131: 1132: width = 3; 1133: value = cl.frame.playerstate.stats[STAT_AMMO]; 1134: if (value > 5) 1135: color = 0; // green 1136: else if (value >= 0) 1137: color = (cl.frame.serverframe>>2) & 1; // flash 1138: else 1139: continue; // negative number = don't show 1140: 1141: if (cl.frame.playerstate.stats[STAT_FLASHES] & 4) 1142: re.DrawPic (x, y, "field_3"); 1143: 1144: SCR_DrawField (x, y, color, width, value); 1145: continue; 1146: } 1147: 1148: if (!strcmp(token, "rnum")) 1149: { // armor number 1150: int color; 1151: 1152: width = 3; 1153: value = cl.frame.playerstate.stats[STAT_ARMOR]; 1154: if (value < 1) 1155: continue; 1156: 1157: color = 0; // green 1158: 1159: if (cl.frame.playerstate.stats[STAT_FLASHES] & 2) 1160: re.DrawPic (x, y, "field_3"); 1161: 1162: SCR_DrawField (x, y, color, width, value); 1163: continue; 1164: } 1165: 1166: 1167: if (!strcmp(token, "stat_string")) 1168: { 1169: token = COM_Parse (&s); 1170: index = atoi(token); 1171: if (index < 0 || index >= MAX_CONFIGSTRINGS) 1172: Com_Error (ERR_DROP, "Bad stat_string index"); 1173: index = cl.frame.playerstate.stats[index]; 1174: if (index < 0 || index >= MAX_CONFIGSTRINGS) 1175: Com_Error (ERR_DROP, "Bad stat_string index"); 1176: DrawString (x, y, cl.configstrings[index]); 1177: continue; 1178: } 1.1.1.2 root 1179: 1.1 root 1180: if (!strcmp(token, "cstring")) 1181: { 1182: token = COM_Parse (&s); 1183: DrawHUDString (token, x, y, 320, 0); 1184: continue; 1185: } 1.1.1.2 root 1186: 1.1 root 1187: if (!strcmp(token, "string")) 1188: { 1189: token = COM_Parse (&s); 1190: DrawString (x, y, token); 1191: continue; 1192: } 1193: 1194: if (!strcmp(token, "cstring2")) 1195: { 1196: token = COM_Parse (&s); 1197: DrawHUDString (token, x, y, 320,0x80); 1198: continue; 1199: } 1200: 1201: if (!strcmp(token, "string2")) 1202: { 1203: token = COM_Parse (&s); 1204: DrawAltString (x, y, token); 1205: continue; 1206: } 1.1.1.2 root 1207: 1.1 root 1208: if (!strcmp(token, "if")) 1209: { // draw a number 1210: token = COM_Parse (&s); 1211: value = cl.frame.playerstate.stats[atoi(token)]; 1212: if (!value) 1213: { // skip to endif 1214: while (s && strcmp(token, "endif") ) 1215: { 1216: token = COM_Parse (&s); 1217: } 1218: } 1.1.1.2 root 1219: 1.1 root 1220: continue; 1221: } 1.1.1.2 root 1222: 1223: 1.1 root 1224: } 1225: } 1.1.1.2 root 1226: 1227: 1.1 root 1228: /* 1229: ================ 1230: SCR_DrawStats 1.1.1.2 root 1231: 1.1 root 1232: The status bar is a small layout program that 1233: is based on the stats array 1234: ================ 1235: */ 1236: void SCR_DrawStats (void) 1237: { 1238: SCR_ExecuteLayoutString (cl.configstrings[CS_STATUSBAR]); 1239: } 1.1.1.2 root 1240: 1241: 1.1 root 1242: /* 1243: ================ 1244: SCR_DrawLayout 1.1.1.2 root 1245: 1.1 root 1246: ================ 1247: */ 1248: #define STAT_LAYOUTS 13 1.1.1.2 root 1249: 1.1 root 1250: void SCR_DrawLayout (void) 1251: { 1252: if (!cl.frame.playerstate.stats[STAT_LAYOUTS]) 1253: return; 1254: SCR_ExecuteLayoutString (cl.layout); 1255: } 1.1.1.2 root 1256: 1.1 root 1257: //======================================================= 1.1.1.2 root 1258: 1.1 root 1259: /* 1260: ================== 1261: SCR_UpdateScreen 1.1.1.2 root 1262: 1.1 root 1263: This is called every frame, and can also be called explicitly to flush 1264: text to the screen. 1265: ================== 1266: */ 1267: void SCR_UpdateScreen (void) 1268: { 1269: int numframes; 1270: int i; 1271: float separation[2] = { 0, 0 }; 1272: 1273: // if the screen is disabled (loading plaque is up, or vid mode changing) 1274: // do nothing at all 1275: if (cls.disable_screen) 1276: { 1277: if (Sys_Milliseconds() - cls.disable_screen > 120000) 1278: { 1279: cls.disable_screen = 0; 1280: Com_Printf ("Loading plaque timed out.\n"); 1281: } 1282: return; 1283: } 1284: 1285: if (!scr_initialized || !con.initialized) 1286: return; // not initialized yet 1287: 1288: /* 1289: ** range check cl_camera_separation so we don't inadvertently fry someone's 1290: ** brain 1291: */ 1292: if ( cl_stereo_separation->value > 1.0 ) 1293: Cvar_SetValue( "cl_stereo_separation", 1.0 ); 1294: else if ( cl_stereo_separation->value < 0 ) 1295: Cvar_SetValue( "cl_stereo_separation", 0.0 ); 1296: 1297: if ( cl_stereo->value ) 1298: { 1299: numframes = 2; 1300: separation[0] = -cl_stereo_separation->value / 2; 1301: separation[1] = cl_stereo_separation->value / 2; 1302: } 1303: else 1304: { 1305: separation[0] = 0; 1306: separation[1] = 0; 1307: numframes = 1; 1308: } 1.1.1.2 root 1309: 1.1 root 1310: for ( i = 0; i < numframes; i++ ) 1311: { 1312: re.BeginFrame( separation[i] ); 1.1.1.2 root 1313: 1.1 root 1314: if (scr_draw_loading == 2) 1315: { // loading plaque over black screen 1316: int w, h; 1.1.1.2 root 1317: 1.1 root 1318: re.CinematicSetPalette(NULL); 1319: scr_draw_loading = false; 1320: re.DrawGetPicSize (&w, &h, "loading"); 1321: re.DrawPic ((viddef.width-w)/2, (viddef.height-h)/2, "loading"); 1322: // re.EndFrame(); 1323: // return; 1324: } 1325: // if a cinematic is supposed to be running, handle menus 1326: // and console specially 1327: else if (cl.cinematictime > 0) 1328: { 1329: if (cls.key_dest == key_menu) 1330: { 1331: if (cl.cinematicpalette_active) 1332: { 1333: re.CinematicSetPalette(NULL); 1334: cl.cinematicpalette_active = false; 1335: } 1336: M_Draw (); 1337: // re.EndFrame(); 1338: // return; 1339: } 1340: else if (cls.key_dest == key_console) 1341: { 1342: if (cl.cinematicpalette_active) 1343: { 1344: re.CinematicSetPalette(NULL); 1345: cl.cinematicpalette_active = false; 1346: } 1347: SCR_DrawConsole (); 1348: // re.EndFrame(); 1349: // return; 1350: } 1351: else 1352: { 1353: SCR_DrawCinematic(); 1354: // re.EndFrame(); 1355: // return; 1356: } 1357: } 1358: else 1359: { 1.1.1.2 root 1360: 1.1 root 1361: // make sure the game palette is active 1362: if (cl.cinematicpalette_active) 1363: { 1364: re.CinematicSetPalette(NULL); 1365: cl.cinematicpalette_active = false; 1366: } 1.1.1.2 root 1367: 1.1 root 1368: // do 3D refresh drawing, and then update the screen 1369: SCR_CalcVrect (); 1.1.1.2 root 1370: 1.1 root 1371: // clear any dirty part of the background 1372: SCR_TileClear (); 1.1.1.2 root 1373: 1.1 root 1374: V_RenderView ( separation[i] ); 1.1.1.2 root 1375: 1.1 root 1376: SCR_DrawStats (); 1377: if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 1) 1378: SCR_DrawLayout (); 1379: if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 2) 1380: CL_DrawInventory (); 1381: 1382: SCR_DrawNet (); 1383: SCR_CheckDrawCenterString (); 1.1.1.2 root 1384: 1.1 root 1385: if (scr_timegraph->value) 1386: SCR_DebugGraph (cls.frametime*300, 0); 1.1.1.2 root 1387: 1.1 root 1388: if (scr_debuggraph->value || scr_timegraph->value || scr_netgraph->value) 1389: SCR_DrawDebugGraph (); 1.1.1.2 root 1390: 1.1 root 1391: SCR_DrawPause (); 1.1.1.2 root 1392: 1.1 root 1393: SCR_DrawConsole (); 1.1.1.2 root 1394: 1.1 root 1395: M_Draw (); 1.1.1.2 root 1396: 1.1 root 1397: SCR_DrawLoading (); 1398: } 1399: } 1400: re.EndFrame(); 1401: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.