diff --git a/src/engine.cc b/src/engine.cc index 2608758..8e270aa 100644 --- a/src/engine.cc +++ b/src/engine.cc @@ -49,9 +49,9 @@ namespace openrayman // Provide more complete info for the user. std::stringstream title; title << "OpenRayman " << openrayman::version << " " - << (this_platform == platform::windows ? "Win32" : "Linux") - << " (OpenGL " << gl_major << "." << gl_minor << ")" - << " (Game \"" << load_game << "\")"; + << (this_platform == platform::windows ? "Win32" : "Linux") + << " (OpenGL " << gl_major << "." << gl_minor << ")" + << " (Game \"" << load_game << "\")"; m_window.set_title(title.str()); std::vector icon_data; diff --git a/src/input/standalone_input_provider.cc b/src/input/standalone_input_provider.cc index 087dc48..88bea26 100644 --- a/src/input/standalone_input_provider.cc +++ b/src/input/standalone_input_provider.cc @@ -22,6 +22,7 @@ namespace openrayman { m_input.stick_x = m_input.stick_y = m_input.buttons = m_input.commands = 0; poll_keyboard(); + poll_game_controller(); return m_input; } @@ -32,8 +33,6 @@ namespace openrayman // Keyboard // This is not 100% accurate to the original PC version because // the N64 version is not the same as the PC version - // TODO: rebindable keyboard controls - // and controller... // Control stick // This simulates a slower walk done by the control stick @@ -41,14 +40,23 @@ namespace openrayman // TODO: Is half (64) accurate?!?! int walk_strength = keyboard_state[SDL_SCANCODE_LSHIFT] ? 64 : 127; + int new_stick_x = m_input.stick_x; + int new_stick_y = m_input.stick_y; + if(keyboard_state[SDL_SCANCODE_LEFT]) - m_input.stick_x -= walk_strength; + new_stick_x -= walk_strength; if(keyboard_state[SDL_SCANCODE_RIGHT]) - m_input.stick_x += walk_strength; + new_stick_x += walk_strength; if(keyboard_state[SDL_SCANCODE_UP]) - m_input.stick_y -= walk_strength; + new_stick_y -= walk_strength; if(keyboard_state[SDL_SCANCODE_DOWN]) - m_input.stick_y += walk_strength; + new_stick_y += walk_strength; + + new_stick_x = std::min(127, std::max(-127, new_stick_x)); + new_stick_y = std::min(127, std::max(-127, new_stick_y)); + + m_input.stick_x = new_stick_x; + m_input.stick_y = new_stick_y; // Front buttons if(keyboard_state[SDL_SCANCODE_SPACE]) @@ -82,4 +90,63 @@ namespace openrayman if(keyboard_state[SDL_SCANCODE_F11]) m_input.commands |= input_command::toggle_fullscreen; } + + void standalone_input_provider::poll_game_controller() + { + // Game controller + // Again, not 100% accurate to the original PC version because + // the N64 version is not the same as the PC version and the original game + // was not meant to be played with Xbox controllers and frankly, the original + // layout is shit and doesn't work most of the time (dinput) + + for(const std::pair& pair : m_game_controllers) + { + SDL_GameController* controller = pair.second; + + // Control stick + std::int16_t stick_x = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX) / 258; + std::int16_t stick_y = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY) / 258; + + int new_stick_x = m_input.stick_x; + int new_stick_y = m_input.stick_y; + + new_stick_x += stick_x; + new_stick_y += stick_y; + + new_stick_x = std::min(127, std::max(-127, new_stick_x)); + new_stick_y = std::min(127, std::max(-127, new_stick_y)); + + m_input.stick_x = new_stick_x; + m_input.stick_y = new_stick_y; + + // Front buttons + if(SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_A)) + m_input.buttons |= input_button::a; + if(SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_X)) + m_input.buttons |= input_button::b; + + // Triggers + if(SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT) > 20000 || + SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_LEFTSHOULDER)) + m_input.buttons |= input_button::z; + if(SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_Y)) + m_input.buttons |= input_button::l; + if(SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_B)) + m_input.buttons |= input_button::r; + + // Start button + if(SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_START)) + m_input.buttons |= input_button::start; + + // C buttons + if(SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_LEFT)) + m_input.commands |= input_button::cbtn_left; + if(SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_RIGHT)) + m_input.commands |= input_button::cbtn_right; + if(SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_UP)) + m_input.commands |= input_button::cbtn_up; + if(SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_DOWN)) + m_input.commands |= input_button::cbtn_down; + } + } } diff --git a/src/input/standalone_input_provider.h b/src/input/standalone_input_provider.h index 1dc6e9b..f95b4a1 100644 --- a/src/input/standalone_input_provider.h +++ b/src/input/standalone_input_provider.h @@ -5,6 +5,7 @@ #include #include #include +#include namespace openrayman { @@ -12,6 +13,7 @@ namespace openrayman // Sources are GLFW and libgcadapter. class standalone_input_provider : public input_provider { + friend class sdl_window; public: standalone_input_provider(SDL_Window* window); ~standalone_input_provider(); @@ -20,8 +22,10 @@ public: const input_state& poll() override; private: void poll_keyboard(); + void poll_game_controller(); input_state m_input; SDL_Window* m_window; + std::unordered_map m_game_controllers; }; } diff --git a/src/window/sdl_window.cc b/src/window/sdl_window.cc index a76bc86..1117384 100644 --- a/src/window/sdl_window.cc +++ b/src/window/sdl_window.cc @@ -105,6 +105,26 @@ namespace openrayman case SDL_QUIT: m_wants_close = true; break; + + case SDL_CONTROLLERDEVICEADDED: + { + SDL_GameController* ctrl = SDL_GameControllerOpen(event.cdevice.which); + if(ctrl) + { + SDL_Joystick* joy = SDL_GameControllerGetJoystick(ctrl); + int id = SDL_JoystickInstanceID(joy); + m_input_provider.m_game_controllers[id] = ctrl; + } + break; + } + + case SDL_CONTROLLERDEVICEREMOVED: + if(m_input_provider.m_game_controllers.count(event.cdevice.which) > 0) + { + SDL_GameControllerClose(m_input_provider.m_game_controllers[event.cdevice.which]); + m_input_provider.m_game_controllers.erase(event.cdevice.which); + } + break; } } }