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