cellGem: fix mouse positions

This commit is contained in:
Megamouse 2021-07-30 15:55:50 +02:00
parent ccb7531289
commit dd7f24b20e
5 changed files with 98 additions and 56 deletions

View file

@ -448,6 +448,10 @@ error_code cellCameraOpenEx(s32 dev_num, vm::ptr<CellCameraInfoEx> info)
g_camera.is_open = true; g_camera.is_open = true;
g_camera.info = *info; g_camera.info = *info;
auto& shared_data = g_fxo->get<gem_camera_shared>();
shared_data.width = info->width > 0 ? +info->width : 640;
shared_data.height = info->height > 0 ? +info->height : 480;
return CELL_OK; return CELL_OK;
} }

View file

@ -443,5 +443,7 @@ using camera_thread = named_thread<camera_context>;
/// Shared data between cellGem and cellCamera /// Shared data between cellGem and cellCamera
struct gem_camera_shared struct gem_camera_shared
{ {
atomic_t<s64> frame_timestamp; // latest read timestamp from cellCamera (cellCameraRead(Ex)) atomic_t<s64> frame_timestamp{}; // latest read timestamp from cellCamera (cellCameraRead(Ex))
atomic_t<s32> width{640};
atomic_t<s32> height{480};
}; };

View file

@ -3,9 +3,10 @@
#include "cellCamera.h" #include "cellCamera.h"
#include "Emu/Cell/PPUModule.h" #include "Emu/Cell/PPUModule.h"
#include "Emu/Cell/timers.hpp"
#include "Emu/Io/MouseHandler.h" #include "Emu/Io/MouseHandler.h"
#include "Emu/RSX/GSRender.h" #include "Emu/system_config.h"
#include "Utilities/Timer.h" #include "Emu/IdManager.h"
#include "Input/pad_thread.h" #include "Input/pad_thread.h"
LOG_CHANNEL(cellGem); LOG_CHANNEL(cellGem);
@ -92,6 +93,10 @@ struct gem_config
u8 rumble = 0; // Rumble intensity u8 rumble = 0; // Rumble intensity
gem_color sphere_rgb = {}; // RGB color of the sphere LED gem_color sphere_rgb = {}; // RGB color of the sphere LED
u32 hue = 0; // Tracking hue of the motion controller u32 hue = 0; // Tracking hue of the motion controller
u32 distance{1500}; // Distance from the camera in mm
u32 radius{10}; // Radius of the sphere in camera pixels
static constexpr s32 diameter_mm = 45; // Physical diameter of the sphere in millimeter
}; };
CellGemAttribute attribute = {}; CellGemAttribute attribute = {};
@ -164,9 +169,7 @@ static bool ds3_input_to_pad(const u32 port_no, be_t<u16>& digital_buttons, be_t
std::scoped_lock lock(pad::g_pad_mutex); std::scoped_lock lock(pad::g_pad_mutex);
const auto handler = pad::get_current_handler(); const auto handler = pad::get_current_handler();
auto& pad = handler->GetPads()[port_no];
auto& pads = handler->GetPads();
auto pad = pads[port_no];
if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
return false; return false;
@ -250,9 +253,7 @@ static bool ds3_input_to_ext(const u32 port_no, const gem_config::gem_controller
std::scoped_lock lock(pad::g_pad_mutex); std::scoped_lock lock(pad::g_pad_mutex);
const auto handler = pad::get_current_handler(); const auto handler = pad::get_current_handler();
auto& pad = handler->GetPads()[port_no];
auto& pads = handler->GetPads();
auto pad = pads[port_no];
if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
return false; return false;
@ -313,17 +314,17 @@ static bool mouse_input_to_pad(const u32 mouse_no, be_t<u16>& digital_buttons, b
digital_buttons |= CELL_GEM_CTRL_CROSS; digital_buttons |= CELL_GEM_CTRL_CROSS;
if (is_pressed(CELL_MOUSE_BUTTON_4)) if (is_pressed(CELL_MOUSE_BUTTON_4))
digital_buttons |= CELL_GEM_CTRL_SELECT;
if (is_pressed(CELL_MOUSE_BUTTON_5))
digital_buttons |= CELL_GEM_CTRL_START;
if (is_pressed(CELL_MOUSE_BUTTON_6) || (is_pressed(CELL_MOUSE_BUTTON_1) && is_pressed(CELL_MOUSE_BUTTON_2)))
digital_buttons |= CELL_GEM_CTRL_CIRCLE; digital_buttons |= CELL_GEM_CTRL_CIRCLE;
if (is_pressed(CELL_MOUSE_BUTTON_7) || (is_pressed(CELL_MOUSE_BUTTON_1) && is_pressed(CELL_MOUSE_BUTTON_3))) if (is_pressed(CELL_MOUSE_BUTTON_5))
digital_buttons |= CELL_GEM_CTRL_SQUARE; digital_buttons |= CELL_GEM_CTRL_SQUARE;
if (is_pressed(CELL_MOUSE_BUTTON_6) || (is_pressed(CELL_MOUSE_BUTTON_1) && is_pressed(CELL_MOUSE_BUTTON_2)))
digital_buttons |= CELL_GEM_CTRL_SELECT;
if (is_pressed(CELL_MOUSE_BUTTON_7) || (is_pressed(CELL_MOUSE_BUTTON_1) && is_pressed(CELL_MOUSE_BUTTON_3)))
digital_buttons |= CELL_GEM_CTRL_START;
if (is_pressed(CELL_MOUSE_BUTTON_8) || (is_pressed(CELL_MOUSE_BUTTON_2) && is_pressed(CELL_MOUSE_BUTTON_3))) if (is_pressed(CELL_MOUSE_BUTTON_8) || (is_pressed(CELL_MOUSE_BUTTON_2) && is_pressed(CELL_MOUSE_BUTTON_3)))
digital_buttons |= CELL_GEM_CTRL_TRIANGLE; digital_buttons |= CELL_GEM_CTRL_TRIANGLE;
@ -332,7 +333,7 @@ static bool mouse_input_to_pad(const u32 mouse_no, be_t<u16>& digital_buttons, b
return true; return true;
} }
static bool mouse_pos_to_gem_image_state(const u32 mouse_no, vm::ptr<CellGemImageState>& gem_image_state) static bool mouse_pos_to_gem_image_state(const u32 mouse_no, const gem_config::gem_controller& controller, vm::ptr<CellGemImageState>& gem_image_state)
{ {
auto& handler = g_fxo->get<MouseHandlerBase>(); auto& handler = g_fxo->get<MouseHandlerBase>();
@ -344,25 +345,40 @@ static bool mouse_pos_to_gem_image_state(const u32 mouse_no, vm::ptr<CellGemImag
} }
const auto& mouse = handler.GetMice().at(0); const auto& mouse = handler.GetMice().at(0);
const auto& shared_data = g_fxo->get<gem_camera_shared>();
const auto renderer = static_cast<GSRender*>(rsx::get_current_renderer()); s32 mouse_width = mouse.x_max;
const auto width = renderer->get_frame()->client_width(); if (mouse_width <= 0) mouse_width = shared_data.width;
const auto height = renderer->get_frame()->client_height(); s32 mouse_height = mouse.y_max;
const f32 scaling_width = width / 640.f; if (mouse_height <= 0) mouse_height = shared_data.height;
const f32 scaling_height = height / 480.f; const f32 scaling_width = mouse_width / static_cast<f32>(shared_data.width);
const f32 scaling_height = mouse_height / static_cast<f32>(shared_data.height);
const f32 mmPerPixel = controller.diameter_mm / static_cast<f32>(controller.radius * 2);
const f32 x = static_cast<f32>(mouse.x_pos) / scaling_width; // Image coordinates in pixels
const f32 y = static_cast<f32>(mouse.y_pos) / scaling_height; const f32 image_x = static_cast<f32>(mouse.x_pos) / scaling_width;
const f32 image_y = static_cast<f32>(mouse.y_pos) / scaling_height;
gem_image_state->u = 133.f + (x / 1.50f); // Centered image coordinates in pixels
gem_image_state->v = 160.f + (y / 1.67f); const f32 centered_x = image_x - (shared_data.width / 2.f);
gem_image_state->projectionx = x - 320.f; const f32 centered_y = (shared_data.height / 2.f) - image_y; // Image coordinates increase downwards, so we have to invert this
gem_image_state->projectiony = 240.f - y;
// Camera coordinates in mm (centered, so it's the same as world coordinates)
const f32 camera_x = centered_x * mmPerPixel;
const f32 camera_y = centered_y * mmPerPixel;
// Image coordinates in pixels
gem_image_state->u = image_x;
gem_image_state->v = image_y;
// Projected camera coordinates in mm
gem_image_state->projectionx = camera_x / controller.distance;
gem_image_state->projectiony = camera_y / controller.distance;
return true; return true;
} }
static bool mouse_pos_to_gem_state(const u32 mouse_no, vm::ptr<CellGemState>& gem_state) static bool mouse_pos_to_gem_state(const u32 mouse_no, const gem_config::gem_controller& controller, vm::ptr<CellGemState>& gem_state)
{ {
auto& handler = g_fxo->get<MouseHandlerBase>(); auto& handler = g_fxo->get<MouseHandlerBase>();
@ -374,28 +390,42 @@ static bool mouse_pos_to_gem_state(const u32 mouse_no, vm::ptr<CellGemState>& ge
} }
const auto& mouse = handler.GetMice().at(0); const auto& mouse = handler.GetMice().at(0);
const auto& shared_data = g_fxo->get<gem_camera_shared>();
const auto renderer = static_cast<GSRender*>(rsx::get_current_renderer()); s32 mouse_width = mouse.x_max;
const auto width = renderer->get_frame()->client_width(); if (mouse_width <= 0) mouse_width = shared_data.width;
const auto height = renderer->get_frame()->client_height(); s32 mouse_height = mouse.y_max;
if (mouse_height <= 0) mouse_height = shared_data.height;
const f32 scaling_width = mouse_width / static_cast<f32>(shared_data.width);
const f32 scaling_height = mouse_height / static_cast<f32>(shared_data.height);
const f32 mmPerPixel = controller.diameter_mm / static_cast<f32>(controller.radius * 2);
const f32 scaling_width = width / 640.f; // Image coordinates in pixels
const f32 scaling_height = height / 480.f; const f32 image_x = static_cast<f32>(mouse.x_pos) / scaling_width;
const f32 x = static_cast<f32>(mouse.x_pos) / scaling_width; const f32 image_y = static_cast<f32>(mouse.y_pos) / scaling_height;
const f32 y = static_cast<f32>(mouse.y_pos) / scaling_height;
gem_state->pos[0] = x; // Centered image coordinates in pixels
gem_state->pos[1] = -y; const f32 centered_x = image_x - (shared_data.width / 2.f);
gem_state->pos[2] = 1500.f; const f32 centered_y = (shared_data.height / 2.f) - image_y; // Image coordinates increase downwards, so we have to invert this
// Camera coordinates in mm (centered, so it's the same as world coordinates)
const f32 camera_x = centered_x * mmPerPixel;
const f32 camera_y = centered_y * mmPerPixel;
// World coordinates in mm
gem_state->pos[0] = camera_x;
gem_state->pos[1] = camera_y;
gem_state->pos[2] = static_cast<f32>(controller.distance);
gem_state->pos[3] = 0.f; gem_state->pos[3] = 0.f;
gem_state->quat[0] = 320.f - x; gem_state->quat[0] = 320.f - image_x;
gem_state->quat[1] = (mouse.y_pos / scaling_width) - 180.f; gem_state->quat[1] = (mouse.y_pos / scaling_width) - 180.f;
gem_state->quat[2] = 1200.f; gem_state->quat[2] = 1200.f;
gem_state->handle_pos[0] = x; // TODO: calculate handle position based on our world coordinate and the angles
gem_state->handle_pos[1] = y; gem_state->handle_pos[0] = camera_x;
gem_state->handle_pos[2] = 1500.f; gem_state->handle_pos[1] = camera_y;
gem_state->handle_pos[2] = static_cast<f32>(controller.distance + 10);
gem_state->handle_pos[3] = 0.f; gem_state->handle_pos[3] = 0.f;
return true; return true;
@ -749,14 +779,13 @@ error_code cellGemGetImageState(u32 gem_num, vm::ptr<CellGemImageState> gem_imag
return CELL_GEM_ERROR_INVALID_PARAMETER; return CELL_GEM_ERROR_INVALID_PARAMETER;
} }
auto& shared_data = g_fxo->get<gem_camera_shared>();
if (g_cfg.io.move == move_handler::fake || g_cfg.io.move == move_handler::mouse) if (g_cfg.io.move == move_handler::fake || g_cfg.io.move == move_handler::mouse)
{ {
auto& shared_data = g_fxo->get<gem_camera_shared>();
gem_image_state->frame_timestamp = shared_data.frame_timestamp.load(); gem_image_state->frame_timestamp = shared_data.frame_timestamp.load();
gem_image_state->timestamp = gem_image_state->frame_timestamp + 10; gem_image_state->timestamp = gem_image_state->frame_timestamp + 10;
gem_image_state->r = 10; gem_image_state->r = gem.controllers[gem_num].radius; // Radius in camera pixels
gem_image_state->distance = 2 * 1000; // 2 meters away from camera gem_image_state->distance = gem.controllers[gem_num].distance; // 1.5 meters away from camera
gem_image_state->visible = gem.is_controller_ready(gem_num); gem_image_state->visible = gem.is_controller_ready(gem_num);
gem_image_state->r_valid = true; gem_image_state->r_valid = true;
@ -769,7 +798,7 @@ error_code cellGemGetImageState(u32 gem_num, vm::ptr<CellGemImageState> gem_imag
} }
else if (g_cfg.io.move == move_handler::mouse) else if (g_cfg.io.move == move_handler::mouse)
{ {
mouse_pos_to_gem_image_state(gem_num, gem_image_state); mouse_pos_to_gem_image_state(gem_num, gem.controllers[gem_num], gem_image_state);
} }
} }
@ -800,7 +829,7 @@ error_code cellGemGetInertialState(u32 gem_num, u32 state_flag, u64 timestamp, v
inertial_state->timestamp = (get_guest_system_time() - gem.start_timestamp); inertial_state->timestamp = (get_guest_system_time() - gem.start_timestamp);
inertial_state->counter = gem.inertial_counter++; inertial_state->counter = gem.inertial_counter++;
inertial_state->accelerometer[0] = 10; inertial_state->accelerometer[0] = 10; // Current gravity in m/s²
if (g_cfg.io.move == move_handler::fake) if (g_cfg.io.move == move_handler::fake)
{ {
@ -958,6 +987,7 @@ error_code cellGemGetState(u32 gem_num, u32 flag, u64 time_parameter, vm::ptr<Ce
if (gem.controllers[gem_num].enabled_tracking) if (gem.controllers[gem_num].enabled_tracking)
tracking_flags |= CELL_GEM_TRACKING_FLAG_POSITION_TRACKED; tracking_flags |= CELL_GEM_TRACKING_FLAG_POSITION_TRACKED;
*gem_state = {};
gem_state->tracking_flags = tracking_flags; gem_state->tracking_flags = tracking_flags;
gem_state->timestamp = (get_guest_system_time() - gem.start_timestamp); gem_state->timestamp = (get_guest_system_time() - gem.start_timestamp);
gem_state->camera_pitch_angle = 0.f; gem_state->camera_pitch_angle = 0.f;
@ -970,7 +1000,7 @@ error_code cellGemGetState(u32 gem_num, u32 flag, u64 time_parameter, vm::ptr<Ce
else if (g_cfg.io.move == move_handler::mouse) 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_input_to_pad(gem_num, gem_state->pad.digitalbuttons, gem_state->pad.analog_T);
mouse_pos_to_gem_state(gem_num, gem_state); mouse_pos_to_gem_state(gem_num, gem.controllers[gem_num], gem_state);
} }
} }

View file

@ -115,6 +115,8 @@ struct Mouse
{ {
s32 x_pos; s32 x_pos;
s32 y_pos; s32 y_pos;
s32 x_max;
s32 y_max;
u8 buttons; // actual mouse button positions u8 buttons; // actual mouse button positions
MouseTabletDataList m_tablet_datalist; MouseTabletDataList m_tablet_datalist;
@ -124,6 +126,8 @@ struct Mouse
Mouse() Mouse()
: x_pos(0) : x_pos(0)
, y_pos(0) , y_pos(0)
, x_max(0)
, y_max(0)
, buttons(0) , buttons(0)
{ {
} }
@ -213,7 +217,7 @@ public:
} }
} }
void Move(const s32 x_pos_new, const s32 y_pos_new, const bool is_qt_fullscreen = false, s32 x_delta = 0, s32 y_delta = 0) void Move(s32 x_pos_new, s32 y_pos_new, s32 x_max, s32 y_max, const bool is_qt_fullscreen = false, s32 x_delta = 0, s32 y_delta = 0)
{ {
std::lock_guard lock(mutex); std::lock_guard lock(mutex);
@ -244,6 +248,8 @@ public:
new_data.x_axis = static_cast<s8>(std::clamp(x_delta, -127, 128)); new_data.x_axis = static_cast<s8>(std::clamp(x_delta, -127, 128));
new_data.y_axis = static_cast<s8>(std::clamp(y_delta, -127, 128)); new_data.y_axis = static_cast<s8>(std::clamp(y_delta, -127, 128));
m_mice[p].x_max = x_max;
m_mice[p].y_max = y_max;
m_mice[p].x_pos = x_pos_new; m_mice[p].x_pos = x_pos_new;
m_mice[p].y_pos = y_pos_new; m_mice[p].y_pos = y_pos_new;

View file

@ -121,12 +121,12 @@ bool basic_mouse_handler::get_mouse_lock_state() const
void basic_mouse_handler::MouseMove(QMouseEvent* event) void basic_mouse_handler::MouseMove(QMouseEvent* event)
{ {
if (is_time_for_update()) if (is_time_for_update())
{
if (m_target && m_target->isActive() && get_mouse_lock_state())
{ {
// get the screen dimensions // get the screen dimensions
const QSize screen = m_target->size(); const QSize screen = m_target->size();
if (m_target && m_target->isActive() && get_mouse_lock_state())
{
// get the center of the screen in global coordinates // get the center of the screen in global coordinates
QPoint p_center = m_target->geometry().topLeft() + QPoint(screen.width() / 2, screen.height() / 2); QPoint p_center = m_target->geometry().topLeft() + QPoint(screen.width() / 2, screen.height() / 2);
@ -147,11 +147,11 @@ void basic_mouse_handler::MouseMove(QMouseEvent* event)
p_real.setY(std::clamp(p_real.y() + p_delta.y(), 0, screen.height())); p_real.setY(std::clamp(p_real.y() + p_delta.y(), 0, screen.height()));
// pass the 'real' position and the current delta to the screen center // pass the 'real' position and the current delta to the screen center
MouseHandlerBase::Move(p_real.x(), p_real.y(), true, p_delta.x(), p_delta.y()); MouseHandlerBase::Move(p_real.x(), p_real.y(), screen.width(), screen.height(), true, p_delta.x(), p_delta.y());
} }
else else
{ {
MouseHandlerBase::Move(event->x(), event->y()); MouseHandlerBase::Move(event->x(), event->y(), screen.width(), screen.height());
} }
} }
} }