1 /* 2 Copyright (C) 2007 The Android Open Source Project 3 4 */ 5 6 #include "quakedef.h" 7 8 unsigned short d_8to16table[256]; 9 unsigned d_8to24table[256]; 10 11 #ifdef SUPPORT_8BIT_MIPMAPGENERATION 12 unsigned char d_15to8table[65536]; 13 #endif 14 15 cvar_t mouse_button_commands[3] = 16 { 17 CVAR2("mouse1","+attack"), 18 CVAR2("mouse2","+strafe"), 19 CVAR2("mouse3","+forward"), 20 }; 21 22 static const int MOUSE_LEFTBUTTON = 1; 23 static const int MOUSE_MIDDLEBUTTON = 2; 24 static const int MOUSE_RIGHTBUTTON = 4; 25 26 bool mouse_tap; 27 float mouse_x, mouse_y; 28 float old_mouse_x, old_mouse_y; 29 int mx, my; 30 bool mouse_buttonstate; 31 bool mouse_oldbuttonstate; 32 33 cvar_t m_filter = CVAR2("m_filter","1"); 34 35 int scr_width, scr_height; 36 37 cvar_t _windowed_mouse = CVAR3("_windowed_mouse","0", true); 38 39 /*-----------------------------------------------------------------------*/ 40 41 //int texture_mode = GL_NEAREST; 42 //int texture_mode = GL_NEAREST_MIPMAP_NEAREST; 43 //int texture_mode = GL_NEAREST_MIPMAP_LINEAR; 44 int texture_mode = GL_LINEAR; 45 // int texture_mode = GL_LINEAR_MIPMAP_NEAREST; 46 //int texture_mode = GL_LINEAR_MIPMAP_LINEAR; 47 48 int texture_extension_number = 1; 49 50 float gldepthmin, gldepthmax; 51 52 cvar_t gl_ztrick = CVAR2("gl_ztrick","0"); 53 54 const char *gl_vendor; 55 const char *gl_renderer; 56 const char *gl_version; 57 const char *gl_extensions; 58 59 qboolean is8bit = false; 60 qboolean isPermedia = false; 61 qboolean gl_mtexable = false; 62 63 /*-----------------------------------------------------------------------*/ 64 void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height) 65 { 66 } 67 68 void D_EndDirectRect (int x, int y, int width, int height) 69 { 70 } 71 72 void VID_Shutdown(void) 73 { 74 } 75 76 void VID_ShiftPalette(unsigned char *p) 77 { 78 // VID_SetPalette(p); 79 } 80 81 void VID_SetPalette (unsigned char *palette) 82 { 83 byte *pal; 84 unsigned r,g,b; 85 unsigned v; 86 int r1,g1,b1; 87 int k; 88 unsigned short i; 89 unsigned *table; 90 FILE *f; 91 char s[255]; 92 int dist, bestdist; 93 static qboolean palflag = false; 94 95 PMPBEGIN(("VID_SetPalette")); 96 // 97 // 8 8 8 encoding 98 // 99 Con_Printf("Converting 8to24\n"); 100 101 pal = palette; 102 table = d_8to24table; 103 for (i=0 ; i<256 ; i++) 104 { 105 r = pal[0]; 106 g = pal[1]; 107 b = pal[2]; 108 pal += 3; 109 110 // v = (255<<24) + (r<<16) + (g<<8) + (b<<0); 111 // v = (255<<0) + (r<<8) + (g<<16) + (b<<24); 112 v = (255<<24) + (r<<0) + (g<<8) + (b<<16); 113 *table++ = v; 114 } 115 d_8to24table[255] &= 0xffffff; // 255 is transparent 116 117 #ifdef SUPPORT_8BIT_MIPMAPGENERATION 118 119 // JACK: 3D distance calcs - k is last closest, l is the distance. 120 // FIXME: Precalculate this and cache to disk. 121 if (palflag) 122 return; 123 palflag = true; 124 125 COM_FOpenFile("glquake/15to8.pal", &f); 126 if (f) { 127 fread(d_15to8table, 1<<15, 1, f); 128 fclose(f); 129 } else { 130 PMPBEGIN(("Creating 15to8 palette")); 131 for (i=0; i < (1<<15); i++) { 132 /* Maps 133 0000.0000.0000.0000 134 0000.0000.0001.1111 = Red = 0x001F 135 0000.0011.1110.0000 = Green = 0x03E0 136 0111.1100.0000.0000 = Blue = 0x7C00 137 */ 138 r = ((i & 0x1F) << 3)+4; 139 g = ((i & 0x03E0) >> (5-3)) +4; 140 b = ((i & 0x7C00) >> (10-3))+4; 141 pal = (unsigned char *)d_8to24table; 142 for (v=0,k=0,bestdist=0x7FFFFFFF; v<256; v++,pal+=4) { 143 r1 = (int)r - (int)pal[0]; 144 g1 = (int)g - (int)pal[1]; 145 b1 = (int)b - (int)pal[2]; 146 dist = ((r1*r1)+(g1*g1)+(b1*b1)); 147 if (dist < bestdist) { 148 k=v; 149 bestdist = dist; 150 } 151 } 152 d_15to8table[i]=k; 153 } 154 PMPEND(("Creating 15to8 palette")); 155 sprintf(s, "%s/glquake", com_gamedir); 156 Sys_mkdir (s); 157 sprintf(s, "%s/glquake/15to8.pal", com_gamedir); 158 if ((f = fopen(s, "wb")) != NULL) { 159 fwrite(d_15to8table, 1<<15, 1, f); 160 fclose(f); 161 } 162 else 163 { 164 Con_Printf("Could not write %s\n", s); 165 } 166 } 167 168 #endif // SUPPORT_8BIT_MIPMAPGENERATION 169 PMPEND(("VID_SetPalette")); 170 } 171 172 /* 173 =============== 174 GL_Init 175 =============== 176 */ 177 void GL_Init (void) 178 { 179 gl_vendor = (char*) glGetString (GL_VENDOR); 180 Con_Printf ("GL_VENDOR: %s\n", gl_vendor); 181 GLCHECK("glGetString"); 182 gl_renderer = (char*) glGetString (GL_RENDERER); 183 Con_Printf ("GL_RENDERER: %s\n", gl_renderer); 184 GLCHECK("glGetString"); 185 186 gl_version = (char*) glGetString (GL_VERSION); 187 Con_Printf ("GL_VERSION: %s\n", gl_version); 188 GLCHECK("glGetString"); 189 gl_extensions = (char*) glGetString (GL_EXTENSIONS); 190 Con_Printf ("GL_EXTENSIONS: %s\n", gl_extensions); 191 GLCHECK("glGetString"); 192 193 // Con_Printf ("%s %s\n", gl_renderer, gl_version); 194 195 // Enable/disable multitexture: 196 197 gl_mtexable = true; 198 199 glClearColor (1,0,0,0); 200 glCullFace(GL_FRONT); 201 glEnable(GL_TEXTURE_2D); 202 203 glEnable(GL_ALPHA_TEST); 204 glAlphaFunc(GL_GREATER, 0.666); 205 206 #ifdef USE_OPENGLES 207 #else 208 glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); 209 #endif 210 glShadeModel(GL_FLAT); 211 glDisable(GL_DITHER); 212 213 // perspective correction don't work well currently 214 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); 215 216 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 217 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 218 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 219 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 220 221 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 222 223 // glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 224 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 225 226 #ifdef USE_OPENGLES 227 glEnableClientState(GL_VERTEX_ARRAY); 228 glEnableClientState(GL_TEXTURE_COORD_ARRAY); 229 #endif 230 } 231 232 /* 233 ================= 234 GL_BeginRendering 235 236 ================= 237 */ 238 void GL_BeginRendering (int *x, int *y, int *width, int *height) 239 { 240 extern cvar_t gl_clear; 241 242 *x = *y = 0; 243 *width = scr_width; 244 *height = scr_height; 245 246 // if (!wglMakeCurrent( maindc, baseRC )) 247 // Sys_Error ("wglMakeCurrent failed"); 248 249 // glViewport (*x, *y, *width, *height); 250 } 251 252 253 void GL_EndRendering (void) 254 { 255 //glFlush(); 256 // !!! Swap buffers. 257 } 258 259 void Init_KBD(void) 260 { 261 } 262 263 // This function controls whether or not 8-bit paletted textures are used: 264 265 qboolean VID_Is8bit(void) 266 { 267 return 0; 268 } 269 270 static void Check_Gamma (unsigned char *pal) 271 { 272 float vid_gamma; 273 float f, inf; 274 unsigned char palette[768]; 275 int i; 276 277 if ((i = COM_CheckParm("-gamma")) == 0) { 278 vid_gamma = 0.5; // brighten up game. 279 } else 280 vid_gamma = Q_atof(com_argv[i+1]); 281 282 if(vid_gamma != 1) 283 { 284 for (i=0 ; i<768 ; i++) 285 { 286 f = pow ( (pal[i]+1)/256.0 , vid_gamma ); 287 inf = f*255 + 0.5; 288 if (inf < 0) 289 inf = 0; 290 if (inf > 255) 291 inf = 255; 292 palette[i] = (unsigned char) inf; 293 } 294 } 295 296 memcpy (pal, palette, sizeof(palette)); 297 } 298 299 void VID_Init(unsigned char *palette) 300 { 301 int i; 302 GLint attribs[32]; 303 char gldir[MAX_OSPATH]; 304 int width = scr_width, height = scr_height; 305 306 S_Init(); 307 308 Init_KBD(); 309 310 Cvar_RegisterVariable (&gl_ztrick); 311 312 vid.maxwarpwidth = scr_width; 313 vid.maxwarpheight = height; 314 vid.colormap = host_colormap; 315 vid.fullbright = 0xffff; 316 vid.aspect = (float) scr_width / (float) scr_height; 317 vid.numpages = 2; 318 vid.rowbytes = 2 * scr_width; 319 vid.width = scr_width; 320 vid.height = scr_height; 321 322 vid.conwidth = scr_width; 323 vid.conheight = scr_height; 324 325 // interpret command-line params 326 327 // set vid parameters 328 329 GL_Init(); 330 331 sprintf (gldir, "%s/glquake", com_gamedir); 332 Sys_mkdir (gldir); 333 334 Check_Gamma(palette); 335 VID_SetPalette(palette); 336 337 Con_SafePrintf ("Video mode %dx%d initialized.\n", width, height); 338 339 vid.recalc_refdef = 1; // force a surface cache flush 340 } 341 342 // Android Key event codes. Some of these are 343 // only generated from the simulator. 344 // Not all Android devices can generate all codes. 345 346 byte scantokey[] = 347 { 348 '$', K_ESCAPE, '$', '$', K_ESCAPE, '$', '$', '0', // 0.. 7 349 '1', '2', '3', '4', '5', '6', '7', '8', // 8..15 350 '9', '$', '$', K_UPARROW, K_DOWNARROW, K_LEFTARROW, K_RIGHTARROW, K_ENTER, // 16..23 351 '$', '$', '$', '$', '$', 'a', 'b', 'c', // 24..31 352 353 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', // 32..39 354 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', // 40..47 355 't', 'u', 'v', 'w', 'x', 'y', 'z', ',', // 48..55 356 '.', K_CTRL, K_SHIFT, K_TAB, ' ', '$', '$', '$', // 56..63 357 '$', '$', K_ENTER, K_BACKSPACE, '`', '-', '=', '[', // 64..71 358 ']', '\\', ';', '\'', '/', '@', '#', '$', // 72..79 359 '$', '$', K_ESCAPE, '$' // 80..83 360 }; 361 362 byte scantokeyAlt[] = 363 { 364 0, 0, 0, 0, 0, 0, 0, 0, // 0.. 7 365 0, 0, 0, 0, 0, 0, 0, 0, // 8..15 366 0, 0, 0, 0, 0, 0, 0, 0, // 16..23 367 0, 0, 0, 0, 0, '%', '=', '8', // 24..31 368 369 '5', '2', '6', '-', '[', '$', ']', '"', // 32..39 370 '\'', '>', '<', '(', ')', '*', '3', '4', // 40..47 371 '+', '&', '9', '1', '7', '!', '#', ';', // 48..55 372 ':', 0, 0, 0, K_TAB, 0, 0, 0, // 56..63 373 0, 0, 0, 0, 0, 0, 0, 0, // 64..71 374 0, 0, '?', '0', 0, 0, 0, 0, // 72..79 375 0, 0, K_ESCAPE, 0 // 80..83 376 }; 377 378 #if 0 379 380 byte scantokeyCap[] = 381 { 382 0, 0, 0, 0, 0, 0, 0, 0, // 0.. 7 383 0, 0, 0, 0, 0, 0, 0, 0, // 8..15 384 0, 0, 0, 0, 0, 0, 0, 0, // 16..23 385 0, 0, 0, 0, 0, 'A', 'B', 'C', // 24..31 386 387 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', // 32..39 388 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', // 40..47 389 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0, // 48..55 390 0, 0, 0, 0, 0, 0, 0, 0, // 56..63 391 0, 0, 0, 0, 0, 0, 0, 0, // 64..71 392 0, 0, 0, 0, 0, 0, 0, 0, // 72..79 393 0, 0, K_ESCAPE, 0 // 80..83 394 }; 395 396 #endif 397 398 byte scantokeySym[] = 399 { 400 0, 0, 0, 0, 0, 0, 0, 0, // 0.. 7 401 0, 0, 0, 0, 0, 0, 0, 0, // 8..15 402 0, 0, 0, 0, 0, 0, 0, 0, // 16..23 403 0, 0, 0, 0, 0, 0, 0, K_F8, // 24..31 404 405 K_F5, K_F2, K_F6, '_', 0, 0, 0, 0, // 32..39 406 0, 0, 0, 0, 0, 0, K_F3, K_F4, // 40..47 407 K_F11, 0, K_F9, K_F1, K_F7, K_F12, K_PAUSE, 0, // 48..55 408 0, 0, 0, 0, 0, 0, 0, 0, // 56..63 409 0, 0, 0, 0, 0, 0, 0, 0, // 64..71 410 0, 0, '`', K_F10, 0, 0, 0, 0, // 72..79 411 0, 0, K_ESCAPE, 0 // 80..83 412 }; 413 414 #define ALT_KEY_VALUE 57 415 // #define CAPS_KEY_VALUE 58 416 #define SYM_KEY_VALUE 61 417 418 byte modifierKeyInEffect; 419 420 qboolean symKeyDown; 421 byte symKeyCode; 422 423 // Called from stand-alone main() function to process an event. 424 // Return non-zero if the event is handled. 425 426 int AndroidEvent(int type, int value) 427 { 428 if(value >= 0 && value < (int) sizeof(scantokey)) 429 { 430 byte key; 431 qboolean isPress = type != 0; 432 433 qboolean isModifier = value == ALT_KEY_VALUE || value == SYM_KEY_VALUE; 434 435 if(isModifier) 436 { 437 if(isPress) 438 { 439 if(modifierKeyInEffect == value) 440 { 441 // Press modifier twice to cancel modifier 442 modifierKeyInEffect = 0; 443 } 444 else 445 { 446 // Most recent modifier key wins 447 modifierKeyInEffect = value; 448 } 449 } 450 return 1; 451 } 452 else 453 { 454 switch(modifierKeyInEffect) 455 { 456 default: key = scantokey[value]; break; 457 case ALT_KEY_VALUE: key = scantokeyAlt[value]; break; 458 // case CAP_KEY_VALUE: key = scantokeyCap[value]; break; 459 case SYM_KEY_VALUE: key = scantokeySym[value]; break; 460 } 461 if(!key) 462 { 463 key = scantokey[value]; 464 } 465 466 // Hack: Remap @ and / to K_CTRL in game mode 467 if(key_dest == key_game && ! modifierKeyInEffect && (key == '@' || key == '/')) 468 { 469 key = K_CTRL; 470 } 471 472 if(!isPress) 473 { 474 modifierKeyInEffect = 0; 475 } 476 } 477 478 Key_Event(key, type); 479 // PMPLOG(("type: %d, value: %d -> %d '%c'\n", type, value, key, key)); 480 481 return 1; 482 } 483 else 484 { 485 PMPWARNING(("unexpected event type: %d, value: %d\n", type, value)); 486 } 487 return 0; 488 } 489 490 // Called from Java to process an event. 491 // Return non-zero if the event is handled. 492 493 int AndroidEvent2(int type, int value) 494 { 495 Key_Event(value, type); 496 return 0; 497 } 498 499 static const int MOTION_DOWN = 0; 500 static const int MOTION_UP = 1; 501 static const int MOTION_MOVE = 2; 502 static const int MOTION_CANCEL = 3; 503 504 class GestureDetector { 505 private: 506 bool mIsScroll; 507 bool mIsTap; 508 bool mIsDoubleTap; 509 510 float mScrollX; 511 float mScrollY; 512 513 static const unsigned long long TAP_TIME_MS = 200; 514 static const unsigned long long DOUBLE_TAP_TIME_MS = 400; 515 static const int TAP_REGION_MANHATTAN_DISTANCE = 10; 516 517 bool mAlwaysInTapRegion; 518 float mDownX; 519 float mDownY; 520 unsigned long long mDownTime; 521 unsigned long long mPreviousDownTime; 522 523 /** 524 * Position of the last motion event. 525 */ 526 float mLastMotionY; 527 float mLastMotionX; 528 529 public: 530 /** 531 * Analyze a motion event. Call this once for each motion event 532 * that is received by a view. 533 * @param ev the motion event to analyze. 534 */ 535 void analyze(unsigned long long eventTime, int action, 536 float x, float y, float pressure, float size, int deviceId) { 537 mIsScroll = false; 538 mIsTap = false; 539 mIsDoubleTap = false; 540 541 switch (action) { 542 case MOTION_DOWN: 543 printf("Down"); 544 // Remember where the motion event started 545 mLastMotionX = x; 546 mLastMotionY = y; 547 mDownX = x; 548 mDownY = y; 549 mPreviousDownTime = mDownTime; 550 mDownTime = eventTime; 551 mAlwaysInTapRegion = true; 552 break; 553 554 case MOTION_MOVE: 555 { 556 mIsScroll = true; 557 mScrollX = mLastMotionX - x; 558 mScrollY = mLastMotionY - y; 559 mLastMotionX = x; 560 mLastMotionY = y; 561 int manhattanTapDistance = (int) (absf(x - mDownX) + 562 absf(y - mDownY)); 563 if (manhattanTapDistance > TAP_REGION_MANHATTAN_DISTANCE) { 564 mAlwaysInTapRegion = false; 565 } 566 } 567 break; 568 569 case MOTION_UP: 570 { 571 unsigned long long doubleTapDelta = 572 eventTime - mPreviousDownTime; 573 unsigned long long singleTapDelta = 574 eventTime - mDownTime; 575 576 if (mAlwaysInTapRegion) { 577 if (doubleTapDelta < DOUBLE_TAP_TIME_MS) { 578 mIsDoubleTap = true; 579 } 580 else if (singleTapDelta < TAP_TIME_MS) { 581 mIsTap = true; 582 } 583 } 584 } 585 break; 586 } 587 } 588 589 /** 590 * @return true if the current motion event is a scroll 591 * event. 592 */ 593 bool isScroll() { 594 return mIsScroll; 595 } 596 597 /** 598 * This value is only defined if {@link #isScroll} is true. 599 * @return the X position of the current scroll event. 600 * event. 601 */ 602 float scrollX() { 603 return mScrollX; 604 } 605 606 /** 607 * This value is only defined if {@link #isScroll} is true. 608 * @return the Y position of the current scroll event. 609 * event. 610 */ 611 float scrollY() { 612 return mScrollY; 613 } 614 615 /** 616 * @return true if the current motion event is a single-tap 617 * event. 618 */ 619 bool isTap() { 620 return mIsTap; 621 } 622 623 /** 624 * This value is only defined if either {@link #isTap} or 625 * {@link #isDoubleTap} is true. 626 * @return the X position of the current tap event. 627 * event. 628 */ 629 float tapX() { 630 return mDownX; 631 } 632 633 /** 634 * This value is only defined if either {@link #isTap} or 635 * {@link #isDoubleTap} is true. 636 * @return the Y position of the current tap event. 637 * event. 638 */ 639 float tapY() { 640 return mDownY; 641 } 642 643 /** 644 * @return true if the current motion event is a double-tap 645 * event. 646 */ 647 bool isDoubleTap() { 648 return mIsDoubleTap; 649 } 650 651 private: 652 inline float absf(float a) { 653 return a >= 0.0f ? a : -a; 654 } 655 }; 656 657 GestureDetector gGestureDetector; 658 659 int AndroidMotionEvent(unsigned long long eventTime, int action, 660 float x, float y, float pressure, float size, int deviceId) 661 { 662 gGestureDetector.analyze(eventTime, action, x, y, pressure, size, deviceId); 663 664 if (gGestureDetector.isTap()) { 665 mouse_tap = true; 666 } 667 else if (gGestureDetector.isScroll()) { 668 mx += (int) gGestureDetector.scrollX(); 669 my += (int) gGestureDetector.scrollY(); 670 } 671 672 return true; 673 } 674 675 int AndroidTrackballEvent(unsigned long long eventTime, int action, 676 float x, float y) 677 { 678 switch (action ) { 679 case MOTION_DOWN: 680 mouse_buttonstate = true; 681 break; 682 case MOTION_UP: 683 mouse_buttonstate = false; 684 break; 685 case MOTION_MOVE: 686 mx += (int) (20.0f * x); 687 my += (int) (20.0f * y); 688 break; 689 } 690 691 return true; 692 } 693 694 void Sys_SendKeyEvents(void) 695 { 696 // Used to poll keyboards on systems that need to poll keyboards. 697 } 698 699 void Force_CenterView_f (void) 700 { 701 cl.viewangles[PITCH] = 0; 702 } 703 704 void IN_Init(void) 705 { 706 Cvar_RegisterVariable (&mouse_button_commands[0]); 707 Cvar_RegisterVariable (&mouse_button_commands[1]); 708 Cvar_RegisterVariable (&mouse_button_commands[2]); 709 Cmd_AddCommand ("force_centerview", Force_CenterView_f); 710 711 } 712 713 void IN_Shutdown(void) 714 { 715 } 716 717 /* 718 =========== 719 IN_Commands 720 =========== 721 */ 722 void IN_Commands (void) 723 { 724 // perform button actions 725 if (mouse_tap) { 726 Key_Event (K_MOUSE1, true); 727 Key_Event (K_MOUSE1, false); 728 mouse_tap = false; 729 } 730 if (mouse_buttonstate != mouse_oldbuttonstate) { 731 Key_Event (K_MOUSE1, mouse_buttonstate ? true : false); 732 mouse_oldbuttonstate = mouse_buttonstate; 733 } 734 } 735 736 /* 737 =========== 738 IN_Move 739 =========== 740 */ 741 void IN_MouseMove (usercmd_t *cmd) 742 { 743 #if 0 744 if (m_filter.value) 745 { 746 mouse_x = (mx + old_mouse_x) * 0.5; 747 mouse_y = (my + old_mouse_y) * 0.5; 748 } 749 else 750 #endif 751 { 752 mouse_x = mx; 753 mouse_y = my; 754 } 755 old_mouse_x = mx; 756 old_mouse_y = my; 757 mx = my = 0; // clear for next update 758 759 mouse_x *= 5.0f * sensitivity.value; 760 mouse_y *= 5.0f * sensitivity.value; 761 762 // add mouse X/Y movement to cmd 763 if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) )) 764 cmd->sidemove += m_side.value * mouse_x; 765 else 766 cl.viewangles[YAW] -= m_yaw.value * mouse_x; 767 768 if (in_mlook.state & 1) 769 V_StopPitchDrift (); 770 771 if ( (in_mlook.state & 1) && !(in_strafe.state & 1)) 772 { 773 cl.viewangles[PITCH] += m_pitch.value * mouse_y; 774 if (cl.viewangles[PITCH] > 80) 775 cl.viewangles[PITCH] = 80; 776 if (cl.viewangles[PITCH] < -70) 777 cl.viewangles[PITCH] = -70; 778 } 779 else 780 { 781 if ((in_strafe.state & 1) && noclip_anglehack) 782 cmd->upmove -= m_forward.value * mouse_y; 783 else 784 cmd->forwardmove -= m_forward.value * mouse_y; 785 } 786 } 787 788 void IN_Move (usercmd_t *cmd) 789 { 790 IN_MouseMove(cmd); 791 } 792 793 794