From af8ebc76e242c468eb20daf15b7834a737717559 Mon Sep 17 00:00:00 2001 From: Zangetsu38 Date: Mon, 23 Jul 2018 19:57:40 +0200 Subject: [PATCH] Modules/cellGem: Implement pos, quat and handle_pos in Gemstate for mouse. Modules/cellGem: Fix name for gem_image_state. Modules/cellGem: Implement projectiion(x/y) in gem_image_State for mouse. Modules/cellGem: Add cross, triangle, circle and start with use middle click for mouse. Modules/cellGem: Refactor global code. Modules/cellGem: fix some warning with initializing value. --- rpcs3/Emu/Cell/Modules/cellGem.cpp | 285 +++++++++++++++++------------ rpcs3/Emu/System.h | 1 + rpcs3/Json/tooltips.json | 2 +- rpcs3/main_application.cpp | 10 +- rpcs3/rpcs3qt/gs_frame.cpp | 2 +- 5 files changed, 179 insertions(+), 121 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellGem.cpp b/rpcs3/Emu/Cell/Modules/cellGem.cpp index 72c4ae8855..a97e4f38db 100644 --- a/rpcs3/Emu/Cell/Modules/cellGem.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGem.cpp @@ -7,6 +7,7 @@ #include "Emu/Cell/PPUModule.h" #include "pad_thread.h" #include "Emu/Io/MouseHandler.h" +#include "Emu/RSX/GSRender.h" #include "Utilities/Timer.h" LOG_CHANNEL(cellGem); @@ -80,31 +81,27 @@ struct gem_config struct gem_controller { - u32 status; // connection status (CELL_GEM_STATUS_DISCONNECTED or CELL_GEM_STATUS_READY) - u32 ext_status; // external port connection status - u32 port; // assigned port - bool enabled_magnetometer; // whether the magnetometer is enabled (probably used for additional rotational precision) - bool calibrated_magnetometer; // whether the magnetometer is calibrated - bool enabled_filtering; // whether filtering is enabled - bool enabled_tracking; // whether tracking is enabled - bool enabled_LED; // whether the LED is enabled - u8 rumble; // rumble intensity - gem_color sphere_rgb; // RGB color of the sphere LED - u32 hue; // tracking hue of the motion controller - - gem_controller() : - status(CELL_GEM_STATUS_DISCONNECTED), - enabled_filtering(false), rumble(0), sphere_rgb() {} + u32 status = CELL_GEM_STATUS_DISCONNECTED; // Connection status (CELL_GEM_STATUS_DISCONNECTED or CELL_GEM_STATUS_READY) + u32 ext_status = CELL_GEM_NO_EXTERNAL_PORT_DEVICE; // External port connection status + u32 port = 0; // Assigned port + bool enabled_magnetometer = false; // Whether the magnetometer is enabled (probably used for additional rotational precision) + bool calibrated_magnetometer = false; // Whether the magnetometer is calibrated + bool enabled_filtering = false; // Whether filtering is enabled + bool enabled_tracking = false; // Whether tracking is enabled + bool enabled_LED = false; // Whether the LED is enabled + u8 rumble = 0; // Rumble intensity + gem_color sphere_rgb = {}; // RGB color of the sphere LED + u32 hue = 0; // Tracking hue of the motion controller }; - CellGemAttribute attribute; - CellGemVideoConvertAttribute vc_attribute; - u64 status_flags; - bool enable_pitch_correction; - u32 inertial_counter; + CellGemAttribute attribute = {}; + CellGemVideoConvertAttribute vc_attribute = {}; + u64 status_flags = CELL_GEM_NOT_CALIBRATED; + bool enable_pitch_correction = false; + u32 inertial_counter = 0; std::array controllers; - u32 connected_controllers; + u32 connected_controllers = 0; bool update_started{}; u32 camera_frame{}; u32 memory_ptr{}; @@ -123,33 +120,20 @@ struct gem_config { switch (g_cfg.io.move) { - default: - case move_handler::null: - { - connected_controllers = 0; - - controllers[gem_num].status = CELL_GEM_STATUS_DISCONNECTED; - controllers[gem_num].port = 0; - break; - } - case move_handler::fake: + case move_handler::mouse: { - // fake one connected controller connected_controllers = 1; - - if (gem_num < connected_controllers) - { - controllers[gem_num].status = CELL_GEM_STATUS_READY; - controllers[gem_num].port = 7u - gem_num; - } - else - { - controllers[gem_num].status = CELL_GEM_STATUS_DISCONNECTED; - controllers[gem_num].port = 0; - } break; } + default: break; + } + + // Assign status and port number + if (gem_num < connected_controllers) + { + controllers[gem_num].status = CELL_GEM_STATUS_READY; + controllers[gem_num].port = 7u - gem_num; } } }; @@ -167,6 +151,7 @@ void fmt_class_string::format(std::string& out, u64 arg) { case move_handler::null: return "Null"; case move_handler::fake: return "Fake"; + case move_handler::mouse: return "Mouse"; } return unknown; @@ -306,40 +291,113 @@ static bool ds3_input_to_ext(const u32 port_no, CellGemExtPortData& ext) } /** -* \brief Maps Move controller data (digital buttons, and analog Trigger data) to mouse input. -* Move Button: Mouse1 -* Trigger: Mouse2 -* \param mouse_no Mouse index number to use -* \param digital_buttons Bitmask filled with CELL_GEM_CTRL_* values -* \param analog_t Analog value of Move's Trigger. -* \return true on success, false if mouse mouse_no is invalid -*/ -static bool map_to_mouse_input(const u32 mouse_no, be_t& digital_buttons, be_t& analog_t) + * \brief Maps Move controller data (digital buttons, and analog Trigger data) to mouse input. + * Move Button: Mouse1 + * Trigger: Mouse2 + * \param mouse_no Mouse index number to use + * \param digital_buttons Bitmask filled with CELL_GEM_CTRL_* values + * \param analog_t Analog value of Move's Trigger. + * \return true on success, false if mouse mouse_no is invalid + */ +static bool mouse_input_to_pad(const u32 mouse_no, be_t& digital_buttons, be_t& analog_t) { const auto handler = g_fxo->get(); - if (handler->GetInfo().status[mouse_no] != CELL_MOUSE_STATUS_CONNECTED) + std::scoped_lock lock(handler->mutex); + + if (!handler || mouse_no >= handler->GetMice().size()) { return false; } - MouseDataList& mouse_data_list = handler->GetDataList(mouse_no); + memset(&digital_buttons, 0, sizeof(digital_buttons)); - if (mouse_data_list.size()) + const auto& mouse_data = handler->GetMice().at(0); + + if ((mouse_data.buttons & CELL_MOUSE_BUTTON_1) && (mouse_data.buttons & CELL_MOUSE_BUTTON_2)) + digital_buttons |= CELL_GEM_CTRL_CIRCLE; + if (mouse_data.buttons & CELL_MOUSE_BUTTON_3) + digital_buttons |= CELL_GEM_CTRL_CROSS; + if (mouse_data.buttons & CELL_MOUSE_BUTTON_2) + digital_buttons |= CELL_GEM_CTRL_MOVE; + if ((mouse_data.buttons & CELL_MOUSE_BUTTON_1) && (mouse_data.buttons & CELL_MOUSE_BUTTON_3)) + digital_buttons |= CELL_GEM_CTRL_START; + if (mouse_data.buttons & CELL_MOUSE_BUTTON_1) + digital_buttons |= CELL_GEM_CTRL_T; + if ((mouse_data.buttons & CELL_MOUSE_BUTTON_2) && (mouse_data.buttons & CELL_MOUSE_BUTTON_3)) + digital_buttons |= CELL_GEM_CTRL_TRIANGLE; + + analog_t = mouse_data.buttons & (CELL_MOUSE_BUTTON_1 ? 0xFFFF : 0); + + return true; +} + +static bool mouse_pos_to_gem_image_state(const u32 mouse_no, vm::ptr& gem_image_state) +{ + const auto handler = g_fxo->get(); + + std::scoped_lock lock(handler->mutex); + + if (!gem_image_state || !handler || mouse_no >= handler->GetMice().size()) + { + return false; + } + + const auto& mouse = handler->GetMice().at(0); + + const auto renderer = static_cast(rsx::get_current_renderer()); + const auto width = renderer->get_frame()->client_width(); + const auto hight = renderer->get_frame()->client_height(); + const f32 scaling_width = width / 640.f; + const f32 scaling_hight = hight / 480.f; + + const f32 x = static_cast(mouse.x_pos) / scaling_width; + const f32 y = static_cast(mouse.y_pos) / scaling_hight; + + gem_image_state->u = 133.f + (x / 1.50f); + gem_image_state->v = 160.f + (y / 1.67f); + gem_image_state->projectionx = x - 320.f; + gem_image_state->projectiony = 240.f - y; + + return true; +} + +static bool mouse_pos_to_gem_state(const u32 mouse_no, vm::ptr& gem_state) +{ + const auto handler = g_fxo->get(); + + std::scoped_lock lock(handler->mutex); + + if (!gem_state || !handler || mouse_no >= handler->GetMice().size()) { - const MouseData& mouse_data = mouse_data_list.front(); - - if (mouse_data.buttons & CELL_MOUSE_BUTTON_1) - digital_buttons |= CELL_GEM_CTRL_T; - - if (mouse_data.buttons & CELL_MOUSE_BUTTON_2) - digital_buttons |= CELL_GEM_CTRL_MOVE; - - analog_t = mouse_data.buttons & CELL_MOUSE_BUTTON_1 ? 0xFFFF : 0; - - mouse_data_list.pop_front(); + return false; } + const auto& mouse = handler->GetMice().at(0); + + const auto renderer = static_cast(rsx::get_current_renderer()); + const auto width = renderer->get_frame()->client_width(); + const auto hight = renderer->get_frame()->client_height(); + + const f32 scaling_width = width / 640.f; + const f32 scaling_hight = hight / 480.f; + const f32 x = static_cast(mouse.x_pos) / scaling_width; + const f32 y = static_cast(mouse.y_pos) / scaling_hight; + + gem_state->pos[0] = x; + gem_state->pos[1] = -y; + gem_state->pos[2] = 1500.f; + gem_state->pos[3] = 0.f; + + gem_state->quat[0] = 320.f - x; + gem_state->quat[1] = (mouse.y_pos / scaling_width) - 180.f; + gem_state->quat[2] = 1200.f; + + gem_state->handle_pos[0] = x; + gem_state->handle_pos[1] = y; + gem_state->handle_pos[2] = 1500.f; + gem_state->handle_pos[3] = 0.f; + return true; } @@ -365,9 +423,11 @@ error_code cellGemCalibrate(u32 gem_num) return CELL_GEM_ERROR_INVALID_PARAMETER; } - if (g_cfg.io.move == move_handler::fake) + if (g_cfg.io.move == move_handler::fake || g_cfg.io.move == move_handler::mouse) { gem->controllers[gem_num].calibrated_magnetometer = true; + gem->controllers[gem_num].enabled_tracking = true; + gem->controllers[gem_num].hue = 1; gem->status_flags = CELL_GEM_FLAG_CALIBRATION_OCCURRED | CELL_GEM_FLAG_CALIBRATION_SUCCEEDED; } @@ -580,7 +640,7 @@ error_code cellGemGetCameraState(vm::ptr camera_state) return CELL_GEM_ERROR_INVALID_PARAMETER; } - camera_state->exposure_time = 1.0f / 60.0f; // TODO: use correct framerate + camera_state->exposure_time = 1.0f / 60.0f; // TODO: use correct framerate camera_state->gain = 1.0; return CELL_OK; @@ -629,9 +689,9 @@ error_code cellGemGetHuePixels(vm::cptr camera_frame, u32 hue, vm::ptr return CELL_OK; } -error_code cellGemGetImageState(u32 gem_num, vm::ptr image_state) +error_code cellGemGetImageState(u32 gem_num, vm::ptr gem_image_state) { - cellGem.todo("cellGemGetImageState(gem_num=%d, image_state=&0x%x)", gem_num, image_state); + cellGem.todo("cellGemGetImageState(gem_num=%d, image_state=&0x%x)", gem_num, gem_image_state); const auto gem = g_fxo->get(); @@ -640,40 +700,31 @@ error_code cellGemGetImageState(u32 gem_num, vm::ptr image_st return CELL_GEM_ERROR_UNINITIALIZED; } - if (!check_gem_num(gem_num) || !image_state) + if (!check_gem_num(gem_num) || !gem_image_state) { return CELL_GEM_ERROR_INVALID_PARAMETER; } - if (g_cfg.io.move == move_handler::fake && - g_cfg.io.mouse == mouse_handler::basic) + auto shared_data = g_fxo->get(); + + if (g_cfg.io.move == move_handler::fake) { - auto shared_data = g_fxo->get(); + gem_image_state->u = 0; + gem_image_state->v = 0; + gem_image_state->projectionx = 1; + gem_image_state->projectiony = 1; + } + else if (g_cfg.io.move == move_handler::mouse) + mouse_pos_to_gem_image_state(gem_num, gem_image_state); - const auto handler = fxm::get(); - auto& mouse = handler->GetMice().at(0); - - f32 x_pos = mouse.x_pos; - f32 y_pos = mouse.y_pos; - - static constexpr auto aspect_ratio = 1.2; - - static constexpr auto screen_offset_x = 400.0; - static constexpr auto screen_offset_y = screen_offset_x * aspect_ratio; - - static constexpr auto screen_scale = 3.0; - - image_state->frame_timestamp = shared_data->frame_timestamp.load(); - image_state->timestamp = image_state->frame_timestamp + 10; // arbitrarily define 10 usecs of frame processing - image_state->visible = true; - image_state->u = screen_offset_x / screen_scale + x_pos / screen_scale; - image_state->v = screen_offset_y / screen_scale + y_pos / screen_scale * aspect_ratio; - image_state->r = 10; - image_state->r_valid = true; - image_state->distance = 2 * 1000; // 2 meters away from camera - // TODO - image_state->projectionx = 1; - image_state->projectiony = 1; + if (g_cfg.io.move == move_handler::fake || g_cfg.io.move == move_handler::mouse) + { + gem_image_state->frame_timestamp = shared_data->frame_timestamp.load(); + gem_image_state->timestamp = gem_image_state->frame_timestamp + 10; + gem_image_state->r = 10; + gem_image_state->distance = 2 * 1000; // 2 meters away from camera + gem_image_state->visible = true; + gem_image_state->r_valid = true; } return CELL_OK; @@ -698,19 +749,16 @@ error_code cellGemGetInertialState(u32 gem_num, u32 state_flag, u64 timestamp, v } if (g_cfg.io.move == move_handler::fake) - { ds3_input_to_pad(gem_num, inertial_state->pad.digitalbuttons, inertial_state->pad.analog_T); + else if (g_cfg.io.move == move_handler::mouse) + mouse_input_to_pad(gem_num, inertial_state->pad.digitalbuttons, inertial_state->pad.analog_T); + + if (g_cfg.io.move == move_handler::fake || g_cfg.io.move == move_handler::mouse) + { ds3_input_to_ext(gem_num, inertial_state->ext); - if (g_cfg.io.mouse == mouse_handler::basic) - { - map_to_mouse_input(gem_num, inertial_state->pad.digitalbuttons, inertial_state->pad.analog_T); - } - inertial_state->timestamp = gem->timer.GetElapsedTimeInMicroSec(); - inertial_state->counter = gem->inertial_counter++; - inertial_state->accelerometer[0] = 10; } @@ -778,7 +826,7 @@ error_code cellGemGetRGB(u32 gem_num, vm::ptr r, vm::ptr g, vm::pt return CELL_GEM_ERROR_UNINITIALIZED; } - if (!check_gem_num(gem_num) || !r || !g || !b ) + if (!check_gem_num(gem_num) || !r || !g || !b) { return CELL_GEM_ERROR_INVALID_PARAMETER; } @@ -833,19 +881,21 @@ error_code cellGemGetState(u32 gem_num, u32 flag, u64 time_parameter, vm::ptrpad.digitalbuttons, gem_state->pad.analog_T); - ds3_input_to_ext(gem_num, gem_state->ext); + else if (g_cfg.io.move == move_handler::mouse) + { + mouse_input_to_pad(gem_num, gem_state->pad.digitalbuttons, gem_state->pad.analog_T); + mouse_pos_to_gem_state(gem_num, gem_state); + } - if (g_cfg.io.mouse == mouse_handler::basic) - { - map_to_mouse_input(gem_num, gem_state->pad.digitalbuttons, gem_state->pad.analog_T); - } + if (g_cfg.io.move == move_handler::fake || g_cfg.io.move == move_handler::mouse) + { + ds3_input_to_ext(gem_num, gem_state->ext); gem_state->tracking_flags = CELL_GEM_TRACKING_FLAG_POSITION_TRACKED | CELL_GEM_TRACKING_FLAG_VISIBLE; gem_state->timestamp = gem->timer.GetElapsedTimeInMicroSec(); + gem_state->quat[3] = 1.f; - gem_state->quat[3] = 1.0; return CELL_OK; } @@ -959,13 +1009,12 @@ error_code cellGemInit(vm::cptr attribute) gem->status_flags = 0; gem->attribute = *attribute; - if (g_cfg.io.move == move_handler::fake && - g_cfg.io.mouse == mouse_handler::basic) + if (g_cfg.io.move == move_handler::mouse) { // init mouse handler const auto handler = g_fxo->get(); - handler->Init(std::min(attribute->max_connect.value(), static_cast(CELL_GEM_MAX_NUM))); + handler->Init(std::min(attribute->max_connect, CELL_GEM_MAX_NUM)); } for (int gem_num = 0; gem_num < CELL_GEM_MAX_NUM; gem_num++) @@ -997,7 +1046,7 @@ error_code cellGemInvalidateCalibration(s32 gem_num) return CELL_GEM_ERROR_INVALID_PARAMETER; } - if (g_cfg.io.move == move_handler::fake) + if (g_cfg.io.move == move_handler::fake || g_cfg.io.move == move_handler::mouse) { gem->controllers[gem_num].calibrated_magnetometer = false; // TODO: gem->status_flags diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index 2482d55b6d..a3c17cbd4f 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -126,6 +126,7 @@ enum class move_handler { null, fake, + mouse, }; enum class microphone_handler diff --git a/rpcs3/Json/tooltips.json b/rpcs3/Json/tooltips.json index 7fd243f90e..5819d2fbb6 100644 --- a/rpcs3/Json/tooltips.json +++ b/rpcs3/Json/tooltips.json @@ -153,7 +153,7 @@ "mouseHandlerBox": "Some games support native mouse input.\nBasic will work in these cases.", "cameraBox": "Camera support is not implemented, leave this on null.", "cameraTypeBox": "Camera support is not implemented, leave this on unknown.", - "moveBox": "PlayStation Move support.\nFake: Experimental! This maps Move controls to DS4 controller mappings." + "moveBox": "PlayStation Move support.\nFake: Experimental! This maps Move controls to DS3 controller mappings.\nMouse: Emulate PSMove with Mouse handler." }, "network": { "netStatusBox": "Leave as disconnected unless you're debugging.\nRPCS3 has no online support." diff --git a/rpcs3/main_application.cpp b/rpcs3/main_application.cpp index ce03e5a839..f3ea23e904 100644 --- a/rpcs3/main_application.cpp +++ b/rpcs3/main_application.cpp @@ -100,7 +100,15 @@ EmuCallbacks main_application::CreateCallbacks() { case mouse_handler::null: { - g_fxo->init(); + if (g_cfg.io.move == move_handler::mouse) + { + basic_mouse_handler* ret = g_fxo->init(); + ret->moveToThread(get_thread()); + ret->SetTargetWindow(m_game_window); + } + else + g_fxo->init(); + break; } case mouse_handler::basic: diff --git a/rpcs3/rpcs3qt/gs_frame.cpp b/rpcs3/rpcs3qt/gs_frame.cpp index fdaee9b2c9..c7ad86213a 100644 --- a/rpcs3/rpcs3qt/gs_frame.cpp +++ b/rpcs3/rpcs3qt/gs_frame.cpp @@ -419,7 +419,7 @@ void gs_frame::take_screenshot(const std::vector sshot_data, const u32 sshot void gs_frame::mouseDoubleClickEvent(QMouseEvent* ev) { - if (m_disable_mouse) return; + if (m_disable_mouse || g_cfg.io.move == move_handler::mouse) return; if (ev->button() == Qt::LeftButton) {