Home | History | Annotate | Download | only in WinQuake
      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