// // Lol Engine // // Copyright: (c) 2010-2013 Sam Hocevar // This program is free software; you can redistribute it and/or // modify it under the terms of the Do What The Fuck You Want To // Public License, Version 2, as published by Sam Hocevar. See // http://www.wtfpl.net/ for more details. // #if defined HAVE_CONFIG_H # include "config.h" #endif #include #if defined USE_SDL # if defined HAVE_SDL_SDL_H # include # else # include # endif #endif #include "core.h" namespace lol { /* * Input implementation class */ InputTracker* Input::m_input_tracker = nullptr; static class InputData { friend class Input; public: InputData() : mouse(-1), buttons(0), nentities(0), lastfocus(0) { } private: ivec2 mouse; uint32_t buttons; static int const MAX_ENTITIES = 100; WorldEntity *entities[MAX_ENTITIES]; int nentities; WorldEntity *lastfocus; Array m_sticks; } inputdata; static InputData * const data = &inputdata; /* * ButtonSetting class */ int ButtonSetting::GetActionSettingIdx(Action a) { for (int i = 0; i < m_associated_action_list.Count(); i++) if (ACTION_CMP(m_associated_action_list[i].m_action, a)) return i; return -1; } /* * InputTracker class */ InputTracker::InputTracker() { m_gamegroup = GAMEGROUP_BEFORE; for (int i = 0; i < Key::Last * 2; ++i) m_input_status << 0; Ticker::Ref(this); } //Internal int InputTracker::GetButtonSettingIdx(Key k) { for (int i = 0; i < m_input_assocation_list.Count(); i++) if (m_input_assocation_list[i].m_raw_button == k) return i; return -1; } //----- int InputTracker::GetCurrentButtonStatus(Key k) { if (k < m_input_status.Count()) return m_input_status[k]; return 0; } //----- int InputTracker::GetPreviousButtonStatus(Key k) { if (k < m_input_status.Count()) return m_input_status[(int)k + (int)Key::Last]; return 0; } //Internal : Updates the action status & timers void InputTracker::UpdateActionStatus(float seconds) { #if defined USE_SDL # if SDL_VERSION_ATLEAST(1,3,0) Uint8 *keystate = SDL_GetKeyboardState(nullptr); # else Uint8 *keystate = SDL_GetKeyState(nullptr); # endif //SOOOoooo ugly. for (int i = 0; i < Key::Last; ++i) { m_input_status[i + Key::Last] = m_input_status[i]; m_input_status[i] = keystate[i]; } #endif for (int i = 0; i < m_input_assocation_list.Count(); i++) { ButtonSetting &CurIT = m_input_assocation_list[i]; for (int j = 0; j < CurIT.m_associated_action_list.Count(); j++) { ActionSetting &CurAS = CurIT.m_associated_action_list[j]; if (CurAS.m_buffered_since <= CurAS.m_buffering_time) CurAS.m_buffered_since += seconds; if (GetCurrentButtonStatus(CurIT.m_raw_button) && CurAS.m_buffering_time >= .0f) CurAS.m_buffered_since = .0f; } } } //Helps link a software input Action-Id to an hardware input Button-Id. void InputTracker::LinkActionToKey(Action a, Key k) { int ITIdx = GetButtonSettingIdx(k); if (ITIdx == -1) { ITIdx = m_input_assocation_list.Count(); m_input_assocation_list << ButtonSetting(k); } ButtonSetting &CurIT = m_input_assocation_list[ITIdx]; int ASIdx = CurIT.GetActionSettingIdx(a); if (ASIdx == -1) { ASIdx = CurIT.m_associated_action_list.Count(); CurIT.m_associated_action_list << ActionSetting(a); } } //Helps unlink a software input Action-Id to an hardware input k-Id. void InputTracker::UnlinkAction(Action a) { for (int i = 0; i < m_input_assocation_list.Count(); i++) { ButtonSetting &CurIT = m_input_assocation_list[i]; int ASIdx = CurIT.GetActionSettingIdx(a); if (ASIdx != -1) CurIT.m_associated_action_list.Remove(ASIdx); } } //Returns the current status of a given action int InputTracker::GetStatus(Action a) { for (int i = 0; i < m_input_assocation_list.Count(); i++) { ButtonSetting &CurIT = m_input_assocation_list[i]; int ASIdx = CurIT.GetActionSettingIdx(a); if (ASIdx != -1) { ActionSetting &CurAS = CurIT.m_associated_action_list[ASIdx]; if (CurAS.m_buffering_time >= .0f && CurAS.m_buffered_since <= CurAS.m_buffering_time) return 1; return 0; } } return 0; } //Returns TRUE if action status went from Active to Inactive this frame bool InputTracker::WasReleased(Action a) { for (int i = 0; i < m_input_assocation_list.Count(); i++) { ButtonSetting &CurIT = m_input_assocation_list[i]; int ASIdx = CurIT.GetActionSettingIdx(a); if (ASIdx != -1) { if (GetPreviousButtonStatus(CurIT.m_raw_button) && !GetCurrentButtonStatus(CurIT.m_raw_button)) return true; return false; } } return false; } //Returns TRUE if action status went from Inactive to Active this frame bool InputTracker::WasPressed(Action a) { for (int i = 0; i < m_input_assocation_list.Count(); i++) { ButtonSetting &CurIT = m_input_assocation_list[i]; int ASIdx = CurIT.GetActionSettingIdx(a); if (ASIdx != -1) { if (!GetPreviousButtonStatus(CurIT.m_raw_button) && GetCurrentButtonStatus(CurIT.m_raw_button)) return true; return false; } } return false; } //Returns the current status of a given action int InputTracker::GetStatus(Key k) { return GetCurrentButtonStatus(k); } //Returns TRUE if action status went from Active to Inactive this frame bool InputTracker::WasReleased(Key k) { if (GetPreviousButtonStatus(k) && !GetCurrentButtonStatus(k)) return true; return false; } //Returns TRUE if action status went from Inactive to Active this frame bool InputTracker::WasPressed(Key k) { if (!GetPreviousButtonStatus(k) && GetCurrentButtonStatus(k)) return true; return false; } /* * Public Input class */ #if 0 vec2 Input::GetAxis(int axis) { vec2 ret; #if defined USE_SDL /* Simulate a joystick using the keyboard. This SDL call is free. */ # if SDL_VERSION_ATLEAST(1,3,0) Uint8 *keystate = SDL_GetKeyboardState(nullptr); # else Uint8 *keystate = SDL_GetKeyState(nullptr); # endif int left = keystate[SDLK_d] - (keystate[SDLK_a] | keystate[SDLK_q]); int up = (keystate[SDLK_w] | keystate[SDLK_z]) - keystate[SDLK_s] ; ret.x += left; ret.y += up; if (left && up) ret = ret * sqrtf(0.5f); #else ret = vec2(0, 0); #endif return ret; } #endif ivec2 Input::GetMousePos() { return data->mouse; } uint32_t Input::GetMouseButtons() { return data->buttons; } //BH : Added this, is a v0.1 Alpha version. int Input::GetButtonState(int button) { #if defined USE_SDL # if SDL_VERSION_ATLEAST(1,3,0) Uint8 *keystate = SDL_GetKeyboardState(nullptr); # else Uint8 *keystate = SDL_GetKeyState(nullptr); # endif return keystate[button]; #else return 0; #endif } //Helps link a software input Action-Id to an hardware input Button-Id. void Input::LinkActionToKey(Action a, Key k) { if (CheckInputTrackerInit()) Input::m_input_tracker->LinkActionToKey(a, k); } //Helps unlink a software input Action-Id to an hardware input Button-Id. void Input::UnlinkAction(Action a) { if (CheckInputTrackerInit()) Input::m_input_tracker->UnlinkAction(a); } //Returns the current status of a given action int Input::GetStatus(Action a) { if (CheckInputTrackerInit()) return Input::m_input_tracker->GetStatus(a); return 0; } //Returns TRUE if action status when from Active to Inactive this frame bool Input::WasPressed(Action a) { if (CheckInputTrackerInit()) return Input::m_input_tracker->WasPressed(a); return false; } //Returns TRUE if action status when from Active to Inactive this frame bool Input::WasReleased(Action a) { if (CheckInputTrackerInit()) return Input::m_input_tracker->WasReleased(a); return false; } //Returns the current status of a given action int Input::GetStatus(Key k) { if (CheckInputTrackerInit()) return Input::m_input_tracker->GetStatus(k); return 0; } //Returns TRUE if action status when from Active to Inactive this frame bool Input::WasPressed(Key k) { if (CheckInputTrackerInit()) return Input::m_input_tracker->WasPressed(k); return false; } //Returns TRUE if action status when from Active to Inactive this frame bool Input::WasReleased(Key k) { if (CheckInputTrackerInit()) return Input::m_input_tracker->WasReleased(k); return false; } //-- void Input::TrackMouse(WorldEntity *e) { if (data->nentities >= InputData::MAX_ENTITIES) return; data->entities[data->nentities] = e; data->nentities++; } void Input::UntrackMouse(WorldEntity *e) { for (int n = 0; n < data->nentities; n++) { if (data->entities[n] != e) continue; data->entities[n] = data->entities[data->nentities - 1]; data->nentities--; n--; } } void Input::SetMousePos(ivec2 coord) { data->mouse = coord; WorldEntity *top = nullptr; /* Find the top “widget” amongst all entities that match the * mouse coordinates */ for (int n = 0; n < data->nentities; n++) { if (coord.x < data->entities[n]->m_bbox[0].x || coord.x >= data->entities[n]->m_bbox[1].x || coord.y < data->entities[n]->m_bbox[0].y || coord.y >= data->entities[n]->m_bbox[1].y) continue; if (!top || top->m_bbox[1].z < data->entities[n]->m_bbox[1].z) top = data->entities[n]; } for (int n = 0; n < data->nentities; n++) { if (data->entities[n] == top) { data->entities[n]->m_mousepos = coord - (ivec2)top->m_bbox[0].xy; if (top != data->lastfocus) data->entities[n]->m_pressed = data->buttons; else data->entities[n]->m_clicked = 0; } else { data->entities[n]->m_mousepos = ivec2(-1); /* FIXME */ data->entities[n]->m_released = 0; data->entities[n]->m_pressed = 0; data->entities[n]->m_clicked = 0; } } data->lastfocus = top; } void Input::SetMouseButton(int index) { uint32_t flag = 1 << index; data->buttons |= flag; if (data->lastfocus) { if (!(data->lastfocus->m_pressed & flag)) data->lastfocus->m_clicked |= flag; data->lastfocus->m_pressed |= flag; data->lastfocus->m_released &= ~flag; } } void Input::UnsetMouseButton(int index) { uint32_t flag = 1 << index; data->buttons &= ~flag; if (data->lastfocus) { if (!(data->lastfocus->m_pressed & flag)) data->lastfocus->m_released |= flag; data->lastfocus->m_pressed &= ~flag; data->lastfocus->m_clicked &= ~flag; } } Stick *Input::CreateStick() { Stick *stick = new Stick(); Ticker::Ref(stick); data->m_sticks.Push(stick); return stick; } void Input::DestroyStick(Stick *stick) { for (int i = 0; i < data->m_sticks.Count(); i++) if (data->m_sticks[i] == stick) data->m_sticks.Remove(i); Ticker::Unref(stick); } Stick *Input::TrackStick(int desired) { /* FIXME: add the possibility to choose amongst sticks */ if (desired >= data->m_sticks.Count()) return nullptr; Ticker::Ref(data->m_sticks[desired]); return data->m_sticks[desired]; } void Input::UntrackStick(Stick *stick) { Ticker::Unref(stick); } } /* namespace lol */