diff --git a/rpcs3/Emu/Cell/Modules/cellGem.cpp b/rpcs3/Emu/Cell/Modules/cellGem.cpp index ec1cf8d002..f1d0a5a4a6 100644 --- a/rpcs3/Emu/Cell/Modules/cellGem.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGem.cpp @@ -3993,9 +3993,9 @@ error_code cellGemSetRumble(u32 gem_num, u8 rumble) return CELL_OK; } -error_code cellGemSetYaw(u32 gem_num, vm::ptr z_direction) +error_code cellGemSetYaw(u32 gem_num, f32 z_direction_x, f32 z_direction_y, f32 z_direction_z, f32 z_direction_w) { - cellGem.todo("cellGemSetYaw(gem_num=%d, z_direction=*0x%x)", gem_num, z_direction); + cellGem.warning("cellGemSetYaw(gem_num=%d, z_direction_x=%f, z_direction_y=%f, z_direction_z=%f, z_direction_w=%f)", gem_num, z_direction_x, z_direction_y, z_direction_z, z_direction_w); auto& gem = g_fxo->get(); @@ -4006,12 +4006,32 @@ error_code cellGemSetYaw(u32 gem_num, vm::ptr z_direction) return CELL_GEM_ERROR_UNINITIALIZED; } - if (!z_direction || !check_gem_num(gem_num)) + if (!check_gem_num(gem_num)) { return CELL_GEM_ERROR_INVALID_PARAMETER; } - // TODO + // The game tells us that the motion controller currently points towards the given point in world coordinates (mm). + // So far we've only seen points on the camera axis (e.g. 0,0,1), which means that the controller points at the camera. + // That's our default orientation, so we simply reset the orientation. + if (z_direction_x != 0.0f || z_direction_y != 0.0f) + { + cellGem.warning("cellGemSetYaw: Unexpected direction (x=%f, y=%f, z=%f). Resetting the orientation to face the camera anyway.", z_direction_x, z_direction_y, z_direction_z); + } + + if (g_cfg.io.move != move_handler::real) + { + return CELL_OK; + } + + std::lock_guard pad_lock(pad::g_pad_mutex); + const auto handler = pad::get_pad_thread(); + const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num)); + + if (pad && pad->m_pad_handler == pad_handler::move && !pad->is_copilot()) + { + pad->move_data.orientation_reset_requested = true; + } return CELL_OK; } diff --git a/rpcs3/Emu/Io/PadHandler.cpp b/rpcs3/Emu/Io/PadHandler.cpp index abd2fe4602..72c99cbf0d 100644 --- a/rpcs3/Emu/Io/PadHandler.cpp +++ b/rpcs3/Emu/Io/PadHandler.cpp @@ -960,6 +960,14 @@ void PadHandlerBase::get_orientation(const pad_ensemble& binding) const return; } + // The game told us that the controller currently points at the camera (see cellGemSetYaw) + if (std::exchange(pad->move_data.orientation_reset_requested, false)) + { + device->reset_orientation(); + pad->move_data.quaternion = ps_move_data::default_quaternion; + return; + } + if (!pad->move_data.orientation_enabled || pad->get_orientation_reset_button_active()) { // This can be called extensively in quick succession, so let's just reset the pointer instead of creating a new object. diff --git a/rpcs3/Emu/Io/ps_move_data.h b/rpcs3/Emu/Io/ps_move_data.h index 2470e47e8c..4ab555dd62 100644 --- a/rpcs3/Emu/Io/ps_move_data.h +++ b/rpcs3/Emu/Io/ps_move_data.h @@ -62,6 +62,8 @@ struct ps_move_data bool calibration_requested = false; bool calibration_succeeded = false; + bool orientation_reset_requested = false; // Reset the orientation to the default (facing the camera). See cellGemSetYaw. + bool magnetometer_enabled = false; bool orientation_enabled = false;