ui_atoms.c (25522B)
1 /* 2 =========================================================================== 3 Copyright (C) 1999-2005 Id Software, Inc. 4 5 This file is part of Quake III Arena source code. 6 7 Quake III Arena source code is free software; you can redistribute it 8 and/or modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 2 of the License, 10 or (at your option) any later version. 11 12 Quake III Arena source code is distributed in the hope that it will be 13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with Foobar; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 =========================================================================== 21 */ 22 // 23 /********************************************************************** 24 UI_ATOMS.C 25 26 User interface building blocks and support functions. 27 **********************************************************************/ 28 #include "ui_local.h" 29 30 uiStatic_t uis; 31 qboolean m_entersound; // after a frame, so caching won't disrupt the sound 32 33 // these are here so the functions in q_shared.c can link 34 #ifndef UI_HARD_LINKED 35 36 void QDECL Com_Error( int level, const char *error, ... ) { 37 va_list argptr; 38 char text[1024]; 39 40 va_start (argptr, error); 41 vsprintf (text, error, argptr); 42 va_end (argptr); 43 44 trap_Error( va("%s", text) ); 45 } 46 47 void QDECL Com_Printf( const char *msg, ... ) { 48 va_list argptr; 49 char text[1024]; 50 51 va_start (argptr, msg); 52 vsprintf (text, msg, argptr); 53 va_end (argptr); 54 55 trap_Print( va("%s", text) ); 56 } 57 58 #endif 59 60 /* 61 ================= 62 UI_ClampCvar 63 ================= 64 */ 65 float UI_ClampCvar( float min, float max, float value ) 66 { 67 if ( value < min ) return min; 68 if ( value > max ) return max; 69 return value; 70 } 71 72 /* 73 ================= 74 UI_StartDemoLoop 75 ================= 76 */ 77 void UI_StartDemoLoop( void ) { 78 trap_Cmd_ExecuteText( EXEC_APPEND, "d1\n" ); 79 } 80 81 /* 82 ================= 83 UI_PushMenu 84 ================= 85 */ 86 void UI_PushMenu( menuframework_s *menu ) 87 { 88 int i; 89 menucommon_s* item; 90 91 // avoid stacking menus invoked by hotkeys 92 for (i=0 ; i<uis.menusp ; i++) 93 { 94 if (uis.stack[i] == menu) 95 { 96 uis.menusp = i; 97 break; 98 } 99 } 100 101 if (i == uis.menusp) 102 { 103 if (uis.menusp >= MAX_MENUDEPTH) 104 trap_Error("UI_PushMenu: menu stack overflow"); 105 106 uis.stack[uis.menusp++] = menu; 107 } 108 109 uis.activemenu = menu; 110 111 // default cursor position 112 menu->cursor = 0; 113 menu->cursor_prev = 0; 114 115 m_entersound = qtrue; 116 117 trap_Key_SetCatcher( KEYCATCH_UI ); 118 119 // force first available item to have focus 120 for (i=0; i<menu->nitems; i++) 121 { 122 item = (menucommon_s *)menu->items[i]; 123 if (!(item->flags & (QMF_GRAYED|QMF_MOUSEONLY|QMF_INACTIVE))) 124 { 125 menu->cursor_prev = -1; 126 Menu_SetCursor( menu, i ); 127 break; 128 } 129 } 130 131 uis.firstdraw = qtrue; 132 } 133 134 /* 135 ================= 136 UI_PopMenu 137 ================= 138 */ 139 void UI_PopMenu (void) 140 { 141 trap_S_StartLocalSound( menu_out_sound, CHAN_LOCAL_SOUND ); 142 143 uis.menusp--; 144 145 if (uis.menusp < 0) 146 trap_Error ("UI_PopMenu: menu stack underflow"); 147 148 if (uis.menusp) { 149 uis.activemenu = uis.stack[uis.menusp-1]; 150 uis.firstdraw = qtrue; 151 } 152 else { 153 UI_ForceMenuOff (); 154 } 155 } 156 157 void UI_ForceMenuOff (void) 158 { 159 uis.menusp = 0; 160 uis.activemenu = NULL; 161 162 trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI ); 163 trap_Key_ClearStates(); 164 trap_Cvar_Set( "cl_paused", "0" ); 165 } 166 167 /* 168 ================= 169 UI_LerpColor 170 ================= 171 */ 172 void UI_LerpColor(vec4_t a, vec4_t b, vec4_t c, float t) 173 { 174 int i; 175 176 // lerp and clamp each component 177 for (i=0; i<4; i++) 178 { 179 c[i] = a[i] + t*(b[i]-a[i]); 180 if (c[i] < 0) 181 c[i] = 0; 182 else if (c[i] > 1.0) 183 c[i] = 1.0; 184 } 185 } 186 187 /* 188 ================= 189 UI_DrawProportionalString2 190 ================= 191 */ 192 static int propMap[128][3] = { 193 {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, 194 {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, 195 196 {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, 197 {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, 198 199 {0, 0, PROP_SPACE_WIDTH}, // SPACE 200 {11, 122, 7}, // ! 201 {154, 181, 14}, // " 202 {55, 122, 17}, // # 203 {79, 122, 18}, // $ 204 {101, 122, 23}, // % 205 {153, 122, 18}, // & 206 {9, 93, 7}, // ' 207 {207, 122, 8}, // ( 208 {230, 122, 9}, // ) 209 {177, 122, 18}, // * 210 {30, 152, 18}, // + 211 {85, 181, 7}, // , 212 {34, 93, 11}, // - 213 {110, 181, 6}, // . 214 {130, 152, 14}, // / 215 216 {22, 64, 17}, // 0 217 {41, 64, 12}, // 1 218 {58, 64, 17}, // 2 219 {78, 64, 18}, // 3 220 {98, 64, 19}, // 4 221 {120, 64, 18}, // 5 222 {141, 64, 18}, // 6 223 {204, 64, 16}, // 7 224 {162, 64, 17}, // 8 225 {182, 64, 18}, // 9 226 {59, 181, 7}, // : 227 {35,181, 7}, // ; 228 {203, 152, 14}, // < 229 {56, 93, 14}, // = 230 {228, 152, 14}, // > 231 {177, 181, 18}, // ? 232 233 {28, 122, 22}, // @ 234 {5, 4, 18}, // A 235 {27, 4, 18}, // B 236 {48, 4, 18}, // C 237 {69, 4, 17}, // D 238 {90, 4, 13}, // E 239 {106, 4, 13}, // F 240 {121, 4, 18}, // G 241 {143, 4, 17}, // H 242 {164, 4, 8}, // I 243 {175, 4, 16}, // J 244 {195, 4, 18}, // K 245 {216, 4, 12}, // L 246 {230, 4, 23}, // M 247 {6, 34, 18}, // N 248 {27, 34, 18}, // O 249 250 {48, 34, 18}, // P 251 {68, 34, 18}, // Q 252 {90, 34, 17}, // R 253 {110, 34, 18}, // S 254 {130, 34, 14}, // T 255 {146, 34, 18}, // U 256 {166, 34, 19}, // V 257 {185, 34, 29}, // W 258 {215, 34, 18}, // X 259 {234, 34, 18}, // Y 260 {5, 64, 14}, // Z 261 {60, 152, 7}, // [ 262 {106, 151, 13}, // '\' 263 {83, 152, 7}, // ] 264 {128, 122, 17}, // ^ 265 {4, 152, 21}, // _ 266 267 {134, 181, 5}, // ' 268 {5, 4, 18}, // A 269 {27, 4, 18}, // B 270 {48, 4, 18}, // C 271 {69, 4, 17}, // D 272 {90, 4, 13}, // E 273 {106, 4, 13}, // F 274 {121, 4, 18}, // G 275 {143, 4, 17}, // H 276 {164, 4, 8}, // I 277 {175, 4, 16}, // J 278 {195, 4, 18}, // K 279 {216, 4, 12}, // L 280 {230, 4, 23}, // M 281 {6, 34, 18}, // N 282 {27, 34, 18}, // O 283 284 {48, 34, 18}, // P 285 {68, 34, 18}, // Q 286 {90, 34, 17}, // R 287 {110, 34, 18}, // S 288 {130, 34, 14}, // T 289 {146, 34, 18}, // U 290 {166, 34, 19}, // V 291 {185, 34, 29}, // W 292 {215, 34, 18}, // X 293 {234, 34, 18}, // Y 294 {5, 64, 14}, // Z 295 {153, 152, 13}, // { 296 {11, 181, 5}, // | 297 {180, 152, 13}, // } 298 {79, 93, 17}, // ~ 299 {0, 0, -1} // DEL 300 }; 301 302 static int propMapB[26][3] = { 303 {11, 12, 33}, 304 {49, 12, 31}, 305 {85, 12, 31}, 306 {120, 12, 30}, 307 {156, 12, 21}, 308 {183, 12, 21}, 309 {207, 12, 32}, 310 311 {13, 55, 30}, 312 {49, 55, 13}, 313 {66, 55, 29}, 314 {101, 55, 31}, 315 {135, 55, 21}, 316 {158, 55, 40}, 317 {204, 55, 32}, 318 319 {12, 97, 31}, 320 {48, 97, 31}, 321 {82, 97, 30}, 322 {118, 97, 30}, 323 {153, 97, 30}, 324 {185, 97, 25}, 325 {213, 97, 30}, 326 327 {11, 139, 32}, 328 {42, 139, 51}, 329 {93, 139, 32}, 330 {126, 139, 31}, 331 {158, 139, 25}, 332 }; 333 334 #define PROPB_GAP_WIDTH 4 335 #define PROPB_SPACE_WIDTH 12 336 #define PROPB_HEIGHT 36 337 338 // bk001205 - code below duplicated in cgame/cg_drawtools.c 339 // bk001205 - FIXME: does this belong in ui_shared.c? 340 /* 341 ================= 342 UI_DrawBannerString 343 ================= 344 */ 345 static void UI_DrawBannerString2( int x, int y, const char* str, vec4_t color ) 346 { 347 const char* s; 348 unsigned char ch; // bk001204 - unsigned 349 float ax; 350 float ay; 351 float aw; 352 float ah; 353 float frow; 354 float fcol; 355 float fwidth; 356 float fheight; 357 358 // draw the colored text 359 trap_R_SetColor( color ); 360 361 ax = x * uis.scale + uis.bias; 362 ay = y * uis.scale; 363 364 s = str; 365 while ( *s ) 366 { 367 ch = *s & 127; 368 if ( ch == ' ' ) { 369 ax += ((float)PROPB_SPACE_WIDTH + (float)PROPB_GAP_WIDTH)* uis.scale; 370 } 371 else if ( ch >= 'A' && ch <= 'Z' ) { 372 ch -= 'A'; 373 fcol = (float)propMapB[ch][0] / 256.0f; 374 frow = (float)propMapB[ch][1] / 256.0f; 375 fwidth = (float)propMapB[ch][2] / 256.0f; 376 fheight = (float)PROPB_HEIGHT / 256.0f; 377 aw = (float)propMapB[ch][2] * uis.scale; 378 ah = (float)PROPB_HEIGHT * uis.scale; 379 trap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol+fwidth, frow+fheight, uis.charsetPropB ); 380 ax += (aw + (float)PROPB_GAP_WIDTH * uis.scale); 381 } 382 s++; 383 } 384 385 trap_R_SetColor( NULL ); 386 } 387 388 void UI_DrawBannerString( int x, int y, const char* str, int style, vec4_t color ) { 389 const char * s; 390 int ch; 391 int width; 392 vec4_t drawcolor; 393 394 // find the width of the drawn text 395 s = str; 396 width = 0; 397 while ( *s ) { 398 ch = *s; 399 if ( ch == ' ' ) { 400 width += PROPB_SPACE_WIDTH; 401 } 402 else if ( ch >= 'A' && ch <= 'Z' ) { 403 width += propMapB[ch - 'A'][2] + PROPB_GAP_WIDTH; 404 } 405 s++; 406 } 407 width -= PROPB_GAP_WIDTH; 408 409 switch( style & UI_FORMATMASK ) { 410 case UI_CENTER: 411 x -= width / 2; 412 break; 413 414 case UI_RIGHT: 415 x -= width; 416 break; 417 418 case UI_LEFT: 419 default: 420 break; 421 } 422 423 if ( style & UI_DROPSHADOW ) { 424 drawcolor[0] = drawcolor[1] = drawcolor[2] = 0; 425 drawcolor[3] = color[3]; 426 UI_DrawBannerString2( x+2, y+2, str, drawcolor ); 427 } 428 429 UI_DrawBannerString2( x, y, str, color ); 430 } 431 432 433 int UI_ProportionalStringWidth( const char* str ) { 434 const char * s; 435 int ch; 436 int charWidth; 437 int width; 438 439 s = str; 440 width = 0; 441 while ( *s ) { 442 ch = *s & 127; 443 charWidth = propMap[ch][2]; 444 if ( charWidth != -1 ) { 445 width += charWidth; 446 width += PROP_GAP_WIDTH; 447 } 448 s++; 449 } 450 451 width -= PROP_GAP_WIDTH; 452 return width; 453 } 454 455 static void UI_DrawProportionalString2( int x, int y, const char* str, vec4_t color, float sizeScale, qhandle_t charset ) 456 { 457 const char* s; 458 unsigned char ch; // bk001204 - unsigned 459 float ax; 460 float ay; 461 float aw = 0; // bk001204 - init 462 float ah; 463 float frow; 464 float fcol; 465 float fwidth; 466 float fheight; 467 468 // draw the colored text 469 trap_R_SetColor( color ); 470 471 ax = x * uis.scale + uis.bias; 472 ay = y * uis.scale; 473 474 s = str; 475 while ( *s ) 476 { 477 ch = *s & 127; 478 if ( ch == ' ' ) { 479 aw = (float)PROP_SPACE_WIDTH * uis.scale * sizeScale; 480 } 481 else if ( propMap[ch][2] != -1 ) { 482 fcol = (float)propMap[ch][0] / 256.0f; 483 frow = (float)propMap[ch][1] / 256.0f; 484 fwidth = (float)propMap[ch][2] / 256.0f; 485 fheight = (float)PROP_HEIGHT / 256.0f; 486 aw = (float)propMap[ch][2] * uis.scale * sizeScale; 487 ah = (float)PROP_HEIGHT * uis.scale * sizeScale; 488 trap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol+fwidth, frow+fheight, charset ); 489 } 490 491 ax += (aw + (float)PROP_GAP_WIDTH * uis.scale * sizeScale); 492 s++; 493 } 494 495 trap_R_SetColor( NULL ); 496 } 497 498 /* 499 ================= 500 UI_ProportionalSizeScale 501 ================= 502 */ 503 float UI_ProportionalSizeScale( int style ) { 504 if( style & UI_SMALLFONT ) { 505 return PROP_SMALL_SIZE_SCALE; 506 } 507 508 return 1.00; 509 } 510 511 512 /* 513 ================= 514 UI_DrawProportionalString 515 ================= 516 */ 517 void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color ) { 518 vec4_t drawcolor; 519 int width; 520 float sizeScale; 521 522 sizeScale = UI_ProportionalSizeScale( style ); 523 524 switch( style & UI_FORMATMASK ) { 525 case UI_CENTER: 526 width = UI_ProportionalStringWidth( str ) * sizeScale; 527 x -= width / 2; 528 break; 529 530 case UI_RIGHT: 531 width = UI_ProportionalStringWidth( str ) * sizeScale; 532 x -= width; 533 break; 534 535 case UI_LEFT: 536 default: 537 break; 538 } 539 540 if ( style & UI_DROPSHADOW ) { 541 drawcolor[0] = drawcolor[1] = drawcolor[2] = 0; 542 drawcolor[3] = color[3]; 543 UI_DrawProportionalString2( x+2, y+2, str, drawcolor, sizeScale, uis.charsetProp ); 544 } 545 546 if ( style & UI_INVERSE ) { 547 drawcolor[0] = color[0] * 0.7; 548 drawcolor[1] = color[1] * 0.7; 549 drawcolor[2] = color[2] * 0.7; 550 drawcolor[3] = color[3]; 551 UI_DrawProportionalString2( x, y, str, drawcolor, sizeScale, uis.charsetProp ); 552 return; 553 } 554 555 if ( style & UI_PULSE ) { 556 drawcolor[0] = color[0] * 0.7; 557 drawcolor[1] = color[1] * 0.7; 558 drawcolor[2] = color[2] * 0.7; 559 drawcolor[3] = color[3]; 560 UI_DrawProportionalString2( x, y, str, color, sizeScale, uis.charsetProp ); 561 562 drawcolor[0] = color[0]; 563 drawcolor[1] = color[1]; 564 drawcolor[2] = color[2]; 565 drawcolor[3] = 0.5 + 0.5 * sin( uis.realtime / PULSE_DIVISOR ); 566 UI_DrawProportionalString2( x, y, str, drawcolor, sizeScale, uis.charsetPropGlow ); 567 return; 568 } 569 570 UI_DrawProportionalString2( x, y, str, color, sizeScale, uis.charsetProp ); 571 } 572 573 /* 574 ================= 575 UI_DrawProportionalString_Wrapped 576 ================= 577 */ 578 void UI_DrawProportionalString_AutoWrapped( int x, int y, int xmax, int ystep, const char* str, int style, vec4_t color ) { 579 int width; 580 char *s1,*s2,*s3; 581 char c_bcp; 582 char buf[1024]; 583 float sizeScale; 584 585 if (!str || str[0]=='\0') 586 return; 587 588 sizeScale = UI_ProportionalSizeScale( style ); 589 590 Q_strncpyz(buf, str, sizeof(buf)); 591 s1 = s2 = s3 = buf; 592 593 while (1) { 594 do { 595 s3++; 596 } while (*s3!=' ' && *s3!='\0'); 597 c_bcp = *s3; 598 *s3 = '\0'; 599 width = UI_ProportionalStringWidth(s1) * sizeScale; 600 *s3 = c_bcp; 601 if (width > xmax) { 602 if (s1==s2) 603 { 604 // fuck, don't have a clean cut, we'll overflow 605 s2 = s3; 606 } 607 *s2 = '\0'; 608 UI_DrawProportionalString(x, y, s1, style, color); 609 y += ystep; 610 if (c_bcp == '\0') 611 { 612 // that was the last word 613 // we could start a new loop, but that wouldn't be much use 614 // even if the word is too long, we would overflow it (see above) 615 // so just print it now if needed 616 s2++; 617 if (*s2 != '\0') // if we are printing an overflowing line we have s2 == s3 618 UI_DrawProportionalString(x, y, s2, style, color); 619 break; 620 } 621 s2++; 622 s1 = s2; 623 s3 = s2; 624 } 625 else 626 { 627 s2 = s3; 628 if (c_bcp == '\0') // we reached the end 629 { 630 UI_DrawProportionalString(x, y, s1, style, color); 631 break; 632 } 633 } 634 } 635 } 636 637 /* 638 ================= 639 UI_DrawString2 640 ================= 641 */ 642 static void UI_DrawString2( int x, int y, const char* str, vec4_t color, int charw, int charh ) 643 { 644 const char* s; 645 char ch; 646 int forceColor = qfalse; //APSFIXME; 647 vec4_t tempcolor; 648 float ax; 649 float ay; 650 float aw; 651 float ah; 652 float frow; 653 float fcol; 654 655 if (y < -charh) 656 // offscreen 657 return; 658 659 // draw the colored text 660 trap_R_SetColor( color ); 661 662 ax = x * uis.scale + uis.bias; 663 ay = y * uis.scale; 664 aw = charw * uis.scale; 665 ah = charh * uis.scale; 666 667 s = str; 668 while ( *s ) 669 { 670 if ( Q_IsColorString( s ) ) 671 { 672 if ( !forceColor ) 673 { 674 memcpy( tempcolor, g_color_table[ColorIndex(s[1])], sizeof( tempcolor ) ); 675 tempcolor[3] = color[3]; 676 trap_R_SetColor( tempcolor ); 677 } 678 s += 2; 679 continue; 680 } 681 682 ch = *s & 255; 683 if (ch != ' ') 684 { 685 frow = (ch>>4)*0.0625; 686 fcol = (ch&15)*0.0625; 687 trap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol + 0.0625, frow + 0.0625, uis.charset ); 688 } 689 690 ax += aw; 691 s++; 692 } 693 694 trap_R_SetColor( NULL ); 695 } 696 697 /* 698 ================= 699 UI_DrawString 700 ================= 701 */ 702 void UI_DrawString( int x, int y, const char* str, int style, vec4_t color ) 703 { 704 int len; 705 int charw; 706 int charh; 707 vec4_t newcolor; 708 vec4_t lowlight; 709 float *drawcolor; 710 vec4_t dropcolor; 711 712 if( !str ) { 713 return; 714 } 715 716 if ((style & UI_BLINK) && ((uis.realtime/BLINK_DIVISOR) & 1)) 717 return; 718 719 if (style & UI_SMALLFONT) 720 { 721 charw = SMALLCHAR_WIDTH; 722 charh = SMALLCHAR_HEIGHT; 723 } 724 else if (style & UI_GIANTFONT) 725 { 726 charw = GIANTCHAR_WIDTH; 727 charh = GIANTCHAR_HEIGHT; 728 } 729 else 730 { 731 charw = BIGCHAR_WIDTH; 732 charh = BIGCHAR_HEIGHT; 733 } 734 735 if (style & UI_PULSE) 736 { 737 lowlight[0] = 0.8*color[0]; 738 lowlight[1] = 0.8*color[1]; 739 lowlight[2] = 0.8*color[2]; 740 lowlight[3] = 0.8*color[3]; 741 UI_LerpColor(color,lowlight,newcolor,0.5+0.5*sin(uis.realtime/PULSE_DIVISOR)); 742 drawcolor = newcolor; 743 } 744 else 745 drawcolor = color; 746 747 switch (style & UI_FORMATMASK) 748 { 749 case UI_CENTER: 750 // center justify at x 751 len = strlen(str); 752 x = x - len*charw/2; 753 break; 754 755 case UI_RIGHT: 756 // right justify at x 757 len = strlen(str); 758 x = x - len*charw; 759 break; 760 761 default: 762 // left justify at x 763 break; 764 } 765 766 if ( style & UI_DROPSHADOW ) 767 { 768 dropcolor[0] = dropcolor[1] = dropcolor[2] = 0; 769 dropcolor[3] = drawcolor[3]; 770 UI_DrawString2(x+2,y+2,str,dropcolor,charw,charh); 771 } 772 773 UI_DrawString2(x,y,str,drawcolor,charw,charh); 774 } 775 776 /* 777 ================= 778 UI_DrawChar 779 ================= 780 */ 781 void UI_DrawChar( int x, int y, int ch, int style, vec4_t color ) 782 { 783 char buff[2]; 784 785 buff[0] = ch; 786 buff[1] = '\0'; 787 788 UI_DrawString( x, y, buff, style, color ); 789 } 790 791 qboolean UI_IsFullscreen( void ) { 792 if ( uis.activemenu && ( trap_Key_GetCatcher() & KEYCATCH_UI ) ) { 793 return uis.activemenu->fullscreen; 794 } 795 796 return qfalse; 797 } 798 799 static void NeedCDAction( qboolean result ) { 800 if ( !result ) { 801 trap_Cmd_ExecuteText( EXEC_APPEND, "quit\n" ); 802 } 803 } 804 805 static void NeedCDKeyAction( qboolean result ) { 806 if ( !result ) { 807 trap_Cmd_ExecuteText( EXEC_APPEND, "quit\n" ); 808 } 809 } 810 811 void UI_SetActiveMenu( uiMenuCommand_t menu ) { 812 // this should be the ONLY way the menu system is brought up 813 // enusure minumum menu data is cached 814 Menu_Cache(); 815 816 switch ( menu ) { 817 case UIMENU_NONE: 818 UI_ForceMenuOff(); 819 return; 820 case UIMENU_MAIN: 821 UI_MainMenu(); 822 return; 823 case UIMENU_NEED_CD: 824 UI_ConfirmMenu( "Insert the CD", (voidfunc_f)NULL, NeedCDAction ); 825 return; 826 case UIMENU_BAD_CD_KEY: 827 UI_ConfirmMenu( "Bad CD Key", (voidfunc_f)NULL, NeedCDKeyAction ); 828 return; 829 case UIMENU_INGAME: 830 /* 831 //GRank 832 UI_RankingsMenu(); 833 return; 834 */ 835 trap_Cvar_Set( "cl_paused", "1" ); 836 UI_InGameMenu(); 837 return; 838 839 // bk001204 840 case UIMENU_TEAM: 841 case UIMENU_POSTGAME: 842 default: 843 #ifndef NDEBUG 844 Com_Printf("UI_SetActiveMenu: bad enum %d\n", menu ); 845 #endif 846 break; 847 } 848 } 849 850 /* 851 ================= 852 UI_KeyEvent 853 ================= 854 */ 855 void UI_KeyEvent( int key, int down ) { 856 sfxHandle_t s; 857 858 if (!uis.activemenu) { 859 return; 860 } 861 862 if (!down) { 863 return; 864 } 865 866 if (uis.activemenu->key) 867 s = uis.activemenu->key( key ); 868 else 869 s = Menu_DefaultKey( uis.activemenu, key ); 870 871 if ((s > 0) && (s != menu_null_sound)) 872 trap_S_StartLocalSound( s, CHAN_LOCAL_SOUND ); 873 } 874 875 /* 876 ================= 877 UI_MouseEvent 878 ================= 879 */ 880 void UI_MouseEvent( int dx, int dy ) 881 { 882 int i; 883 menucommon_s* m; 884 885 if (!uis.activemenu) 886 return; 887 888 // update mouse screen position 889 uis.cursorx += dx; 890 if (uis.cursorx < 0) 891 uis.cursorx = 0; 892 else if (uis.cursorx > SCREEN_WIDTH) 893 uis.cursorx = SCREEN_WIDTH; 894 895 uis.cursory += dy; 896 if (uis.cursory < 0) 897 uis.cursory = 0; 898 else if (uis.cursory > SCREEN_HEIGHT) 899 uis.cursory = SCREEN_HEIGHT; 900 901 // region test the active menu items 902 for (i=0; i<uis.activemenu->nitems; i++) 903 { 904 m = (menucommon_s*)uis.activemenu->items[i]; 905 906 if (m->flags & (QMF_GRAYED|QMF_INACTIVE)) 907 continue; 908 909 if ((uis.cursorx < m->left) || 910 (uis.cursorx > m->right) || 911 (uis.cursory < m->top) || 912 (uis.cursory > m->bottom)) 913 { 914 // cursor out of item bounds 915 continue; 916 } 917 918 // set focus to item at cursor 919 if (uis.activemenu->cursor != i) 920 { 921 Menu_SetCursor( uis.activemenu, i ); 922 ((menucommon_s*)(uis.activemenu->items[uis.activemenu->cursor_prev]))->flags &= ~QMF_HASMOUSEFOCUS; 923 924 if ( !(((menucommon_s*)(uis.activemenu->items[uis.activemenu->cursor]))->flags & QMF_SILENT ) ) { 925 trap_S_StartLocalSound( menu_move_sound, CHAN_LOCAL_SOUND ); 926 } 927 } 928 929 ((menucommon_s*)(uis.activemenu->items[uis.activemenu->cursor]))->flags |= QMF_HASMOUSEFOCUS; 930 return; 931 } 932 933 if (uis.activemenu->nitems > 0) { 934 // out of any region 935 ((menucommon_s*)(uis.activemenu->items[uis.activemenu->cursor]))->flags &= ~QMF_HASMOUSEFOCUS; 936 } 937 } 938 939 char *UI_Argv( int arg ) { 940 static char buffer[MAX_STRING_CHARS]; 941 942 trap_Argv( arg, buffer, sizeof( buffer ) ); 943 944 return buffer; 945 } 946 947 948 char *UI_Cvar_VariableString( const char *var_name ) { 949 static char buffer[MAX_STRING_CHARS]; 950 951 trap_Cvar_VariableStringBuffer( var_name, buffer, sizeof( buffer ) ); 952 953 return buffer; 954 } 955 956 957 /* 958 ================= 959 UI_Cache 960 ================= 961 */ 962 void UI_Cache_f( void ) { 963 MainMenu_Cache(); 964 InGame_Cache(); 965 ConfirmMenu_Cache(); 966 PlayerModel_Cache(); 967 PlayerSettings_Cache(); 968 Controls_Cache(); 969 Demos_Cache(); 970 UI_CinematicsMenu_Cache(); 971 Preferences_Cache(); 972 ServerInfo_Cache(); 973 SpecifyServer_Cache(); 974 ArenaServers_Cache(); 975 StartServer_Cache(); 976 ServerOptions_Cache(); 977 DriverInfo_Cache(); 978 GraphicsOptions_Cache(); 979 UI_DisplayOptionsMenu_Cache(); 980 UI_SoundOptionsMenu_Cache(); 981 UI_NetworkOptionsMenu_Cache(); 982 UI_SPLevelMenu_Cache(); 983 UI_SPSkillMenu_Cache(); 984 UI_SPPostgameMenu_Cache(); 985 TeamMain_Cache(); 986 UI_AddBots_Cache(); 987 UI_RemoveBots_Cache(); 988 UI_SetupMenu_Cache(); 989 // UI_LoadConfig_Cache(); 990 // UI_SaveConfigMenu_Cache(); 991 UI_BotSelectMenu_Cache(); 992 UI_CDKeyMenu_Cache(); 993 UI_ModsMenu_Cache(); 994 995 } 996 997 998 /* 999 ================= 1000 UI_ConsoleCommand 1001 ================= 1002 */ 1003 qboolean UI_ConsoleCommand( int realTime ) { 1004 char *cmd; 1005 1006 cmd = UI_Argv( 0 ); 1007 1008 // ensure minimum menu data is available 1009 Menu_Cache(); 1010 1011 if ( Q_stricmp (cmd, "levelselect") == 0 ) { 1012 UI_SPLevelMenu_f(); 1013 return qtrue; 1014 } 1015 1016 if ( Q_stricmp (cmd, "postgame") == 0 ) { 1017 UI_SPPostgameMenu_f(); 1018 return qtrue; 1019 } 1020 1021 if ( Q_stricmp (cmd, "ui_cache") == 0 ) { 1022 UI_Cache_f(); 1023 return qtrue; 1024 } 1025 1026 if ( Q_stricmp (cmd, "ui_cinematics") == 0 ) { 1027 UI_CinematicsMenu_f(); 1028 return qtrue; 1029 } 1030 1031 if ( Q_stricmp (cmd, "ui_teamOrders") == 0 ) { 1032 UI_TeamOrdersMenu_f(); 1033 return qtrue; 1034 } 1035 1036 if ( Q_stricmp (cmd, "iamacheater") == 0 ) { 1037 UI_SPUnlock_f(); 1038 return qtrue; 1039 } 1040 1041 if ( Q_stricmp (cmd, "iamamonkey") == 0 ) { 1042 UI_SPUnlockMedals_f(); 1043 return qtrue; 1044 } 1045 1046 if ( Q_stricmp (cmd, "ui_cdkey") == 0 ) { 1047 UI_CDKeyMenu_f(); 1048 return qtrue; 1049 } 1050 1051 return qfalse; 1052 } 1053 1054 /* 1055 ================= 1056 UI_Shutdown 1057 ================= 1058 */ 1059 void UI_Shutdown( void ) { 1060 } 1061 1062 /* 1063 ================= 1064 UI_Init 1065 ================= 1066 */ 1067 void UI_Init( void ) { 1068 UI_RegisterCvars(); 1069 1070 UI_InitGameinfo(); 1071 1072 // cache redundant calulations 1073 trap_GetGlconfig( &uis.glconfig ); 1074 1075 // for 640x480 virtualized screen 1076 uis.scale = uis.glconfig.vidHeight * (1.0/480.0); 1077 if ( uis.glconfig.vidWidth * 480 > uis.glconfig.vidHeight * 640 ) { 1078 // wide screen 1079 uis.bias = 0.5 * ( uis.glconfig.vidWidth - ( uis.glconfig.vidHeight * (640.0/480.0) ) ); 1080 } 1081 else { 1082 // no wide screen 1083 uis.bias = 0; 1084 } 1085 1086 // initialize the menu system 1087 Menu_Cache(); 1088 1089 uis.activemenu = NULL; 1090 uis.menusp = 0; 1091 } 1092 1093 /* 1094 ================ 1095 UI_AdjustFrom640 1096 1097 Adjusted for resolution and screen aspect ratio 1098 ================ 1099 */ 1100 void UI_AdjustFrom640( float *x, float *y, float *w, float *h ) { 1101 // expect valid pointers 1102 *x = *x * uis.scale + uis.bias; 1103 *y *= uis.scale; 1104 *w *= uis.scale; 1105 *h *= uis.scale; 1106 } 1107 1108 void UI_DrawNamedPic( float x, float y, float width, float height, const char *picname ) { 1109 qhandle_t hShader; 1110 1111 hShader = trap_R_RegisterShaderNoMip( picname ); 1112 UI_AdjustFrom640( &x, &y, &width, &height ); 1113 trap_R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader ); 1114 } 1115 1116 void UI_DrawHandlePic( float x, float y, float w, float h, qhandle_t hShader ) { 1117 float s0; 1118 float s1; 1119 float t0; 1120 float t1; 1121 1122 if( w < 0 ) { // flip about vertical 1123 w = -w; 1124 s0 = 1; 1125 s1 = 0; 1126 } 1127 else { 1128 s0 = 0; 1129 s1 = 1; 1130 } 1131 1132 if( h < 0 ) { // flip about horizontal 1133 h = -h; 1134 t0 = 1; 1135 t1 = 0; 1136 } 1137 else { 1138 t0 = 0; 1139 t1 = 1; 1140 } 1141 1142 UI_AdjustFrom640( &x, &y, &w, &h ); 1143 trap_R_DrawStretchPic( x, y, w, h, s0, t0, s1, t1, hShader ); 1144 } 1145 1146 /* 1147 ================ 1148 UI_FillRect 1149 1150 Coordinates are 640*480 virtual values 1151 ================= 1152 */ 1153 void UI_FillRect( float x, float y, float width, float height, const float *color ) { 1154 trap_R_SetColor( color ); 1155 1156 UI_AdjustFrom640( &x, &y, &width, &height ); 1157 trap_R_DrawStretchPic( x, y, width, height, 0, 0, 0, 0, uis.whiteShader ); 1158 1159 trap_R_SetColor( NULL ); 1160 } 1161 1162 /* 1163 ================ 1164 UI_DrawRect 1165 1166 Coordinates are 640*480 virtual values 1167 ================= 1168 */ 1169 void UI_DrawRect( float x, float y, float width, float height, const float *color ) { 1170 trap_R_SetColor( color ); 1171 1172 UI_AdjustFrom640( &x, &y, &width, &height ); 1173 1174 trap_R_DrawStretchPic( x, y, width, 1, 0, 0, 0, 0, uis.whiteShader ); 1175 trap_R_DrawStretchPic( x, y, 1, height, 0, 0, 0, 0, uis.whiteShader ); 1176 trap_R_DrawStretchPic( x, y + height - 1, width, 1, 0, 0, 0, 0, uis.whiteShader ); 1177 trap_R_DrawStretchPic( x + width - 1, y, 1, height, 0, 0, 0, 0, uis.whiteShader ); 1178 1179 trap_R_SetColor( NULL ); 1180 } 1181 1182 void UI_SetColor( const float *rgba ) { 1183 trap_R_SetColor( rgba ); 1184 } 1185 1186 void UI_UpdateScreen( void ) { 1187 trap_UpdateScreen(); 1188 } 1189 1190 /* 1191 ================= 1192 UI_Refresh 1193 ================= 1194 */ 1195 void UI_Refresh( int realtime ) 1196 { 1197 uis.frametime = realtime - uis.realtime; 1198 uis.realtime = realtime; 1199 1200 if ( !( trap_Key_GetCatcher() & KEYCATCH_UI ) ) { 1201 return; 1202 } 1203 1204 UI_UpdateCvars(); 1205 1206 if ( uis.activemenu ) 1207 { 1208 if (uis.activemenu->fullscreen) 1209 { 1210 // draw the background 1211 if( uis.activemenu->showlogo ) { 1212 UI_DrawHandlePic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, uis.menuBackShader ); 1213 } 1214 else { 1215 UI_DrawHandlePic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, uis.menuBackNoLogoShader ); 1216 } 1217 } 1218 1219 if (uis.activemenu->draw) 1220 uis.activemenu->draw(); 1221 else 1222 Menu_Draw( uis.activemenu ); 1223 1224 if( uis.firstdraw ) { 1225 UI_MouseEvent( 0, 0 ); 1226 uis.firstdraw = qfalse; 1227 } 1228 } 1229 1230 // draw cursor 1231 UI_SetColor( NULL ); 1232 UI_DrawHandlePic( uis.cursorx-16, uis.cursory-16, 32, 32, uis.cursor); 1233 1234 #ifndef NDEBUG 1235 if (uis.debug) 1236 { 1237 // cursor coordinates 1238 UI_DrawString( 0, 0, va("(%d,%d)",uis.cursorx,uis.cursory), UI_LEFT|UI_SMALLFONT, colorRed ); 1239 } 1240 #endif 1241 1242 // delay playing the enter sound until after the 1243 // menu has been drawn, to avoid delay while 1244 // caching images 1245 if (m_entersound) 1246 { 1247 trap_S_StartLocalSound( menu_in_sound, CHAN_LOCAL_SOUND ); 1248 m_entersound = qfalse; 1249 } 1250 } 1251 1252 void UI_DrawTextBox (int x, int y, int width, int lines) 1253 { 1254 UI_FillRect( x + BIGCHAR_WIDTH/2, y + BIGCHAR_HEIGHT/2, ( width + 1 ) * BIGCHAR_WIDTH, ( lines + 1 ) * BIGCHAR_HEIGHT, colorBlack ); 1255 UI_DrawRect( x + BIGCHAR_WIDTH/2, y + BIGCHAR_HEIGHT/2, ( width + 1 ) * BIGCHAR_WIDTH, ( lines + 1 ) * BIGCHAR_HEIGHT, colorWhite ); 1256 } 1257 1258 qboolean UI_CursorInRect (int x, int y, int width, int height) 1259 { 1260 if (uis.cursorx < x || 1261 uis.cursory < y || 1262 uis.cursorx > x+width || 1263 uis.cursory > y+height) 1264 return qfalse; 1265 1266 return qtrue; 1267 }