/* * Copyright(c) 1997-2001 Id Software, Inc. * Copyright(c) 2002 The Quakeforge Project. * Copyright(c) 2006 Quetoo. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or(at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "client.h" #include "keys.h" static SDL_Surface *surface; struct { int key; int down; int repeat; } keyq[64]; int keyq_head = 0; int keyq_tail = 0; int config_notify = 0; int config_notify_width; int config_notify_height; glwstate_t glw_state; // mouse vars static qboolean mouse_active; static int mouse_buttonstate; static int mouse_oldbuttonstate; static int mouse_x, mouse_y; static int old_mouse_x, old_mouse_y; static qboolean mlooking; static cvar_t *m_freelook; static cvar_t *m_sensitivity; static cvar_t *m_filter; static cvar_t *m_invert; static cvar_t *m_yaw; static cvar_t *m_pitch; static void MLookDown(void){ mlooking = true; } static void MLookUp(void){ mlooking = false; } void IN_Init(){ m_freelook = Cvar_Get("m_freelook", "1", CVAR_ARCHIVE); m_sensitivity = Cvar_Get("m_sensitivity", "3", CVAR_ARCHIVE); m_filter = Cvar_Get("m_filter", "0", CVAR_ARCHIVE); m_invert = Cvar_Get("m_invert", "0", CVAR_ARCHIVE); m_pitch = Cvar_Get("m_pitch", "0.022", 0); m_yaw = Cvar_Get("m_yaw", "0.022", 0); Cmd_AddCommand("+mlook", MLookDown); Cmd_AddCommand("-mlook", MLookUp); } /* IN_Shutdown */ void IN_Shutdown(void){ Cmd_RemoveCommand("+mlook"); Cmd_RemoveCommand("-mlook"); } /* IN_UpdateViewAngles */ void IN_UpdateViewAngles(int mx, int my){ if(m_filter->value){ mouse_x = (mx + old_mouse_x) * 0.5; mouse_y = (my + old_mouse_y) * 0.5; } else { mouse_x = mx; mouse_y = my; } old_mouse_x = mx; old_mouse_y = my; if(mouse_x || mouse_y){ mouse_x *= m_sensitivity->value; mouse_y *= m_sensitivity->value; if(m_invert->value) // invert mouse mouse_y = -mouse_y; // always add horizontal movement cl.viewangles[YAW] -= m_yaw->value * mouse_x; if((mlooking || m_freelook->value)) // and usually add vertical too cl.viewangles[PITCH] += m_pitch->value * mouse_y; mx = my = 0; } } /* KeyMap */ static int KeyMap(SDL_Event *event){ unsigned int keysym = event->key.keysym.sym; int key = 0; switch(keysym){ case SDLK_KP9: key = K_KP_PGUP; break; case SDLK_PAGEUP: key = K_PGUP; break; case SDLK_KP3: key = K_KP_PGDN; break; case SDLK_PAGEDOWN: key = K_PGDN; break; case SDLK_KP7: key = K_KP_HOME; break; case SDLK_HOME: key = K_HOME; break; case SDLK_KP1: key = K_KP_END; break; case SDLK_END: key = K_END; break; case SDLK_KP4: key = K_KP_LEFTARROW; break; case SDLK_LEFT: key = K_LEFTARROW; break; case SDLK_KP6: key = K_KP_RIGHTARROW; break; case SDLK_RIGHT: key = K_RIGHTARROW; break; case SDLK_KP2: key = K_KP_DOWNARROW; break; case SDLK_DOWN: key = K_DOWNARROW; break; case SDLK_KP8: key = K_KP_UPARROW; break; case SDLK_UP: key = K_UPARROW; break; case SDLK_ESCAPE: key = K_ESCAPE; break; case SDLK_KP_ENTER: key = K_KP_ENTER; break; case SDLK_RETURN: key = K_ENTER; break; case SDLK_TAB: key = K_TAB; break; case SDLK_F1: key = K_F1; break; case SDLK_F2: key = K_F2; break; case SDLK_F3: key = K_F3; break; case SDLK_F4: key = K_F4; break; case SDLK_F5: key = K_F5; break; case SDLK_F6: key = K_F6; break; case SDLK_F7: key = K_F7; break; case SDLK_F8: key = K_F8; break; case SDLK_F9: key = K_F9; break; case SDLK_F10: key = K_F10; break; case SDLK_F11: if(event->type == SDL_KEYDOWN){ if(vid_fullscreen->value){ // toggle fullscreen Cvar_SetValue("vid_fullscreen", 0); Cvar_SetValue("vid_width", vid_width->value / 2); Cvar_SetValue("vid_height", vid_height->value / 2); } else { Cvar_SetValue("vid_fullscreen", 1); Cvar_SetValue("vid_width", vid_width->value * 2); Cvar_SetValue("vid_height", vid_height->value * 2); } } VID_Restart_f(); break; case SDLK_F12: key = K_F12; break; case SDLK_BACKSPACE: key = K_BACKSPACE; break; case SDLK_KP_PERIOD: key = K_KP_DEL; break; case SDLK_DELETE: key = K_DEL; break; case SDLK_PAUSE: key = K_PAUSE; break; case SDLK_LSHIFT: case SDLK_RSHIFT: key = K_SHIFT; break; case SDLK_LCTRL: case SDLK_RCTRL: key = K_CTRL; break; case SDLK_LMETA: case SDLK_RMETA: case SDLK_LALT: case SDLK_RALT: key = K_ALT; break; case SDLK_KP5: key = K_KP_5; break; case SDLK_INSERT: key = K_INS; break; case SDLK_KP0: key = K_KP_INS; break; case SDLK_KP_MULTIPLY: key = '*'; break; case SDLK_KP_PLUS: key = K_KP_PLUS; break; case SDLK_KP_MINUS: key = K_KP_MINUS; break; case SDLK_KP_DIVIDE: key = K_KP_SLASH; break; case SDLK_WORLD_7: key = '`'; break; default: if(keysym < 128) key = keysym; break; } return key; } /* HandleEvents */ static void HandleEvents(SDL_Event *event){ unsigned int key; switch(event->type){ case SDL_MOUSEBUTTONDOWN: if(event->button.button == 4){ keyq[keyq_head].key = K_MWHEELUP; keyq[keyq_head].down = true; keyq_head = (keyq_head + 1) & 63; keyq[keyq_head].key = K_MWHEELUP; keyq[keyq_head].down = false; keyq_head = (keyq_head + 1) & 63; } else if(event->button.button == 5){ keyq[keyq_head].key = K_MWHEELDOWN; keyq[keyq_head].down = true; keyq_head = (keyq_head + 1) & 63; keyq[keyq_head].key = K_MWHEELDOWN; keyq[keyq_head].down = false; keyq_head = (keyq_head + 1) & 63; } break; case SDL_KEYDOWN: key = KeyMap(event); if(key){ keyq[keyq_head].key = key; keyq[keyq_head].down = true; keyq_head = (keyq_head + 1) & 63; } break; case SDL_KEYUP: key = KeyMap(event); if(key){ keyq[keyq_head].key = key; keyq[keyq_head].down = false; keyq_head = (keyq_head + 1) & 63; } break; case SDL_QUIT: Cmd_ExecuteString("quit"); break; } } /* IN_HandleEvents */ void IN_HandleEvents(void){ extern unsigned in_frametime; int i, bstate, xoffset, yoffset; SDL_Event event; if(!surface) return; // handle key events while(SDL_PollEvent(&event)) HandleEvents(&event); if(!cl.view_prepped || cls.key_dest == key_console){ if(mouse_active){ // yield cursor to os SDL_WM_GrabInput(SDL_GRAB_OFF); mouse_active = false; } } else { if(!mouse_active){ // or take it back SDL_WM_GrabInput(SDL_GRAB_ON); mouse_active = true; } } in_frametime = Sys_Milliseconds(); if(mouse_active){ // check for movement bstate = SDL_GetMouseState(&xoffset, &yoffset); xoffset -= viddef.width / 2; //normalize to center yoffset -= viddef.height / 2; if(xoffset != 0 || yoffset != 0){ // mouse has moved IN_UpdateViewAngles(xoffset, yoffset); SDL_WarpMouse(viddef.width / 2, viddef.height / 2); } mouse_buttonstate = 0; // and check for buttons if(SDL_BUTTON(1) & bstate) mouse_buttonstate |= (1 << 0); if(SDL_BUTTON(3) & bstate) // right button is mouse2 mouse_buttonstate |= (1 << 1); if(SDL_BUTTON(2) & bstate) // middle button is mouse3 mouse_buttonstate |= (1 << 2); if(SDL_BUTTON(4) & bstate) mouse_buttonstate |= (1 << 3); if(SDL_BUTTON(5) & bstate) mouse_buttonstate |= (1 << 4); for(i = 0; i < 5; i++){ if((mouse_buttonstate & (1 << i)) && !(mouse_oldbuttonstate & (1 << i))) Key_Event(K_MOUSE1 + i, true, in_frametime); if(!(mouse_buttonstate & (1 << i)) && (mouse_oldbuttonstate & (1 << i))) Key_Event(K_MOUSE1 + i, false, in_frametime); } mouse_oldbuttonstate = mouse_buttonstate; } while(keyq_head != keyq_tail){ // then check for keys Key_Event(keyq[keyq_tail].key, keyq[keyq_tail].down, in_frametime); keyq_tail = (keyq_tail + 1) & 63; } } /* GL_SetIcon */ static void GL_SetIcon(void){ #include "icon.xbm" SDL_Surface *icon; SDL_Color color; Uint8 *ptr; int i, mask; icon = SDL_CreateRGBSurface( SDL_SWSURFACE, icon_width, icon_height, 8, 0, 0, 0, 0 ); if(icon == NULL) return; SDL_SetColorKey(icon, SDL_SRCCOLORKEY, 0); color.r = color.g = color.b = 255; SDL_SetColors(icon, &color, 0, 1); color.r = 0; color.g = 16; color.b = 0; SDL_SetColors(icon, &color, 1, 1); ptr = (Uint8 *)icon->pixels; for(i = 0; i < sizeof(icon_bits); i++){ for(mask = 1; mask != 0x100; mask <<= 1){ *ptr = (icon_bits[i] & mask) ? 1 : 0; ptr++; } } SDL_WM_SetIcon(icon, NULL); SDL_FreeSurface(icon); } /* GL_InitGraphics */ qboolean GL_InitGraphics(int width, int height, qboolean fullscreen){ int flags; if(SDL_WasInit(SDL_INIT_AUDIO | SDL_INIT_VIDEO) == 0){ if(SDL_Init(SDL_INIT_VIDEO) < 0){ Com_Error(ERR_DROP, "GL_InitGraphics: %s\n", SDL_GetError()); } } else if(SDL_WasInit(SDL_INIT_VIDEO) == 0){ if(SDL_InitSubSystem(SDL_INIT_VIDEO) < 0){ Com_Error(ERR_DROP, "GL_InitGraphics: %s\n", SDL_GetError()); } } if(surface && (surface->w == width) && (surface->h == height)){ //toggle fs int isfullscreen = (surface->flags & SDL_FULLSCREEN) ? 1 : 0; if(fullscreen != isfullscreen) SDL_WM_ToggleFullScreen(surface); isfullscreen = (surface->flags & SDL_FULLSCREEN) ? 1 : 0; if(fullscreen == isfullscreen) return true; } // free resources in use if(surface) SDL_FreeSurface(surface); // let the sound and input subsystems know about the new window viddef.width = width; viddef.height = height; SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); flags = SDL_OPENGL; if(fullscreen) flags |= SDL_FULLSCREEN; if((surface = SDL_SetVideoMode(width, height, 0, flags)) == NULL){ Com_Error(ERR_DROP, "GL_InitGraphics: %s\n", SDL_GetError()); return false; } SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); SDL_WM_SetCaption("Quetoo", "Quetoo"); SDL_ShowCursor(0); GL_SetIcon(); return true; } /* GL_EndFrame */ void GL_EndFrame(void){ float g; if(vid_gamma->modified){ vid_gamma->modified = false; g = vid_gamma->value; if(g < 0.1) g = 0.1; if(g > 3.0) g = 3.0; SDL_SetGamma(g, g, g); } SDL_GL_SwapBuffers(); } /* GL_ShutdownGraphics */ void GL_ShutdownGraphics(void){ if(surface) SDL_FreeSurface(surface); surface = NULL; if(SDL_WasInit(SDL_INIT_EVERYTHING) == SDL_INIT_VIDEO) SDL_Quit(); else SDL_QuitSubSystem(SDL_INIT_VIDEO); }