mirror of
https://github.com/Mr-Wiseguy/Zelda64Recomp.git
synced 2024-12-22 19:11:54 +01:00
Implemented mouse aiming
This commit is contained in:
parent
539497f84d
commit
b28614b128
@ -74,31 +74,50 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- mouse sensitivity -->
|
||||
<div class="config-option" data-event-mouseover="set_cur_config_index(3)">
|
||||
<label class="config-option__title">Mouse Sensitivity</label>
|
||||
<div class="config-option__range-wrapper config-option__list">
|
||||
<label class="config-option__range-label">{{mouse_sensitivity}}%</label>
|
||||
<input
|
||||
class="nav-vert"
|
||||
data-event-blur="set_cur_config_index(-1)"
|
||||
data-event-focus="set_cur_config_index(3)"
|
||||
id="mouse_sensitivity_input"
|
||||
type="range"
|
||||
min="0"
|
||||
max="100"
|
||||
style="flex: 1; margin: 0dp;"
|
||||
data-value="mouse_sensitivity"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- targeting mode -->
|
||||
<div class="config-option" data-event-mouseover="set_cur_config_index(3)" id="conf-general__Background-Input">
|
||||
<div class="config-option" data-event-mouseover="set_cur_config_index(4)" id="conf-general__Background-Input">
|
||||
<label class="config-option__title">Background Input</label>
|
||||
<div class="config-option__list">
|
||||
<input
|
||||
type="radio"
|
||||
data-event-blur="set_cur_config_index(-1)"
|
||||
data-event-focus="set_cur_config_index(3)"
|
||||
data-event-focus="set_cur_config_index(4)"
|
||||
name="background_input_mode"
|
||||
data-checked="background_input_mode"
|
||||
value="On"
|
||||
id="bg_input_enabled"
|
||||
style="nav-up: #gyro_sensitivity_input"
|
||||
style="nav-up: #mouse_sensitivity_input"
|
||||
/>
|
||||
<label class="config-option__tab-label" for="bg_input_enabled">On</label>
|
||||
|
||||
<input
|
||||
type="radio"
|
||||
data-event-blur="set_cur_config_index(-1)"
|
||||
data-event-focus="set_cur_config_index(3)"
|
||||
data-event-focus="set_cur_config_index(4)"
|
||||
name="background_input_mode"
|
||||
data-checked="background_input_mode"
|
||||
value="Off"
|
||||
id="bg_input_disabled"
|
||||
style="nav-up: #gyro_sensitivity_input"
|
||||
style="nav-up: #mouse_sensitivity_input"
|
||||
/>
|
||||
<label class="config-option__tab-label" for="bg_input_disabled">Off</label>
|
||||
</div>
|
||||
@ -119,6 +138,12 @@
|
||||
<b>Note: To recalibrate controller gyro, set the controller down on a still, flat surface for 5 seconds.</b>
|
||||
</p>
|
||||
<p data-if="cur_config_index == 3">
|
||||
Controls the sensitivity of mouse aiming when using items in first person for controllers that support it. <b>Setting this to zero will disable mouse aiming.</b>
|
||||
<br />
|
||||
<br />
|
||||
<b>Note: This option does not allow mouse buttons to activate items. Mouse aiming is meant for using inputs that are mapped to mouse movement, such as gyro on Steam Deck.</b>
|
||||
</p>
|
||||
<p data-if="cur_config_index == 4">
|
||||
Allows the game to read controller input when out of focus.
|
||||
<br/>
|
||||
<b>This setting does not affect keyboard input.</b>
|
||||
|
@ -66,6 +66,7 @@ namespace recomp {
|
||||
bool get_input_digital(const InputField& field);
|
||||
bool get_input_digital(const std::span<const recomp::InputField> fields);
|
||||
void get_gyro_deltas(float* x, float* y);
|
||||
void get_mouse_deltas(float* x, float* y);
|
||||
|
||||
enum class InputDevice {
|
||||
Controller,
|
||||
@ -125,9 +126,11 @@ namespace recomp {
|
||||
int get_rumble_strength();
|
||||
void set_rumble_strength(int strength);
|
||||
|
||||
// Gyro sensitivity ranges from 0 to 100 (gets doubled).
|
||||
// Gyro and mouse sensitivities range from 0 to 100.
|
||||
int get_gyro_sensitivity();
|
||||
int get_mouse_sensitivity();
|
||||
void set_gyro_sensitivity(int strength);
|
||||
void set_mouse_sensitivity(int strength);
|
||||
|
||||
enum class TargetingMode {
|
||||
Switch,
|
||||
|
@ -9,7 +9,7 @@ s32 func_80847190(PlayState* play, Player* this, s32 arg2);
|
||||
s16 func_80832754(Player* this, s32 arg1);
|
||||
s32 func_8082EF20(Player* this);
|
||||
|
||||
// Patched to add gyro aiming
|
||||
// @recomp Patched to add gyro and mouse aiming.
|
||||
s32 func_80847190(PlayState* play, Player* this, s32 arg2) {
|
||||
s32 pad;
|
||||
s16 var_s0;
|
||||
@ -24,18 +24,19 @@ s32 func_80847190(PlayState* play, Player* this, s32 arg2) {
|
||||
}
|
||||
else {
|
||||
static float total_gyro_x, total_gyro_y;
|
||||
static float total_mouse_x, total_mouse_y;
|
||||
static float filtered_gyro_x, filtered_gyro_y;
|
||||
static int applied_gyro_x, applied_gyro_y;
|
||||
static int applied_aim_x, applied_aim_y;
|
||||
|
||||
const float filter_factor = 0.00f;
|
||||
const float gyro_filter_factor = 0.00f;
|
||||
|
||||
// TODO remappable gyro reset button
|
||||
if (play->state.input[0].press.button & BTN_L) {
|
||||
total_gyro_x = 0;
|
||||
total_gyro_y = 0;
|
||||
filtered_gyro_x = 0;
|
||||
filtered_gyro_y = 0;
|
||||
}
|
||||
// // TODO remappable gyro reset button
|
||||
// if (play->state.input[0].press.button & BTN_L) {
|
||||
// total_gyro_x = 0;
|
||||
// total_gyro_y = 0;
|
||||
// filtered_gyro_x = 0;
|
||||
// filtered_gyro_y = 0;
|
||||
// }
|
||||
|
||||
float delta_gyro_x, delta_gyro_y;
|
||||
recomp_get_gyro_deltas(&delta_gyro_x, &delta_gyro_y);
|
||||
@ -43,18 +44,28 @@ s32 func_80847190(PlayState* play, Player* this, s32 arg2) {
|
||||
total_gyro_x += delta_gyro_x;
|
||||
total_gyro_y += delta_gyro_y;
|
||||
|
||||
filtered_gyro_x = filtered_gyro_x * filter_factor + total_gyro_x * (1.0f - filter_factor);
|
||||
filtered_gyro_y = filtered_gyro_y * filter_factor + total_gyro_y * (1.0f - filter_factor);
|
||||
filtered_gyro_x = filtered_gyro_x * gyro_filter_factor + total_gyro_x * (1.0f - gyro_filter_factor);
|
||||
filtered_gyro_y = filtered_gyro_y * gyro_filter_factor + total_gyro_y * (1.0f - gyro_filter_factor);
|
||||
|
||||
int target_gyro_x = (int)filtered_gyro_x;
|
||||
int target_gyro_y = (int)filtered_gyro_y;
|
||||
float delta_mouse_x, delta_mouse_y;
|
||||
recomp_get_mouse_deltas(&delta_mouse_x, &delta_mouse_y);
|
||||
|
||||
total_mouse_x += delta_mouse_x;
|
||||
total_mouse_y += delta_mouse_y;
|
||||
|
||||
// The gyro X-axis (tilt) corresponds to the camera X-axis (tilt).
|
||||
// The gyro Y-axis (left/right rotation) corresponds to the camera Y-axis (left/right rotation).
|
||||
// The mouse Y-axis (up/down movement) corresponds to the camera X-axis (tilt).
|
||||
// The mouse X-axis (left/right movement) corresponds to the camera Y-axis (left/right rotation).
|
||||
int target_aim_x = (int)(filtered_gyro_x * -3.0f + total_mouse_y * 20.0f);
|
||||
int target_aim_y = (int)(filtered_gyro_y * 3.0f + total_mouse_x * -20.0f);
|
||||
|
||||
s16 temp3;
|
||||
|
||||
temp3 = ((play->state.input[0].rel.stick_y >= 0) ? 1 : -1) *
|
||||
(s32)((1.0f - Math_CosS(play->state.input[0].rel.stick_y * 0xC8)) * 1500.0f);
|
||||
this->actor.focus.rot.x += temp3 + (s32)((target_gyro_x - applied_gyro_x) * -1.5f);
|
||||
applied_gyro_x = target_gyro_x;
|
||||
this->actor.focus.rot.x += temp3 + (s32)(target_aim_x - applied_aim_x);
|
||||
applied_aim_x = target_aim_x;
|
||||
|
||||
if (this->stateFlags1 & PLAYER_STATE1_800000) {
|
||||
this->actor.focus.rot.x = CLAMP(this->actor.focus.rot.x, -0x1F40, 0xFA0);
|
||||
@ -66,8 +77,8 @@ s32 func_80847190(PlayState* play, Player* this, s32 arg2) {
|
||||
var_s0 = this->actor.focus.rot.y - this->actor.shape.rot.y;
|
||||
temp3 = ((play->state.input[0].rel.stick_x >= 0) ? 1 : -1) *
|
||||
(s32)((1.0f - Math_CosS(play->state.input[0].rel.stick_x * 0xC8)) * -1500.0f);
|
||||
var_s0 += temp3 + (s32)((target_gyro_y - applied_gyro_y) * 1.5f);
|
||||
applied_gyro_y = target_gyro_y;
|
||||
var_s0 += temp3 + (s32)(target_aim_y - applied_aim_y);
|
||||
applied_aim_y = target_aim_y;
|
||||
|
||||
this->actor.focus.rot.y = CLAMP(var_s0, -0x4AAA, 0x4AAA) + this->actor.shape.rot.y;
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ typedef enum {
|
||||
extern RecompCameraMode recomp_camera_mode;
|
||||
|
||||
DECLARE_FUNC(void, recomp_get_gyro_deltas, float* x, float* y);
|
||||
DECLARE_FUNC(void, recomp_get_mouse_deltas, float* x, float* y);
|
||||
DECLARE_FUNC(int, recomp_get_targeting_mode);
|
||||
|
||||
#endif
|
||||
|
@ -46,3 +46,4 @@ osContStartReadData_recomp = 0x8F000070;
|
||||
osContGetReadData_recomp = 0x8F000074;
|
||||
osContStartQuery_recomp = 0x8F000078;
|
||||
osContGetQuery_recomp = 0x8F00007C;
|
||||
recomp_get_mouse_deltas = 0x8F000080;
|
||||
|
@ -130,6 +130,7 @@ void save_general_config(const std::filesystem::path& path) {
|
||||
recomp::to_json(config_json["background_input_mode"], recomp::get_background_input_mode());
|
||||
config_json["rumble_strength"] = recomp::get_rumble_strength();
|
||||
config_json["gyro_sensitivity"] = recomp::get_gyro_sensitivity();
|
||||
config_json["mouse_sensitivity"] = recomp::get_mouse_sensitivity();
|
||||
config_json["debug_mode"] = recomp::get_debug_mode_enabled();
|
||||
config_file << std::setw(4) << config_json;
|
||||
}
|
||||
@ -144,6 +145,7 @@ void load_general_config(const std::filesystem::path& path) {
|
||||
recomp::set_background_input_mode(from_or_default(config_json, "background_input_mode", recomp::BackgroundInputMode::On));
|
||||
recomp::set_rumble_strength(from_or_default(config_json, "rumble_strength", 25));
|
||||
recomp::set_gyro_sensitivity(from_or_default(config_json, "gyro_sensitivity", 50));
|
||||
recomp::set_mouse_sensitivity(from_or_default(config_json, "mouse_sensitivity", 0));
|
||||
recomp::set_debug_mode_enabled(from_or_default(config_json, "debug_mode", false));
|
||||
}
|
||||
|
||||
|
@ -30,9 +30,13 @@ static struct {
|
||||
std::mutex cur_controllers_mutex;
|
||||
std::vector<SDL_GameController*> cur_controllers{};
|
||||
std::unordered_map<SDL_JoystickID, ControllerState> controller_states;
|
||||
|
||||
std::array<float, 2> rotation_delta{};
|
||||
std::mutex pending_rotation_mutex;
|
||||
std::array<float, 2> mouse_delta{};
|
||||
std::mutex pending_input_mutex;
|
||||
std::array<float, 2> pending_rotation_delta{};
|
||||
std::array<float, 2> pending_mouse_delta{};
|
||||
|
||||
float cur_rumble;
|
||||
bool rumble_active;
|
||||
} InputState;
|
||||
@ -189,12 +193,19 @@ bool sdl_event_filter(void* userdata, SDL_Event* event) {
|
||||
state.motion.GetPlayerSpaceGyro(rot_x, rot_y);
|
||||
|
||||
{
|
||||
std::lock_guard lock{ InputState.pending_rotation_mutex };
|
||||
std::lock_guard lock{ InputState.pending_input_mutex };
|
||||
InputState.pending_rotation_delta[0] += rot_x;
|
||||
InputState.pending_rotation_delta[1] += rot_y;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDL_EventType::SDL_MOUSEMOTION:
|
||||
if (!recomp::game_input_disabled()) {
|
||||
SDL_MouseMotionEvent* motion_event = &event->motion;
|
||||
std::lock_guard lock{ InputState.pending_input_mutex };
|
||||
InputState.pending_mouse_delta[0] += motion_event->xrel;
|
||||
InputState.pending_mouse_delta[1] += motion_event->yrel;
|
||||
}
|
||||
default:
|
||||
queue_if_enabled(event);
|
||||
break;
|
||||
@ -207,7 +218,18 @@ void recomp::handle_events() {
|
||||
static bool exited = false;
|
||||
while (SDL_PollEvent(&cur_event) && !exited) {
|
||||
exited = sdl_event_filter(nullptr, &cur_event);
|
||||
SDL_ShowCursor(cursor_enabled ? SDL_ENABLE : SDL_DISABLE);
|
||||
|
||||
// Lock the cursor if all three conditions are true: mouse aiming is enabled, game input is not disabled, and the game has been started.
|
||||
bool cursor_locked = (recomp::get_mouse_sensitivity() != 0) && !recomp::game_input_disabled() && ultramodern::is_game_started();
|
||||
|
||||
// Hide the cursor based on its enable state, but override visibility to false if the cursor is locked.
|
||||
bool cursor_visible = cursor_enabled;
|
||||
if (cursor_locked) {
|
||||
cursor_visible = false;
|
||||
}
|
||||
|
||||
SDL_ShowCursor(cursor_visible ? SDL_ENABLE : SDL_DISABLE);
|
||||
SDL_SetRelativeMouseMode(cursor_locked ? SDL_TRUE : SDL_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -352,9 +374,13 @@ void recomp::poll_inputs() {
|
||||
|
||||
// Read the deltas while resetting them to zero.
|
||||
{
|
||||
std::lock_guard lock{ InputState.pending_rotation_mutex };
|
||||
std::lock_guard lock{ InputState.pending_input_mutex };
|
||||
|
||||
InputState.rotation_delta = InputState.pending_rotation_delta;
|
||||
InputState.pending_rotation_delta = { 0.0f, 0.0f };
|
||||
|
||||
InputState.mouse_delta = InputState.pending_mouse_delta;
|
||||
InputState.pending_mouse_delta = { 0.0f, 0.0f };
|
||||
}
|
||||
|
||||
// Quicksaving is disabled for now and will likely have more limited functionality
|
||||
@ -503,11 +529,18 @@ bool recomp::get_input_digital(const std::span<const recomp::InputField> fields)
|
||||
|
||||
void recomp::get_gyro_deltas(float* x, float* y) {
|
||||
std::array<float, 2> cur_rotation_delta = InputState.rotation_delta;
|
||||
float sensitivity = (float)recomp::get_gyro_sensitivity() / 50.0f;
|
||||
float sensitivity = (float)recomp::get_gyro_sensitivity() / 100.0f;
|
||||
*x = cur_rotation_delta[0] * sensitivity;
|
||||
*y = cur_rotation_delta[1] * sensitivity;
|
||||
}
|
||||
|
||||
void recomp::get_mouse_deltas(float* x, float* y) {
|
||||
std::array<float, 2> cur_mouse_delta = InputState.mouse_delta;
|
||||
float sensitivity = (float)recomp::get_mouse_sensitivity() / 100.0f;
|
||||
*x = cur_mouse_delta[0] * sensitivity;
|
||||
*y = cur_mouse_delta[1] * sensitivity;
|
||||
}
|
||||
|
||||
bool recomp::game_input_disabled() {
|
||||
// Disable input if any menu is open.
|
||||
return recomp::get_current_menu() != recomp::Menu::None;
|
||||
|
@ -35,6 +35,13 @@ extern "C" void recomp_get_gyro_deltas(uint8_t* rdram, recomp_context* ctx) {
|
||||
recomp::get_gyro_deltas(x_out, y_out);
|
||||
}
|
||||
|
||||
extern "C" void recomp_get_mouse_deltas(uint8_t* rdram, recomp_context* ctx) {
|
||||
float* x_out = _arg<0, float*>(rdram, ctx);
|
||||
float* y_out = _arg<1, float*>(rdram, ctx);
|
||||
|
||||
recomp::get_mouse_deltas(x_out, y_out);
|
||||
}
|
||||
|
||||
extern "C" void recomp_powf(uint8_t* rdram, recomp_context* ctx) {
|
||||
float a = _arg<0, float>(rdram, ctx);
|
||||
float b = ctx->f14.fl; //_arg<1, float>(rdram, ctx);
|
||||
|
@ -264,7 +264,8 @@ void open_quit_game_prompt() {
|
||||
|
||||
struct ControlOptionsContext {
|
||||
int rumble_strength = 50; // 0 to 100
|
||||
int gyro_sensitivity = 50; // 0 to 200
|
||||
int gyro_sensitivity = 50; // 0 to 100
|
||||
int mouse_sensitivity = 50; // 0 to 100
|
||||
recomp::TargetingMode targeting_mode = recomp::TargetingMode::Switch;
|
||||
recomp::BackgroundInputMode background_input_mode = recomp::BackgroundInputMode::On;
|
||||
};
|
||||
@ -286,6 +287,10 @@ int recomp::get_gyro_sensitivity() {
|
||||
return control_options_context.gyro_sensitivity;
|
||||
}
|
||||
|
||||
int recomp::get_mouse_sensitivity() {
|
||||
return control_options_context.mouse_sensitivity;
|
||||
}
|
||||
|
||||
void recomp::set_gyro_sensitivity(int sensitivity) {
|
||||
control_options_context.gyro_sensitivity = sensitivity;
|
||||
if (general_model_handle) {
|
||||
@ -293,6 +298,13 @@ void recomp::set_gyro_sensitivity(int sensitivity) {
|
||||
}
|
||||
}
|
||||
|
||||
void recomp::set_mouse_sensitivity(int sensitivity) {
|
||||
control_options_context.mouse_sensitivity = sensitivity;
|
||||
if (general_model_handle) {
|
||||
general_model_handle.DirtyVariable("mouse_sensitivity");
|
||||
}
|
||||
}
|
||||
|
||||
recomp::TargetingMode recomp::get_targeting_mode() {
|
||||
return control_options_context.targeting_mode;
|
||||
}
|
||||
@ -787,6 +799,7 @@ public:
|
||||
|
||||
constructor.Bind("rumble_strength", &control_options_context.rumble_strength);
|
||||
constructor.Bind("gyro_sensitivity", &control_options_context.gyro_sensitivity);
|
||||
constructor.Bind("mouse_sensitivity", &control_options_context.mouse_sensitivity);
|
||||
bind_option(constructor, "targeting_mode", &control_options_context.targeting_mode);
|
||||
bind_option(constructor, "background_input_mode", &control_options_context.background_input_mode);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user