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