diff --git a/src/game/states/forage.cpp b/src/game/states/forage.cpp index 95c6a8c..5a791ad 100644 --- a/src/game/states/forage.cpp +++ b/src/game/states/forage.cpp @@ -246,7 +246,10 @@ void setup_controls(game::context* ctx) const float dolly_speed = 20.0f; const float truck_speed = dolly_speed; const float pedestal_speed = 30.0f; - const float pan_speed = math::radians(8.0f); + const float pan_speed_mouse = math::radians(8.0f); + const float tilt_speed_mouse = pan_speed_mouse; + + const float pan_speed = math::radians(110.0f); const float tilt_speed = pan_speed; const input::control* move_slow = ctx->controls["move_slow"]; @@ -371,55 +374,89 @@ void setup_controls(game::context* ctx) ); // Pan left - ctx->controls["mouse_left"]->set_active_callback + ctx->controls["pan_left"]->set_active_callback + ( + [ctx, three_dof_eid, pan_speed](float value) + { + auto& three_dof = ctx->entity_registry->get(three_dof_eid); + three_dof.yaw += pan_speed * value * (1.0f / 60.0f); + } + ); + ctx->controls["pan_left_mouse"]->set_active_callback ( - [ctx, three_dof_eid, pan_speed, mouse_rotate](float value) + [ctx, three_dof_eid, pan_speed_mouse, mouse_rotate](float value) { if (!mouse_rotate->is_active()) return; auto& three_dof = ctx->entity_registry->get(three_dof_eid); - three_dof.yaw += pan_speed * value * (1.0f / 60.0f); + three_dof.yaw += pan_speed_mouse * value * (1.0f / 60.0f); } ); // Pan right - ctx->controls["mouse_right"]->set_active_callback + ctx->controls["pan_right"]->set_active_callback ( - [ctx, three_dof_eid, pan_speed, mouse_rotate](float value) + [ctx, three_dof_eid, pan_speed](float value) + { + auto& three_dof = ctx->entity_registry->get(three_dof_eid); + three_dof.yaw -= pan_speed * value * (1.0f / 60.0f); + } + ); + ctx->controls["pan_right_mouse"]->set_active_callback + ( + [ctx, three_dof_eid, pan_speed_mouse, mouse_rotate](float value) { if (!mouse_rotate->is_active()) return; auto& three_dof = ctx->entity_registry->get(three_dof_eid); - three_dof.yaw -= pan_speed * value * (1.0f / 60.0f); + three_dof.yaw -= pan_speed_mouse * value * (1.0f / 60.0f); } ); // Tilt up - ctx->controls["mouse_up"]->set_active_callback + ctx->controls["tilt_up"]->set_active_callback ( - [ctx, three_dof_eid, tilt_speed, mouse_rotate](float value) + [ctx, three_dof_eid, tilt_speed](float value) + { + auto& three_dof = ctx->entity_registry->get(three_dof_eid); + three_dof.pitch -= tilt_speed * value * (1.0f / 60.0f); + three_dof.pitch = std::max(math::radians(-90.0f), three_dof.pitch); + } + ); + ctx->controls["tilt_up_mouse"]->set_active_callback + ( + [ctx, three_dof_eid, tilt_speed_mouse, mouse_rotate](float value) { if (!mouse_rotate->is_active()) return; auto& three_dof = ctx->entity_registry->get(three_dof_eid); - three_dof.pitch -= tilt_speed * value * (1.0f / 60.0f); + three_dof.pitch -= tilt_speed_mouse * value * (1.0f / 60.0f); three_dof.pitch = std::max(math::radians(-90.0f), three_dof.pitch); } ); // Tilt down - ctx->controls["mouse_down"]->set_active_callback + ctx->controls["tilt_down"]->set_active_callback ( - [ctx, three_dof_eid, tilt_speed, mouse_rotate](float value) + [ctx, three_dof_eid, tilt_speed](float value) + { + auto& three_dof = ctx->entity_registry->get(three_dof_eid); + three_dof.pitch += tilt_speed * value * (1.0f / 60.0f); + three_dof.pitch = std::min(math::radians(90.0f), three_dof.pitch); + } + ); + ctx->controls["tilt_down_mouse"]->set_active_callback + ( + [ctx, three_dof_eid, tilt_speed_mouse, mouse_rotate](float value) { if (!mouse_rotate->is_active()) return; auto& three_dof = ctx->entity_registry->get(three_dof_eid); - three_dof.pitch += tilt_speed * value * (1.0f / 60.0f); + three_dof.pitch += tilt_speed_mouse * value * (1.0f / 60.0f); three_dof.pitch = std::min(math::radians(90.0f), three_dof.pitch); } ); diff --git a/src/game/states/loading.cpp b/src/game/states/loading.cpp index 8173efa..1b3cec5 100644 --- a/src/game/states/loading.cpp +++ b/src/game/states/loading.cpp @@ -125,11 +125,205 @@ void exit(game::context* ctx) void load_controls(game::context* ctx) { + // Get keyboard and mouse devices + input::keyboard* keyboard = ctx->app->get_keyboard(); + input::mouse* mouse = ctx->app->get_mouse(); + + const std::unordered_map gamepad_button_map = + { + {"a", input::game_controller_button::a}, + {"b", input::game_controller_button::b}, + {"x", input::game_controller_button::x}, + {"y", input::game_controller_button::y}, + {"back", input::game_controller_button::back}, + {"guide", input::game_controller_button::guide}, + {"start", input::game_controller_button::start}, + {"leftstick", input::game_controller_button::left_stick}, + {"rightstick", input::game_controller_button::right_stick}, + {"leftshoulder", input::game_controller_button::left_shoulder}, + {"rightshoulder", input::game_controller_button::right_shoulder}, + {"dpup", input::game_controller_button::dpad_up}, + {"dpdown", input::game_controller_button::dpad_down}, + {"dpleft", input::game_controller_button::dpad_left}, + {"dpright", input::game_controller_button::dpad_right} + }; + + const std::unordered_map gamepad_axis_map = + { + {"leftx", input::game_controller_axis::left_x}, + {"lefty", input::game_controller_axis::left_y}, + {"rightx", input::game_controller_axis::right_x}, + {"righty", input::game_controller_axis::right_y}, + {"lefttrigger", input::game_controller_axis::left_trigger}, + {"righttrigger", input::game_controller_axis::right_trigger} + }; + + // Check if a control profile is set in the config file + if (ctx->config->contains("control_profile")) + { + // Load control profile + json* profile = ctx->resource_manager->load((*ctx->config)["control_profile"].get()); + + // Parse control profile + for (auto it = profile->begin(); it != profile->end(); ++it) + { + // Parse control name + if (!it->contains("name")) + { + ctx->logger->warning("Unnamed control in control profile"); + continue; + } + std::string name = (*it)["name"].get(); + + // Find or create control + input::control* control; + if (ctx->controls.count(name)) + { + control = ctx->controls[name]; + } + else + { + control = new input::control; + control->set_deadzone(0.15f); + ctx->controls[name] = control; + } + + // Parse control device + if (!it->contains("device")) + { + ctx->logger->warning("Control \"" + name + "\" not mapped to a device"); + continue; + } + std::string device = (*it)["device"].get(); + + if (device == "keyboard") + { + // Parse key name + if (!it->contains("key")) + { + ctx->logger->warning("Control \"" + name + "\" has invalid keyboard mapping"); + continue; + } + std::string key = (*it)["key"].get(); + + // Get scancode from key name + input::scancode scancode = keyboard->get_scancode_from_name(key.c_str()); + if (scancode == input::scancode::unknown) + { + ctx->logger->warning("Control \"" + name + "\" mapped to unknown keyboard key \"" + key + "\""); + continue; + } + + // Map control to keyboard key + ctx->input_event_router->add_mapping(input::key_mapping(control, nullptr, scancode)); + + ctx->logger->log("Mapped control \"" + name + "\" to keyboard key \"" + key + "\""); + } + else if (device == "mouse") + { + if (it->contains("button")) + { + // Parse mouse button index + int button = (*it)["button"].get(); + + // Map control to mouse button + ctx->input_event_router->add_mapping(input::mouse_button_mapping(control, nullptr, button)); + + ctx->logger->log("Mapped control \"" + name + "\" to mouse button " + std::to_string(button)); + } + else if (it->contains("wheel")) + { + // Parse mouse wheel axis + std::string wheel = (*it)["wheel"].get(); + input::mouse_wheel_axis axis; + if (wheel == "+x") + axis = input::mouse_wheel_axis::positive_x; + else if (wheel == "-x") + axis = input::mouse_wheel_axis::negative_x; + else if (wheel == "+y") + axis = input::mouse_wheel_axis::positive_y; + else if (wheel == "-y") + axis = input::mouse_wheel_axis::negative_y; + else + { + ctx->logger->warning("Control \"" + name + "\" is mapped to invalid mouse wheel axis \"" + wheel + "\""); + continue; + } + + // Map control to mouse wheel axis + ctx->input_event_router->add_mapping(input::mouse_wheel_mapping(control, nullptr, axis)); + + ctx->logger->log("Mapped control \"" + name + "\" to mouse wheel axis " + wheel); + } + else + { + ctx->logger->warning("Control \"" + name + "\" has invalid mouse mapping"); + continue; + } + } + else if (device == "gamepad") + { + if (it->contains("button")) + { + // Parse gamepad button + std::string button = (*it)["button"].get(); + + auto button_it = gamepad_button_map.find(button); + if (button_it == gamepad_button_map.end()) + { + ctx->logger->warning("Control \"" + name + "\" is mapped to invalid gamepad button \"" + button + "\""); + continue; + } + + // Map control to gamepad button + ctx->input_event_router->add_mapping(input::game_controller_button_mapping(control, nullptr, button_it->second)); + + ctx->logger->log("Mapped control \"" + name + "\" to gamepad button " + button); + } + else if (it->contains("axis")) + { + std::string axis = (*it)["axis"].get(); + + // Parse gamepad axis name + const std::string axis_name = axis.substr(0, axis.length() - 1); + auto axis_it = gamepad_axis_map.find(axis_name); + if (axis_it == gamepad_axis_map.end()) + { + ctx->logger->warning("Control \"" + name + "\" is mapped to invalid gamepad axis \"" + axis_name + "\""); + continue; + } + + // Parse gamepad axis sign + const char axis_sign = axis.back(); + if (axis_sign != '-' && axis_sign != '+') + { + ctx->logger->warning("Control \"" + name + "\" is mapped to gamepad axis with invalid sign \"" + axis_sign + "\""); + continue; + } + bool axis_negative = (axis_sign == '-'); + + // Map control to gamepad axis + ctx->input_event_router->add_mapping(input::game_controller_axis_mapping(control, nullptr, axis_it->second, axis_negative)); + + ctx->logger->log("Mapped control \"" + name + "\" to gamepad axis " + axis); + } + else + { + ctx->logger->log("Control \"" + name + "\" has invalid gamepad mapping"); + continue; + } + } + else + { + ctx->logger->warning("Control \"" + name + "\" bound to unknown device \"" + device + "\""); + } + } + } + // Toggle fullscreen if (!ctx->controls.count("toggle_fullscreen")) { input::control* control = new input::control(); - ctx->input_event_router->add_mapping(input::key_mapping(control, nullptr, input::scancode::f11)); ctx->controls["toggle_fullscreen"] = control; } ctx->controls["toggle_fullscreen"]->set_activated_callback @@ -157,7 +351,6 @@ void load_controls(game::context* ctx) if (!ctx->controls.count("screenshot")) { input::control* control = new input::control(); - ctx->input_event_router->add_mapping(input::key_mapping(control, nullptr, input::scancode::f12)); ctx->controls["screenshot"] = control; } ctx->controls["screenshot"]->set_activated_callback @@ -173,8 +366,6 @@ void load_controls(game::context* ctx) if (!ctx->controls.count("menu_back")) { input::control* control = new input::control(); - ctx->input_event_router->add_mapping(input::key_mapping(control, nullptr, input::scancode::escape)); - ctx->input_event_router->add_mapping(input::key_mapping(control, nullptr, input::scancode::backspace)); ctx->controls["menu_back"] = control; } ctx->controls["menu_back"]->set_activated_callback @@ -186,8 +377,6 @@ void load_controls(game::context* ctx) if (!ctx->controls.count("dolly_forward")) { input::control* control = new input::control(); - ctx->input_event_router->add_mapping(input::key_mapping(control, nullptr, input::scancode::w)); - ctx->input_event_router->add_mapping(input::game_controller_axis_mapping(control, nullptr, input::game_controller_axis::left_y, true)); ctx->controls["dolly_forward"] = control; } @@ -195,8 +384,6 @@ void load_controls(game::context* ctx) if (!ctx->controls.count("dolly_backward")) { input::control* control = new input::control(); - ctx->input_event_router->add_mapping(input::key_mapping(control, nullptr, input::scancode::s)); - ctx->input_event_router->add_mapping(input::game_controller_axis_mapping(control, nullptr, input::game_controller_axis::left_y, false)); ctx->controls["dolly_backward"] = control; } @@ -204,8 +391,6 @@ void load_controls(game::context* ctx) if (!ctx->controls.count("truck_left")) { input::control* control = new input::control(); - ctx->input_event_router->add_mapping(input::key_mapping(control, nullptr, input::scancode::a)); - ctx->input_event_router->add_mapping(input::game_controller_axis_mapping(control, nullptr, input::game_controller_axis::left_x, true)); ctx->controls["truck_left"] = control; } @@ -213,8 +398,6 @@ void load_controls(game::context* ctx) if (!ctx->controls.count("truck_right")) { input::control* control = new input::control(); - ctx->input_event_router->add_mapping(input::key_mapping(control, nullptr, input::scancode::d)); - ctx->input_event_router->add_mapping(input::game_controller_axis_mapping(control, nullptr, input::game_controller_axis::left_x, false)); ctx->controls["truck_right"] = control; } @@ -222,7 +405,6 @@ void load_controls(game::context* ctx) if (!ctx->controls.count("pedestal_up")) { input::control* control = new input::control(); - ctx->input_event_router->add_mapping(input::mouse_wheel_mapping(control, nullptr, input::mouse_wheel_axis::positive_y)); ctx->controls["pedestal_up"] = control; } @@ -230,7 +412,6 @@ void load_controls(game::context* ctx) if (!ctx->controls.count("pedestal_down")) { input::control* control = new input::control(); - ctx->input_event_router->add_mapping(input::mouse_wheel_mapping(control, nullptr, input::mouse_wheel_axis::negative_y)); ctx->controls["pedestal_down"] = control; } @@ -238,7 +419,6 @@ void load_controls(game::context* ctx) if (!ctx->controls.count("move_slow")) { input::control* control = new input::control(); - ctx->input_event_router->add_mapping(input::key_mapping(control, nullptr, input::scancode::left_ctrl)); ctx->controls["move_slow"] = control; } @@ -246,7 +426,6 @@ void load_controls(game::context* ctx) if (!ctx->controls.count("move_fast")) { input::control* control = new input::control(); - ctx->input_event_router->add_mapping(input::key_mapping(control, nullptr, input::scancode::left_shift)); ctx->controls["move_fast"] = control; } @@ -254,48 +433,65 @@ void load_controls(game::context* ctx) if (!ctx->controls.count("mouse_rotate")) { input::control* control = new input::control(); - ctx->input_event_router->add_mapping(input::mouse_button_mapping(control, nullptr, 3)); - ctx->input_event_router->add_mapping(input::key_mapping(control, nullptr, input::scancode::left_alt)); ctx->controls["mouse_rotate"] = control; } - // Mouse left - if (!ctx->controls.count("mouse_left")) + // Pan left + if (!ctx->controls.count("pan_left")) + { + input::control* control = new input::control(); + ctx->controls["pan_left"] = control; + } + if (!ctx->controls.count("pan_left_mouse")) { input::control* control = new input::control(); ctx->input_event_router->add_mapping(input::mouse_motion_mapping(control, nullptr, input::mouse_motion_axis::negative_x)); - ctx->controls["mouse_left"] = control; + ctx->controls["pan_left_mouse"] = control; } - // Mouse right - if (!ctx->controls.count("mouse_right")) + // Pan right + if (!ctx->controls.count("pan_right")) + { + input::control* control = new input::control(); + ctx->controls["pan_right"] = control; + } + if (!ctx->controls.count("pan_right_mouse")) { input::control* control = new input::control(); ctx->input_event_router->add_mapping(input::mouse_motion_mapping(control, nullptr, input::mouse_motion_axis::positive_x)); - ctx->controls["mouse_right"] = control; + ctx->controls["pan_right_mouse"] = control; } - // Mouse up - if (!ctx->controls.count("mouse_up")) + // Tilt up + if (!ctx->controls.count("tilt_up")) + { + input::control* control = new input::control(); + ctx->controls["tilt_up"] = control; + } + if (!ctx->controls.count("tilt_up_mouse")) { input::control* control = new input::control(); ctx->input_event_router->add_mapping(input::mouse_motion_mapping(control, nullptr, input::mouse_motion_axis::negative_y)); - ctx->controls["mouse_up"] = control; + ctx->controls["tilt_up_mouse"] = control; } - // Mouse down - if (!ctx->controls.count("mouse_down")) + // Tilt down + if (!ctx->controls.count("tilt_down")) + { + input::control* control = new input::control(); + ctx->controls["tilt_down"] = control; + } + if (!ctx->controls.count("tilt_down_mouse")) { input::control* control = new input::control(); ctx->input_event_router->add_mapping(input::mouse_motion_mapping(control, nullptr, input::mouse_motion_axis::positive_y)); - ctx->controls["mouse_down"] = control; + ctx->controls["tilt_down_mouse"] = control; } // Use tool if (!ctx->controls.count("use_tool")) { input::control* control = new input::control(); - ctx->input_event_router->add_mapping(input::mouse_button_mapping(control, nullptr, 1)); ctx->controls["use_tool"] = control; } } diff --git a/src/input/game-controller.hpp b/src/input/game-controller.hpp index 46cef7a..0b73ad9 100644 --- a/src/input/game-controller.hpp +++ b/src/input/game-controller.hpp @@ -49,8 +49,8 @@ enum class game_controller_axis left_y, right_x, right_y, - trigger_left, - trigger_right, + left_trigger, + right_trigger, }; /** diff --git a/src/input/sdl-game-controller-tables.cpp b/src/input/sdl-game-controller-tables.cpp index 12c5b57..c318ace 100644 --- a/src/input/sdl-game-controller-tables.cpp +++ b/src/input/sdl-game-controller-tables.cpp @@ -47,8 +47,8 @@ const game_controller_axis sdl_axis_table[6] = game_controller_axis::left_y, // SDL_CONTROLLER_AXIS_LEFTY, game_controller_axis::right_x, // SDL_CONTROLLER_AXIS_RIGHTX, game_controller_axis::right_y, // SDL_CONTROLLER_AXIS_RIGHTY, - game_controller_axis::trigger_left, // SDL_CONTROLLER_AXIS_TRIGGERLEFT, - game_controller_axis::trigger_right, // SDL_CONTROLLER_AXIS_TRIGGERRIGHT, + game_controller_axis::left_trigger, // SDL_CONTROLLER_AXIS_TRIGGERLEFT, + game_controller_axis::right_trigger, // SDL_CONTROLLER_AXIS_TRIGGERRIGHT, }; } // namespace input